2009-09-07 5 views
0

이 코드는 어떻게 작동합니까?define_method 및 method_missing에 관한 질문

class Meta 

    @array = [:a,:b] 

    def self.method_missing(name, *args, &block) 
      if @array.include? name 
        self.class.send(:define_method, name) do 
          do_call(name) 
        end 
      else 
        puts "[#{name.inspect}] is not part of array!" 
      end 
    end 

    def do_call arg 
      puts "doing call for ['#{arg}'] " 
    end 
end 

아이디어는 본문

def a 
do_call(a) 
end 

을 갖는 (이후에 정의되는) Meta.a을 가지고있다. 그러나이 프로그램을 실행 한 후, 내 출력은 다음과 같습니다

[:do_call] is not part of array!

UPDATE : 이제 좀 이런 식으로 작업 :

class Meta 

    @array = [:a,:b] 

    def self.do_call arg 
      puts "doing call for ['#{arg}'] " 
    end 

    def self.method_missing(name, *args, &block) 
      puts "#{name} is missing!" 
      if @array.include? name 
        self.class.send(:define_method, name) do 
          do_call name 
      end 
      else 
        puts "[#{name.inspect}] is not part of array!" 
      end 
     end 
    end 

하지만 여전히, 여기 IRB 세션의 발췌 한 것입니다 :

[~/code] $ irb -r meta

irb(main):001:0> Meta.a

a is missing!

=> #

irb(main):002:0> Meta.a

doing call for ['a']

=> nil

irb(main):003:0> c = Meta.new

=> #

irb(main):004:0> c.a

NoMethodError: undefined method `a' for #

from (irb):4 

irb(main):005:0> Meta.methods

=> ["inspect", "send", "pretty_inspect", "class_eval", "clone", "yaml_tag_read_class", > >"public_methods", "protected_instance_methods", "send", "private_method_defined?", "equal?", "freeze", "do_call", "yaml_as", "methods", "instance_eval", "to_yaml", "display", "dup", "object_id", "include?", "private_instance_methods", "instance_variables", "extend", "protected_method_defined?", "const_defined?", "to_yaml_style", "instance_of?", "eql?", "name", "public_class_method", "hash", "id", "new", "singleton_methods", "yaml_tag_subclasses?", "pretty_print_cycle", "taint", "pretty_print_inspect", "frozen?", "instance_variable_get", "autoload", "constants", "kind_of?", "to_yaml_properties", "to_a", "ancestors", "private_class_method", "const_missing", "type", "yaml_tag_class_name", "instance_method", "<", "protected_methods", "<=>", "instance_methods", "==", "method_missing", "method_defined?", "superclass", ">", "pretty_print", "===", "instance_variable_set", "const_get", "is_a?", "taguri", ">=", "respond_to?", "to_s", "<=", "module_eval", "class_variables", "allocate", "class", "taguri=", "pretty_print_instance_variables", "tainted?", "public_instance_methods", "=~", "private_methods", "public_method_defined?", "autoload?", "id", "nil?", "untaint", "included_modules", "const_set", "a", "method"]

가 뭐라 구요? 'a'는 클래스 메소드이며 새로운 Meta 객체 (c)로 전달되지 않습니다. 왜?

답변

4

do_call을 인스턴스 메소드로 정의했는데, 클래스 메소드로 정의하려는 경우 일 가능성이 있습니다. 그래서 do_call에 대해 method_missing을 호출하는 이유는 오류가 발생하기 때문입니다.

self.class.send을 입력하면 self.class이 클래스가되므로 메서드는 메타뿐만 아니라 모든 클래스에서 사용할 수 있습니다. a 클래스의 방법이다

'a' is a class method and it is not passed on to the new Meta object (c). Why?

때문에 [1] : 당신의 갱신에 응답

class <<self 
    self 
end.send 

편집 : 당신은 아마 대신합니다. 클래스의 인스턴스는 클래스의 인스턴스 메소드 만 가져옵니다.

클래스를 인스턴스 메서드로 정의한 다음이를 작동하지 않는 Meta 인스턴스에서 호출하려고합니다. 클래스에 정의 된 싱글 톤 메소드뿐만 아니라 클래스의 루비 인스턴스 메쏘드에서 TheClass.the_method이 아니라 instance_of_the_class.the_method이 아닌 경우에만 호출 될 수 있습니다. Meta 인스턴스에서 메소드를 호출하려면 인스턴스 메소드로 정의하십시오. Meta.aMeta.new.a을 수행하려면 인스턴스와 클래스 메소드 a을 모두 정의해야합니다.

[1] 사실 내가 말했듯이, 당신이 정의하는 방식은 메타의 클래스 메소드조차도 아닙니다. Class의 인스턴스 메소드입니다 (즉, String.a로도 호출 할 수 있음을 의미 함).

+0

또한이 접근법의 큰 경고는 doy 문제 –

+0

의 무한 루프를 method_missing하여 지금도 이와 같이 작동하고 있습니다. –

+0

내가 언급 한 변경을 한 후에, 그것은 나에게 잘 작동한다. http://pastie.org/609427 – sepp2k