1

我正在使用 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

“新手”说,通过在 Web 上的搜索,我想出了该singleton_class = class << self; self end语句,并使用它(而不是class << self ... end块)来限定变量的范围my_method_name从而动态生成别名。

想确切了解上述代码中的工作原理和singleton_class方式,以及是否有更好的方法(也许是更易于维护和性能更好的方法)来实现相同的方法(别名、定义单例方法等),但是“正确的方式”,因为我认为并非如此。

4

1 回答 1

7

我推荐 Yehuda Katz关于 Ruby 自我元编程的帖子。以下是我针对您的问题的简要总结:

在 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

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

Person.singleton_class 

person = Person.new
person.singleton_class

由于类直接继承自其单例类,因此我们希望在元编程时动态添加类方法。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
于 2012-10-17T22:58:29.443 回答