На множественных вызовах расширения #

Рассмотрим код из этой статьи:

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

В статье говорится, что эта реализация аналогична другим примерам, основанным на наследовании, которые они дают.

Другие вопросы по тегам