2008-10-09 28 views
63

作爲編程練習,我編寫了一個創建類的Ruby片段,實例化該類中的兩個對象,monkeypatches一個對象,並依靠method_missing來修改另一個對象。Ruby:define_method與def

這是交易。這按預期工作:

class Monkey 

    def chatter 
    puts "I am a chattering monkey!" 
    end 

    def method_missing(m) 
    puts "No #{m}, so I'll make one..." 
    def screech 
     puts "This is the new screech." 
    end 
    end 
end 

m1 = Monkey.new 
m2 = Monkey.new 

m1.chatter 
m2.chatter 

def m1.screech 
    puts "Aaaaaargh!" 
end 

m1.screech 
m2.screech 
m2.screech 
m1.screech 
m2.screech 

你會注意到我有一個method_missing的參數。我這樣做是因爲我希望使用define_method來動態創建具有適當名稱的缺少方法。但是,它不起作用。事實上,即使使用define_method使用靜態名稱,像這樣:

def method_missing(m) 
    puts "No #{m}, so I'll make one..." 
    define_method(:screech) do 
    puts "This is the new screech." 
    end 
end 

結果如下結束:

ArgumentError: wrong number of arguments (2 for 1) 

method method_missing in untitled document at line 9 
method method_missing in untitled document at line 9 
at top level in untitled document at line 26 
Program exited. 

是什麼使得錯誤消息更撲朔迷離的是,我只有method_missing一個參數。 ...

回答

132

define_method是對象類別的(私有)方法。您從實例調用它。沒有實例方法define_method,因此它會遞歸到您的method_missing,這次是:define_method(缺少方法的名稱)和:screech(您傳遞給define_method的唯一參數)。

試試這個(定義上的所有猴子對象的新方法):

def method_missing(m) 
    puts "No #{m}, so I'll make one..." 
    self.class.send(:define_method, :screech) do 
     puts "This is the new screech." 
    end 
end 

還是這個(定義它只能在它被要求的對象,使用對象的「eigenclass」):

def method_missing(m) 
    puts "No #{m}, so I'll make one..." 
    class << self 
     define_method(:screech) do 
     puts "This is the new screech." 
     end 
    end 
end 
+1

這是一個很好的答案,Avdi,它清除了我有的其他問題。謝謝。 – gauth 2008-10-09 11:40:11

4

self.class.define_method(:尖叫)是不行的,因爲define_method是私有方法 你能做到這一點

class << self 
    public :define_method 
end 
def method_missing(m) 
puts "No #{m}, so I'll make one..." 
Monkey.define_method(:screech) do 
    puts "This is the new screech." 
end 
4
def method_missing(m) 
    self.class.class_exec do 
     define_method(:screech) {puts "This is the new screech."} 
    end 
end 

screech方法將可用於所有猴子對象。