Dav*_*ani 9 ruby method-missing
我有几个扩展方法缺失的模块:
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
Run Code Online (Sandbox Code Playgroud)
这一切都运作良好,例如ObjectA.new.hello_there输出"Hello, hello_there".同样,ObjectB.new.goodbye_xxx产出"Goodbye, xxx".respond_to?也有效,例如ObjectA.new.respond_to? :hello_there返回true.
但是,当您想要同时使用SaysHello和时,这不能很好地工作SaysGoodbye:
class ObjectC
include SaysHello
include SaysGoodbye
end
Run Code Online (Sandbox Code Playgroud)
虽然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)
Run Code Online (Sandbox Code Playgroud)
它输出正确,然后抛出错误.也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
Run Code Online (Sandbox Code Playgroud)
也行为奇怪.ObjectD.new.lol_zzz但是,and ObjectD.new.goodbye_t在输出正确的字符串后,ObjectD.new.hello_a 都会抛出名称异常.respond_to?你好和再见的方法也失败了.
有没有办法让这一切正常工作?解释如何method_missing,模块和super交互也将非常有用.
编辑:coreyward解决了问题,如果我使用super而不是super.<method-name>(args...)我定义的所有方法,程序正常工作.我不明白为什么会这样,所以我在ruby中以super.<method-name>做什么问了另一个问题呢?
重新定义方法时,重新定义方法; 期.
当您使用method_missing方法define 包含第二个模块时,您正在执行的操作将覆盖先前定义的内容method_missing.你可以在重新定义之前通过别名来保持它,但你可能想要注意它.
另外,我不知道你为什么打电话super.method_missing.一旦你的method_missing定义没有技巧,你应该让Ruby知道它可以继续寻找处理调用的方法,只需通过调用super(不需要传递参数或指定方法名称).
关于超级(更新)
当你调用superRuby继续在继承链上寻找被调用方法的下一个定义时,如果它找到一个它调用它并返回响应.当你打电话时super.method_missing,请method_missing在响应中调用方法super().
拿这个(有点傻)的例子:
class Sauce
def flavor
"Teriyaki"
end
end
# yes, noodles inherit from sauce:
# warmth, texture, flavor, and more! ;)
class Noodle < Sauce
def flavor
sauce_flavor = super
"Noodles with #{sauce_flavor} sauce"
end
end
dinner = Noodle.new
puts dinner.flavor #=> "Noodles with Teriyaki sauce"
Run Code Online (Sandbox Code Playgroud)
你可以看到super就像其他任何一种方法一样,它只是在幕后做了一些魔术.如果你打电话给super.class你,你会看到String,因为"Teriyaki"是一个字符串.
现在有道理吗?