如何使此代码有效?
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 meta
IRB(主):001:0> Meta.a
a缺少!
=> #
IRB(主):002:0> Meta.a
打电话给['a']
=>零
IRB(主):003:0> c = Meta.new
=> #
IRB(主):004:0> C.A
NoMethodError:#
的未定义方法`a'from (irb):4
IRB(主):005:0> Meta.methods
=> [“inspect”,“send”,“pretty_inspect”,“class_eval”,“clone”,“yaml_tag_read_class”,> >“public_methods”,“protected_instance_methods”,“发送”,“private_method_defined?”, “相等?”,“冻结”,“do_call”,“yaml_as”,“方法”,“instance_eval”,“to_yaml”,“显示”, “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”,“污点”,“pretty_print_inspect”,“冻结?”, “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”,“污点?”,“public_instance_methods”,“=〜”, “private_methods”,“public_method_defined?”,“autoload?”,“ id ”,“nil?”,“untaint”, “included_modules”,“const_set”,“a”,“method”]
是什么给出的? 'a'是一个类方法,它不会传递给新的Meta对象(c)。为什么呢?
答案 0 :(得分:4)
您将do_call定义为实例方法,而您可能希望将其定义为类方法。这就是为什么它也为do_call调用method_missing而你得到的错误。
另请注意,当您执行self.class.send
时,self.class
将为Class,因此该方法将适用于所有类,而不仅仅是meta。你可能更想要:
class <<self
self
end.send
编辑以响应您的更新:
'a'是一个类方法,它不会传递给新的Meta对象(c)。为什么呢?
因为a
是一种类方法[1]。类的实例只获取类的实例方法。
您在Class上定义了一个实例方法,然后尝试在Meta的实例上调用它,这不起作用。在ruby实例中,类的方法以及类上定义的单例方法只能通过执行TheClass.the_method
而不是instance_of_the_class.the_method
来调用。如果要在Meta实例上调用方法,请将其定义为实例方法。如果您希望能够Meta.a
以及Meta.new.a
,则必须同时定义实例和类方法a
。
[1]实际上,正如我已经说过的那样,你定义它的方式甚至不是Meta的类方法。它是Class的实例方法(这意味着您也可以将其称为例如String.a)。