На множественных вызовах расширения #
Рассмотрим код из этой статьи:
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
Причина в том, что это 2,6, а не 2,2, потому что каждый вызов extend
добавляет модуль в цепочку предков класса singleton-экземпляра, как указано ниже.
2 ответа
extend
добавляет в список предков, он не заменяет каких-либо существующих предков - если вы посмотрите coffee.singleton_class.ancestors
после второго продления вы можете увидеть, что он включает в себя как Milk
а также Sugar
,
Если вы используете 2.2, вы можете использовать новый super_method
способ проверить это:
coffee.method(:cost) => #<Method: Coffee(Sugar)#cost>
Это показывает, что если вы называете "стоимость", вы сначала переходите к реализации модуля "Сахар"
coffee.method(:cost).super_method => #<Method: Coffee(Milk)#cost>
это показывает, что в Sugar#cost
ты звонишь super
тогда вы перейдете к методу, предоставленному Milk
и наконец
coffee.method(:cost).super_method.super_method => #<Method: Coffee#cost>
когда вы вызываете супер оттуда вы в конечном итоге в реализации базового класса
Вы всегда просто #cost
который модифицируется будущими аргументами - это не вопрос перезаписи:
coffee = Coffee.new
#cost is 2
coffee.extend(Milk)
#cost is 2.4
coffee.extend(Sugar)
#cost is 2.6
В статье говорится, что эта реализация аналогична другим примерам, основанным на наследовании, которые они дают.