2008-10-09 11 views
63

프로그래밍 실습으로 클래스를 생성하고, 그 클래스에서 두 개의 객체를 인스턴스화하며, 하나의 객체를 monkeypatches하고, 다른 객체를 monkeypatch하기 위해 method_missing에 의존하는 Ruby 스 니펫을 작성했습니다.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이라는 인스턴스 메서드가 없으므로 이번에는 :define_method (누락 된 메서드의 이름) 및 :screech (define_method에 전달한 유일한 인수)을 사용하여 method_missing으로 다시 순환합니다. (객체의 "eigenclass"을 사용하여, 단지 그것을에 호출되는 객체를 정의하는)

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 

을 또는이 :

(모든 원숭이 개체에 대한 새로운 방법을 정의하는) 대신이 시도

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

+12

일반적으로 이것은 왜 항상 "method_missing"에 화이트리스트를 사용하여 * 실제로 * 관심있는 메소드를 처리하고 * 당신이 원하는 모든 것을 포워드하도록 * 왜 *해야 하는지를 보여줍니다 '슈퍼 체인 '을 이용해'먹이 사슬을 다스린 다 '. –

+1

@ JörgWMittag 줄에 더 많은 단어를 넣을 수 있습니다. * b) super를 사용하여 "먹이 사슬 위로"취급하고 싶지 않은 모든 것을 전달하십시오. ? * –

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 메서드는 모든 원숭이 개체에서 사용할 수 있습니다.