Cайт веб-разработчика, программиста Ruby on Rails ESV Corp. Екатеринбург, Москва, Санкт-Петербург, Новосибирск, Первоуральск

Админка на Ruby on Rails

Метод 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. Вывод "1"
  2. Вызов метода родителя с помощью super, но в иерархии на один шаг выше - метод модуля FooBar, вывод "2". Это обусловлено правилами поиска метода в Ruby: сначала поиск в самом классе, затем в подключенных модулях, а затем уже выше в иерархии классов.
  3. В конце вызов 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".