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
To find a suitable method for SubExample#subexample_method
Ruby first looks at ancestors chain of SubExample
SubExample.ancestors # => [SubExample, Example, Object, Kernel, BasicObject]
It starts from SubExample
. If we send subexample_method
message Ruby chooses the one available one SubExample and ignores Example#subexample_method
.
s.subexample_method # => :subexample
After SubExample
it checks Example
. If we send example_method
Ruby checks if SubExample
can reply to it or not and since it can't Ruby goes up the chain and looks into Example
.
s.example_method # => :example
After Ruby checks all defined methods then it runs method_missing
to see if it can reply or not. If we send missing_subexample_method
Ruby won't be able to find a defined method on SubExample
so it moves up to Example
. It can't find a defined method on Example
or any other class higher in chain either. Ruby starts over and runs method_missing
. method_missing
of SubExample
can reply to missing_subexample_method
.
s.missing_subexample_method # => :subexample
However if a method is defined Ruby uses defined version even if it is higher in the chain. For example if we send not_missed_method
even though method_missing
of SubExample
can reply to it Ruby walks up on SubExample
because it doesn't have a defined method with that name and looks into Example
which has one.
s.not_missed_method # => :example