В общем случае модуль никогда не может переопределить метод в классе, в который он включен. Это связано с тем, что включение модуля работает так же, как подкласс.Суперкласс также не может переопределять методы своих подклассов, и вы не ожидаете, что он это сделает.
Когда модуль включен в класс, модуль вставляется сразу после класса в цепочке предков класса.Вызов super
из класса вызовет реализацию модуля .
class Something
module PreExtension; end
module PostExtension; end
include PreExtension
include PostExtension
end
Something.ancestors # => [Something, Something::PostExtension, Something::PreExtension, Object, Kernel]
Всякий раз, когда метод вызывается на Something
, Ruby просматриваетэтот список в порядке и вызывает первую реализацию, которую он находит.Если реализация вызывает super
, она продолжает поиск и находит следующий.
Это означает, что модули, включенные позже, имеют приоритет над модулями, включенными ранее, и могут вызвать super
, чтобы получить более ранние реализации модулей.Это связано с тем, что включенные модули вставляются в цепочку предков непосредственно после класса.Так работает упомянутый код маршрутизации.Этот код помещает все в модули, например:
class SomethingNew
module Base
def my_method
puts "(A)"
end
end
module Extension
def my_method
puts "(B)"
super
end
end
include Base
include Extension
end
SomethingNew.new.my_method
# Output:
# >> (B)
# >> (A)
SomethingNew.ancestors # => [SomethingNew, SomethingNew::Extension, SomethingNew::Base, Object, Kernel]
Вот почему alias_method_chain
существовал в первую очередь.Если поместить базовый код в модуль невозможно, я не уверен, как выполнить эквивалент alias_method_chain
.