Исследование механизмов работы метода 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".
Исследование механизмов работы метода Module#prepend в Ruby 2
С помощью
prepend
методы модуля устанавливаются первоочередными при поиске метода в классе, в который подключен модуль.Модуль, подключаемый с помощью
prepend
может вызвать метод, который он перекрывает в классе с помощью обращенияsuper
:Классическое применение
include
:Результат:
Происходит следующая последовательность вызова метода:
super
, но в иерархии на один шаг выше - метод модуля FooBar, вывод "2". Это обусловлено правилами поиска метода в Ruby: сначала поиск в самом классе, затем в подключенных модулях, а затем уже выше в иерархии классов.super
из модуля FooBar приводит к вызову Foo#helloТеперь то же самое, но с Module#prepend:
Результат:
Предполагает, что методы подключаемого модуля имеют более высокий приоритет (первую очередь при поиске метода), чем методы класса.
Этот механизм безопаснее и выглядит гораздо лучше, чем
alias_method_chain
или "monkey patching".