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

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

 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”说,在网上搜索我想出了singleton_class = class << self; self end singleton_class = class << self; self end语句和我使用它(而不是class << self ... end块)以范围 my_method_name变量,使动态生成别名。

我想准确理解为什么以及如何在上面的代码中使用singleton_class ,以及是否有更好的方法(可能是一个更易于维护和高性能的方法)来实现相同的(别名,定义单例方法等),但是“正确的方式”因为我认为不是这样。

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

在Ruby中,所有对象都有一个单例类(也称为元类)。 对象首先从它们的单例类中不可见地inheritance,然后从它们的显式类inheritance。 Ruby类本身也有自己的单例类,因为类也是对象。 class << idiom只是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 

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

 Person.singleton_class person = Person.new person.singleton_class 

由于类直接从其单例类inheritance,因此我们希望在元编程时动态添加类方法。 Ruby提供了一些方法来打开对象的范围,同时保持对周围范围的访问: class_evalinstance_eval 。 这些行为的方式存在细微差别(Yehuda的post解释了这一点),但您可以使用任何一个来输入单例类的范围,将单例类的方法解析为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