2011-09-07 73 views
4

我需要在Parent類的每個子類中注入一個回調。所以,方法與回調必須首先調用,和後來所有本鏈:ruby​​混合和繼承注入

有可能才達到思想alias_method(或alias_method_chain):

module ChildMod1 
    def save 
    puts "save ChildMod1" 
    super 
    end 
end 

module ChildMod2 
    def save 
    puts "save ChildMod2" 
    super 
    end 
end 

class Parent 
    def save 
    puts "save Parent" 
    end 
end 
class Child < Parent 
    include ChildMod1 
    include ChildMod2 

    def save 
    puts "save Child" 
    super 
    end 

    alias_method :old_save, :save 
    module_eval <<-R 
     def save 
     puts "save Callback" 
     old_save 
     end 
    R 
end 
c = Child.new 
c.save 

輸出

save Callback 
save Child 
save ChildMod2 
save ChildMod1 
save Parent 

但是它可能通過繼承來實現這一點?如在ChildMod1或ChildMod2中。我whant執行模塊空間內的代碼從繼承得到的所有好處

module ChildMod1 
    def save 
    puts "save ChildMod1" 
    super 
    end 
end 

module ChildMod2 
    def save 
    puts "save ChildMod2" 
    super 
    end 
end 

class Parent 
    def save 
    puts "save Parent" 
    end 
end 
class Child < Parent 
    include ChildMod1 
    include ChildMod2 

    def save 
    puts "save Child" 
    super 
    end 

    module_eval <<-R 
     def save 
     puts "save Callback" 
     super 
     end 
    R 

end 

c = Child.new 
c.save 

輸出

save Callback 
save ChildMod2 
save ChildMod1 
save Parent 

正如你看到的,它只是簡單地覆蓋兒童

UPDATE wdebeaum解決方案好,但如果我需要創建很多方法動態地認爲module_eval或模擬並重新定義它們在一個類中呢?我無法爲他們創建一個單獨的模塊。

class TestEval 
    def redefine_me 
    puts "Test method" 
    super # I expect that it will call Eval method, but module_eval just overwrite it 
    end 

    module_eval <<-R 
     def redefine_me 
     puts "Eval method" 
     end 
    R 
end 

UPDATE2 使用一個單獨的類,我會得到的,而不是檢驗錯鏈評估和演示=>檢測=>評估

class TestEval 
    def initialize 
    class << self 
     def redefine_me 
     puts "Eval method" 
     super 
     end 
    end 
    end 
    def redefine_me 
    puts "Test method" 
    end 
end 

TestEval.new.redefine_me 

我們假設,我有一個類的方法「場」 ,爲Datastream添加一些實例方法(前者會添加setter和getter方法),並且我想重新定義其中一種方法,如下所示:

class Datastream 
    field :name 
    def name=(value) 
    puts "redefined!" 
    super 
    end 
end 
+0

BTW我這個問題後創造了一個寶石https://github.com/AlexParamonov/ inheritance_module_eval 只是忘了在這裏添加它 – AlexParamonov

回答

2

您可以將回調方法放在其自己的模塊中,並將該父級的初始化方法重寫爲該模塊的extend(如果需要,使用alias_method)。這將通過將回調方法鏈接到每個Child實例的單例類來將該回調方法放在Child的方法之前。剛剛從你的第二個代碼示例刪除module_eval部分,c = Child.new前補充一點:

module Callback 
    def save 
    puts "save Callback" 
    super 
    end 
end 

class Parent 
    alias_method :old_initialize, :initialize 
    def initialize 
    old_initialize 
    extend Callback 
    end 
end 

輸出:

save Callback 
save Child 
save ChildMod2 
save ChildMod1 
save Parent 
+0

不錯。我已經投票給你了。你的解決方案是好的,但是如果我需要動態地創建很多方法,認爲module_eval或analog並在類中重新定義它們會怎麼樣?我無法爲他們創建一個單獨的模塊。我會盡快更新一篇新文章。 – AlexParamonov

+0

爲什麼你不能製作一個單獨的模塊?如果你只是想動態地創建方法,你可以使用'Module.new'來動態創建模塊,然後像你一樣在模塊上使用'module_eval'。如果你根本不能創建新模塊,你可以嘗試爲每個實例的單例類添加方法,而不是擴展模塊。但對我來說,這似乎是額外的工作,沒有什麼理由。 – wdebeaum

+0

請參閱第1篇文章 – AlexParamonov