消息传递继承链
class Example
def example_method
:example
end
def subexample_method
:example
end
def not_missed_method
:example
end
def method_missing name
return :example if name == :missing_example_method
return :example if name == :missing_subexample_method
return :subexample if name == :not_missed_method
super
end
end
class SubExample < Example
def subexample_method
:subexample
end
def method_missing name
return :subexample if name == :missing_subexample_method
return :subexample if name == :not_missed_method
super
end
end
s = Subexample.new
要找到适合 SubExample#subexample_method
Ruby 的方法,首先要看一下 SubExample
的祖先链
SubExample.ancestors # => [SubExample, Example, Object, Kernel, BasicObject]
它从 SubExample
开始。如果我们发送 subexample_method
消息,Ruby 选择一个可用的 SubExample 并忽略 Example#subexample_method
。
s.subexample_method # => :subexample
在 SubExample
之后它会检查 Example
。如果我们发送 example_method
Ruby 检查 SubExample
是否可以回复它,因为它不能 Ruby 上链并查看 Example
。
s.example_method # => :example
在 Ruby 检查所有定义的方法之后,它运行 method_missing
以查看它是否可以回复。如果我们发送 missing_subexample_method
Ruby 将无法在 SubExample
上找到一个已定义的方法,所以它会移动到 Example
。它无法在 Example
或任何其他类别的链上找到定义的方法。Ruby 重新启动并运行 method_missing
。SubExample
的 method_missing
可以回复 missing_subexample_method
。
s.missing_subexample_method # => :subexample
但是,如果定义了一个方法,Ruby 就会使用已定义的版本,即使它在链中更高。例如,如果我们发送 not_missed_method
,即使 SubExample
的 method_missing
可以回复它,Ruby 也会在 SubExample
上走路,因为它没有一个带有该名称的已定义方法,并且会查看有一个的 Example
。
s.not_missed_method # => :example