Метод Module#prepend в Ruby 2
Исследование механизмов работы метода Module#prepend в Ruby 2
С помощью prepend
методы модуля устанавливаются первоочередными при поиске метода в классе, в который подключен модуль.
Модуль, подключаемый с помощью prepend
может вызвать метод, который он перекрывает в классе с помощью обращения super
:
module A def m puts "A" super end end class B include A def m puts "B" end end class C prepend A def m puts "C" end end B.new.m #=> B C.new.m #=> A #=> C
Классическое применение include
:
module FooBar def hello puts 2 super end end class Foo def hello puts 'hello' end end class Bar < Foo include FooBar def hello puts 1 super end end Bar.new.hello
Результат:
1 2 "hello"
Происходит следующая последовательность вызова метода:
- Вывод "1"
- Вызов метода родителя с помощью
super
, но в иерархии на один шаг выше - метод модуля FooBar, вывод "2". Это обусловлено правилами поиска метода в Ruby: сначала поиск в самом классе, затем в подключенных модулях, а затем уже выше в иерархии классов. - В конце вызов
super
из модуля FooBar приводит к вызову Foo#hello
Теперь то же самое, но с Module#prepend:
module FooBar def hello puts 2 super end end class Foo def hello puts 'hello' end end class Bar < Foo prepend FooBar def hello puts 1 super end end Bar.new.hello
Результат:
2 1 "hello"
Предполагает, что методы подключаемого модуля имеют более высокий приоритет (первую очередь при поиске метода), чем методы класса.
Этот механизм безопаснее и выглядит гораздо лучше, чем alias_method_chain
или "monkey patching".