【问题标题】:question regarding define_method and method_missing关于define_method和method_missing的问题
【发布时间】:2010-11-26 06:56:36
【问题描述】:

我怎样才能使这段代码工作?

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

想法是让Meta.a(在被定义之后)拥有

def a 
 do_call(a)
end

在它的身体里。但是运行这个之后,我的输出是:

[:do_call] 不是数组的一部分!

更新:现在有点像这样工作:

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 元

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

缺少一个!

=> #

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

正在调用 ['a']

=> 无

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

=> #

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

NoMethodError: # 的未定义方法 `a'

    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?", “相等?”,“冻结”,“do_call”,“yaml_as”,“方法”,“instance_eval”,“to_yaml”,“显示”, “dup”、“object_id”、“包括?”、“private_instance_methods”、“instance_variables”、“扩展”、 “protected_method_defined?”、“const_defined?”、“to_yaml_style”、“instance_of?”、“eql?”、 “名称”、“public_class_method”、“hash”、“id”、“new”、“singleton_methods”、 “yaml_tag_subclasses?”,“pretty_print_cycle”,“污点”,“pretty_print_inspect”,“冻结?”, “instance_variable_get”、“autoload”、“constants”、“kind_of?”、“to_yaml_properties”、“to_a”、 “祖先”,“private_class_method”,“const_missing”,“类型”,“yaml_tag_class_name”, “instance_method”、“”、“instance_methods”、“==”、 “method_missing”、“method_defined?”、“超类”、“>”、“pretty_print”、“===”、 “instance_variable_set”、“const_get”、“is_a?”、“taguri”、“>=”、“respond_to?”、“to_s”、“id”、“nil?”、“untaint”、 "included_modules", "const_set", "a", "method"]

什么给了? 'a' 是一个类方法,它不会传递给新的 Meta 对象 (c)。为什么?

【问题讨论】:

    标签: ruby metaprogramming method-missing


    【解决方案1】:

    您将 do_call 定义为实例方法,而您可能打算将其定义为类方法。这就是为什么它也为 do_call 调用 method_missing 并且你得到了你得到的错误。

    还请注意,当您执行self.class.send 时,self.class 将是 Class,因此该方法将适用于所有类,而不仅仅是 meta。您可能更愿意:

    class <<self
      self
    end.send
    

    根据您的更新进行编辑:

    'a' 是一个类方法,它不会传递给新的 Meta 对象 (c)。为什么?

    因为a 是一个类方法[1]。类的实例只获取类的实例方法。

    您将 a 定义为 Class 上的实例方法,然后尝试在 Meta 的实例上调用它,这不起作用。在 Class 的 ruby​​ 实例方法以及类上定义的单例方法中,只能通过 TheClass.the_method 调用,而不是 instance_of_the_class.the_method。如果要在 Meta 的实例上调用方法,请将其定义为实例方法。如果你希望能够做到Meta.aMeta.new.a,你必须同时定义一个实例和一个类方法a

    [1] 实际上,正如我已经说过的,您定义它的方式甚至不是 Meta 的类方法。它是 Class 的实例方法(这意味着您也可以将其称为 String.a)。

    【讨论】:

    • 另外,这种方法的一大警告是厄运问题的 method_missing 无限循环
    • 进行我提到的更改后,它对我来说效果很好。 pastie.org/609427
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-13
    • 2012-03-06
    • 2019-04-05
    • 2021-01-19
    • 2011-08-09
    • 2010-11-20
    相关资源
    最近更新 更多