Understanding the singleton class when aliasing a instance method

帅比萌擦擦* 提交于 2020-01-16 05:12:29

问题


I am using Ruby 1.9.2 and the Ruby on Rails v3.2.2 gem. I am trying to learn Metaprogramming "the right way" and at this time I am aliasing an instance method in the included do ... end block provided by the RoR ActiveSupport::Concern module:

module MyModule
  extend ActiveSupport::Concern

  included do
    # Builds the instance method name.
    my_method_name = build_method_name.to_sym # => :my_method

    # Defines the :my_method instance method in the including class of MyModule.
    define_singleton_method(my_method_name) do |*args|
      # ...
    end

    # Aliases the :my_method instance method in the including class of MyModule.
    singleton_class = class << self; self end
    singleton_class.send(:alias_method, :my_new_method, my_method_name)        
  end
end

"Newbiely" speaking, with a search on the Web I came up with the singleton_class = class << self; self end statement and I used that (instead of the class << self ... end block) in order to scope the my_method_name variable, making the aliasing generated dynamically.

I would like to understand exactly why and how the singleton_class works in the above code and if there is a better way (maybe, a more maintainable and performant one) to implement the same (aliasing, defining the singleton method and so on), but "the right way" since I think it isn't so.


回答1:


I recommend Yehuda Katz's post on metaprogamming on Ruby's self. Here's my humble summary in response to your question:

In Ruby, all objects have a singleton class (also known as metaclass). Objects inherit first from their singleton class invisibly, then from their explicit class. Ruby classes themselves have their own singleton classes since classes are objects as well. The class << idiom is simply Ruby's syntax for accessing the scope of an object's singleton class.

 class Person
   class << self
     # self in this scope is Person's singleton class
   end
 end

 person = Person.new
 person_singleton_class = class << person; self; end

Your version of Rails actually provides singleton_class as a shortcut. Since singleton_class is an available method, you don't need to assign it to a variable in the expression singleton_class = class << self; self end:

Person.singleton_class 

person = Person.new
person.singleton_class

Since a class inherits directly from its singleton class, this is where we want to add class methods dynamically when metaprogramming. Ruby provides a few ways to open up the scope of an object while maintaining access to the surrounding scope: class_eval and instance_eval. There are subtle differences in the way these behave (Yehuda's post explains this), but you may use either to enter the scope of your singleton class, resolve methods on the singleton class as self and still have access to my_method_name from the surrounding scope.

All that said, you could make a few small changes to your module:

module MyModule
  extend ActiveSupport::Concern

  included do
    # Builds the instance method name.
    my_method_name = build_method_name.to_sym # => :my_method

    # Defines the :my_method instance method in the including class of MyModule.
    define_singleton_method(my_method_name) do |*args|
      # ...
    end

    singleton_class.class_eval do
      # method resolution in scope of singleton class
      alias_method :my_new_method, my_method_name
    end

  end

end


来源:https://stackoverflow.com/questions/12937209/understanding-the-singleton-class-when-aliasing-a-instance-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!