我正在尝试将Module#prepend
用于某些钩子:
module B
def method_missing(method, *args, &block)
p 'B method_missing'
#if condition
# do_something
#else
super method, *args, &block #I need to call method from A
#end
end
end
class A
prepend B
def hello
p 'A hello'
end
end
A.new.hello #=> "A hello"
但我想要的是:
#=> "B method_missing"
#=> "A hello"
但是如果我调用一个不存在的方法:
A.new.baybay #=> "B method_missing"
#and error `method_missing': undefined method `baybay' for #<A:0x0000000182c430> (NoMethodError)
关于祖先:
A.ancestors #=> [B, A, Object, Kernel, BasicObject]
A.new.singleton_class.ancestors #=> [#<Class:#<A:0x000000027b6900>>, B, A, Object, Kernel, BasicObject]
但是如果我创建一个具有相同名称的方法:
module B
def hello
p 'B hello'
end
end
A.new.hello #=> "B hello"
为什么不与method_missing
合作?我怎样才能得到我想要的东西?任何解决方案?
答案 0 :(得分:1)
原因是在方法调用时,ruby将遍历祖先链,搜索具有所述名称的方法。 仅如果找不到此类方法,则会为method_missing
执行第二次遍历。
method_missing
中编写A
:
module B
def method_missing(method, *args, &block)
p 'B method_missing'
super method, *args, &block
end
end
class A
prepend B
def method_missing(method, *args, &block)
p 'A hello' if method == :hello
end
end
A.new.hello # => "B method_missing"
# => "A hello"
<小时/> 另一种不需要您更改
A
类的方法是使用Module#prepended
挂钩。然后,您可以检查班级A
中的所有方法并使用Module#define_method
。
然而,这将是不必要的复杂,我认为这样做没有多大价值,除非你正在编写某种框架。为什么不把这个包裹起来呢?