訊息傳遞繼承鏈
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