Метод 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".