class << self idiom in Ruby

class << self在Ruby中做什么?


First, the class << foo syntax opens up foo 's singleton class (eigenclass). This allows you to specialise the behaviour of methods called on that specific object.

a = 'foo'
class << a
  def inspect
    '"bar"'
  end
end
a.inspect   # => "bar"

a = 'foo'   # new object, new singleton class
a.inspect   # => "foo"

Now, to answer the question: class << self opens up self 's singleton class, so that methods can be redefined for the current self object (which inside a class or module body is the class or module itself). Usually, this is used to define class/module ("static") methods:

class String
  class << self
    def value_of obj
      obj.to_s
    end
  end
end

String.value_of 42   # => "42"

This can also be written as a shorthand:

class String
  def self.value_of obj
    obj.to_s
  end
end

Or even shorter:

def String.value_of obj
  obj.to_s
end

When inside a function definition, self refers to the object the function is being called with. In this case, class << self opens the singleton class for that object; one use of that is to implement a poor man's state machine:

class StateMachineExample
  def process obj
    process_hook obj
  end

private
  def process_state_1 obj
    # ...
    class << self
      alias process_hook process_state_2
    end
  end

  def process_state_2 obj
    # ...
    class << self
      alias process_hook process_state_1
    end
  end

  # Set up initial state
  alias process_hook process_state_1
end

So, in the example above, each instance of StateMachineExample has process_hook aliased to process_state_1 , but note how in the latter, it can redefine process_hook (for self only, not affecting other StateMachineExample instances) to process_state_2 . So, each time a caller calls the process method (which calls the redefinable process_hook ), the behaviour changes depending on what state it's in.


I found a super simple explanation about class << self , Eigenclass and different type of methods in this blog.

In Ruby, there are three types of methods that can be applied to a class:

  • Instance methods
  • Singleton methods
  • Class methods
  • Instance methods and class methods are almost similar to their homonymous in other programming languages.

    class Foo  
      def an_instance_method  
        puts "I am an instance method"  
      end  
      def self.a_class_method  
        puts "I am a class method"  
      end  
    end
    
    foo = Foo.new
    
    def foo.a_singleton_method
      puts "I am a singletone method"
    end
    

    Another way of accessing an Eigenclass (which includes singleton methods) is with the following syntax ( class << ):

    foo = Foo.new
    
    class << foo
      def a_singleton_method
        puts "I am a singleton method"
      end
    end
    

    now you can define a singleton method for self which is the class Foo itself in this context:

    class Foo
      class << self
        def a_singleton_and_class_method
          puts "I am a singleton method for self and a class method for Foo"
        end
      end
    end
    

    What class << thing does:

    class Hi
      self #=> Hi
      class << self #same as 'class << Hi'
        self #=> #<Class:Hi>
        self == Hi.singleton_class #=> true
      end
    end
    

    [it makes self == thing.singleton_class in the context of its block] .


    What is thing.singleton_class?

    hi = String.new
    def hi.a
    end
    
    hi.class.instance_methods.include? :a #=> false
    hi.singleton_class.instance_methods.include? :a #=> true
    

    hi object inherits its #methods from its #singleton_class.instance_methods and then from its #class.instance_methods .
    Here we gave hi 's singleton class instance method :a . It could have been done with class << hi instead.
    hi 's #singleton_class has all instance methods hi 's #class has, and possibly some more ( :a here).

    [instance methods of thing's #class and #singleton_class can be applied directly to thing. when ruby sees thing.a, it first looks for :a method definition in thing.singleton_class.instance_methods and then in thing.class.instance_methods]


    By the way - they call object's singleton class == metaclass == eigenclass .

    链接地址: http://www.djcxy.com/p/4360.html

    上一篇: 如何在Ruby中写入文件?

    下一篇: Ruby中的自我成语