在别名实例方法时理解单例类

Bac*_*cko 1 ruby methods metaprogramming ruby-on-rails definition

我正在使用Ruby 1.9.2和Ruby on Rails v3.2.2 gem.我正在尝试以"正确的方式"学习元编程,此时我在RoR 模块提供的块中对实例方法进行别名:included do ... endActiveSupport::Concern

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
Run Code Online (Sandbox Code Playgroud)

"Newbiely"说,通过在Web上搜索,我想出了singleton_class = class << self; self end语句,并使用它(而不是class << self ... end块)来调整变量的范围my_method_name,使动态生成别名.

我想明白究竟为什么如何singleton_class在上面的代码和作品是否有更好的方法(也许,一个更容易维护和高性能的一个)实现相同的(别名,定义单身方法等),而是"正确的方式"因为我认为不是这样.

ros*_*sta 6

我推荐Yehuda Katz 关于Ruby自我的metaprogamming帖子.以下是我对您的问题的回复:

在Ruby中,所有对象都有一个单例类(也称为元类).对象首先从它们的单例类中隐藏,然后从它们的显式类继承.Ruby类本身也有自己的单例类,因为类也是对象.这个class <<成语只是Ruby用于访问对象单例类范围的语法.

 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
Run Code Online (Sandbox Code Playgroud)

您的Rails版本实际上提供singleton_class了一个快捷方式.由于singleton_class是可用方法,因此您无需将其分配给表达式中的变量singleton_class = class << self; self end:

Person.singleton_class 

person = Person.new
person.singleton_class
Run Code Online (Sandbox Code Playgroud)

由于类直接从其singleton类继承,因此我们希望在元编程时动态添加类方法.Ruby提供了一些方法来打开对象的范围,同时保持对周围范围的访问:class_evalinstance_eval.这些行为的方式存在细微差别(Yehuda的帖子解释了这一点),但是你可以使用任何一个来输入你的单例类的范围,解决单例类的方法,self并且仍然可以my_method_name从周围的范围访问.

总而言之,您可以对模块进行一些小改动:

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
Run Code Online (Sandbox Code Playgroud)