2012-10-17 75 views
1

我正在使用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聲明,我用這個(而不是class << self ... end塊)爲了範圍my_method_name變量,使得動態生成的混疊。

我想了解到底爲什麼如何singleton_class作品在上面的代碼,如果有更好的方法(也許,一個更容易維護和高性能的一個)實現相同的(別名,定義單身法等),但「正確的方式」,因爲我認爲不是這樣。

回答

6

我推薦Yehuda Katz的post on metaprogamming on Ruby's self。下面是我對你的問題的簡要總結:

在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 
+0

這似乎不是那些已經在現有的方法來工作。如果我想要別名ActiveRecord模型已有的delete方法,該怎麼辦? –