Consider a code from this article:
class Coffee
def cost
2
end
end
module Milk
def cost
super + 0.4
end
end
module Sugar
def cost
super + 0.2
end
end
coffee = Coffee.new
coffee.extend(Milk)
coffee.extend(Sugar)
coffee.cost # 2.6, while I expected 2.2
The reason why it's 2.6 and not 2.2 is because every call of extend
adds a module into the instance singleton class ancestors chain, as pointed out below.
extend
adds to the list of ancestors, it doesn't replace any existing ancestors - if you examine coffee.singleton_class.ancestors
after the second extend you can see that it includes both Milk
and Sugar
.
If you are running 2.2, you can use the new super_method
method to examine this:
coffee.method(:cost) => #<Method: Coffee(Sugar)#cost>
This shows that if you call 'cost' you first go to the 'Sugar' module's implementation
coffee.method(:cost).super_method => #<Method: Coffee(Milk)#cost>
this shows that in Sugar#cost
you call super
then you will jump in to the method provided by Milk
and finally
coffee.method(:cost).super_method.super_method => #<Method: Coffee#cost>
when you call super from there you end up in the base class implementation