【问题标题】:Understanding the singleton class when aliasing a instance method为实例方法起别名时理解单例类
【发布时间】:2012-10-17 14:56:31
【问题描述】:

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

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

“新手”说,通过网络搜索,我想出了singleton_class = class &lt;&lt; self; self end 语句,我使用它(而不是class &lt;&lt; self ... end 块)为了范围@987654327 @变量,使别名动态生成。

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

【问题讨论】:

    标签: ruby-on-rails ruby methods metaprogramming definition


    【解决方案1】:

    我推荐 Yehuda Katz 的 post on metaprogamming on Ruby's self。以下是我对您的问题的简要总结:

    在 Ruby 中,所有对象都有一个单例类(也称为元类)。对象首先从它们的单例类不可见地继承,然后从它们的显式类继承。 Ruby 类本身有自己的单例类,因为类也是对象。 class &lt;&lt; 成语只是 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 &lt;&lt; self; self end中的变量:

    Person.singleton_class 
    
    person = Person.new
    person.singleton_class
    

    由于一个类直接继承自它的单例类,这就是我们希望在元编程时动态添加类方法的地方。 Ruby 提供了几种方法来打开对象的范围,同时保持对周围范围的访问:class_evalinstance_eval。它们的行为方式存在细微差别(Yehuda 的帖子对此进行了解释),但您可以使用其中任一方法进入单例类的范围,将单例类上的方法解析为 self 并且仍然可以从周边范围。

    说了这么多,你可以对你的模块做一些小改动:

    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
    

    【讨论】:

    • 这似乎不适用于已经存在的方法。如果我想为 ActiveRecord 模型已经拥有的 :delete 方法设置别名怎么办?
    猜你喜欢
    • 2012-10-22
    • 2017-02-15
    • 2013-06-12
    • 1970-01-01
    • 2012-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-30
    相关资源
    最近更新 更多