【发布时间】:2011-09-16 00:39:38
【问题描述】:
我有几个扩展方法缺失的模块:
module SaysHello
def respond_to?(method)
super.respond_to?(method) || !!(method.to_s =~ /^hello/)
end
def method_missing(method, *args, &block)
if (method.to_s =~ /^hello/)
puts "Hello, #{method}"
else
super.method_missing(method, *args, &block)
end
end
end
module SaysGoodbye
def respond_to?(method)
super.respond_to?(method) || !!(method.to_s =~ /^goodbye/)
end
def method_missing(method, *args, &block)
if (method.to_s =~ /^goodbye/)
puts "Goodbye, #{method}"
else
super.method_missing(method, *args, &block)
end
end
end
class ObjectA
include SaysHello
end
class ObjectB
include SaysGoodbye
end
这一切都很好,例如ObjectA.new.hello_there 输出"Hello, hello_there"。同样,ObjectB.new.goodbye_xxx 输出 "Goodbye, xxx"。 respond_to? 也可以,例如ObjectA.new.respond_to? :hello_there return true。
但是,当您想同时使用 SaysHello 和 SaysGoodbye 时,这并不好用:
class ObjectC
include SaysHello
include SaysGoodbye
end
虽然ObjectC.new.goodbye_aaa 工作正常,但ObjectC.new.hello_a 行为却很奇怪:
> ObjectC.new.hello_aaa
Hello, hello_aaa
NoMethodError: private method `method_missing' called for nil:NilClass
from test.rb:22:in `method_missing' (line 22 was the super.method_missing line in the SaysGoodbye module)
它正确输出,然后抛出错误。 respond_to? 也不正确,ObjectC.new.respond_to? :hello_a 返回 false。
最后,添加这个类:
class ObjectD
include SaysHello
include SaysGoodbye
def respond_to?(method)
super.respond_to?(method) || !!(method.to_s =~ /^lol/)
end
def method_missing(method, *args, &block)
if (method.to_s =~ /^lol/)
puts "Haha, #{method}"
else
super.method_missing(method, *args, &block)
end
end
end
行为也很奇怪。 ObjectD.new.lol_zzz 有效,但是 ObjectD.new.hello_aand ObjectD.new.goodbye_t 在输出正确的字符串后都会抛出名称异常。 respond_to? 也无法使用 hello 和 goodbye 方法。
有没有办法让这一切正常工作?解释method_missing、Modules 和super 是如何交互的也是非常有用的。
编辑:coreyward 解决了这个问题,如果我在我定义的所有方法中使用 super 而不是 super.<method-name>(args...),程序可以正常工作。我不明白为什么会这样,所以我在What does super.<method-name> do in ruby?问了另一个问题@
【问题讨论】:
-
包含的模块被添加到继承链中;他们不会覆盖或替换方法。所以如果每个method_missing调用super,最终它们都会被调用。请参阅下面的答案。
标签: ruby method-missing