Calling a method of a Ruby Singleton without the reference of 'instance'

前端 未结 5 2010
悲&欢浪女
悲&欢浪女 2021-01-21 03:37

I would like to call a method of a Singleton Object without the reference to its instance

SingletonKlass.my_method

instead of

S         


        
相关标签:
5条回答
  • 2021-01-21 03:50

    The problem with your method_missing solution is that it will only redirect calls to instance if there does not exist a method of that name on SingletonKlass, which will cause problems if people want to access, for example, instance.__id__ through this interface you provide. There is not much of a problem with accessing SingletonKlass.instance the normal way, but if you really want to make a shortcut, the safest would be a constant:

    KlassInstance = SingletonKlass.instance
    

    If you want to define the constant dynamically, use Module#const_set:

    const_set :KlassInstance, SingletonKlass.instance
    

    You can extend upon this, too. For example, you can create a method that will create constants like this for you:

    def singleton_constant(singleton_class)
      const_set singleton_class.name, singleton_class.instance
    end
    

    Of course, because Module#const_set is a method of a module, this specific technique can only be performed in the context of a module or class. Another possibility is by a mixin module with an overloaded hook method:

    module SingletonInstance
      def included(base_class)
        const_set base_class.name, base_class.instance
        super
      end
    end
    
    0 讨论(0)
  • 2021-01-21 03:53

    Using forwardable and def_delegators:

    require 'singleton'    
    require 'forwardable'
    
    class SingletonKlass
      include Singleton
      class << self
        extend Forwardable
        def_delegators :instance, :my_method
      end
    
      def my_method
         puts "hi there!!"
      end
    end
    
    SingletonKlass.my_method
    

    Edit: If you want to include all the methods you've defined yourself, you could do

    require 'singleton'    
    require 'forwardable'
    
    class SingletonKlass
      include Singleton
    
      def my_method
         puts "hi there!!"
      end
    
      class << self
        extend Forwardable
        def_delegators :instance, *SingletonKlass.instance_methods(false)
      end
    end
    
    SingletonKlass.my_method
    
    0 讨论(0)
  • 2021-01-21 04:05

    Here is an alternative that does not really fall under the scope of my first answer. You can create a mixin module that undefines all the methods of the base class and then uses the method_missing technique:

    module SingletonRedirect
      def included(base_class)
        instance = base_class.instance
        base_class.class_eval do
          methods.each &undef_method
    
          define_method :method_missing do |name, *arguments|
            instance.public_send name, *arguments
          end
        end
      end
    end
    

    To implement the idea, instance is a local variable that is passed via closure to the blocks in the calls to Class#class_eval and Module#define_method. Then, we do not need to refer to it by base_class.instance, so we can clear out all the methods, including that one (a technique known as a blank slate). Then, we define a method redirection system that takes advantage of the flat scope to refer to instance as a variable and call only methods that are publicly available via Object#public_send.

    0 讨论(0)
  • 2021-01-21 04:08

    Instead of SingletonKlass, I'll use the name UrlHelper as a more concrete example.

    require 'singleton'    
    
    class UrlHelperSingleton
      include Singleton
    
      def my_method
         ...
      end
    end
    
    UrlHelper = UrlHelperSingleton.instance
    
    # then elsewhere
    UrlHelper.my_method
    
    0 讨论(0)
  • 2021-01-21 04:09

    Why don't you use a "static" class? e.g.:

    class StaticKlass
    
      class << self
        def method1; end
        def method2; end
        ...
        def methodN; end
      end
    
    end
    
    StaticKlass.method1
    
    0 讨论(0)
提交回复
热议问题