Я пытался выяснить, как расширить поведение модуля initialize
. Я хочу сделать это, не вызвав super в initialize
класса, который смешивается. Я хочу поддерживать нормальный шаблон вызова include
Я не могу понять это. Я читал все, что мог найти по этому вопросу, и, хотя у людей есть предложения, ни один из них на самом деле не работает (по крайней мере, в моих руках).Можно ли переопределить # инициализацию в модуле Ruby?
Вот что я (думаю) Я знаю:
- Если это может быть сделано на всех, это должно быть сделано с помощью крючка на
include
(т.е.Module.included(base)
). - Крюк
include
будет выполняться до того, как класс включения определитinitialize
, поэтому нет смысла просто пытаться определитьinitialize
сbase.instance_eval
, потому что он будет перезаписан. Было предложено использовать крючок
method_added
и иметь дело с ним. Это то, что я пытаюсь сейчас, но кажется, что крючок выполняется в начале определения метода, поэтому вы получаете то, что вы видите ниже.module Mo def self.included(klass) klass.instance_eval do def method_added(method) puts "Starting creation of #{method} for #{self.name}" case method when :initialize alias_method :original_initialize, :initialize puts "About to define initialize in Mo" def initialize original_initialize puts "Hello from Mo#initialize" end puts "Finished defining initialize in Mo" end puts "Finishing creation of #{method} for #{self.name}" end end end end class Foo include Mo def initialize puts "Hello from Foo#initialize" end end foo = Foo.new
Это приводит следующий вывод:
Starting creation of initialize for Foo
Starting creation of original_initialize for Foo
Finishing creation of original_initialize for Foo
About to define initialize in Mo
Finished defining initialize in Mo
Finishing creation of initialize for Foo
Hello from Foo#initialize
Он смотрит на меня как initialize
из класса Foo еще перезапись определение из модуля. Я предполагаю, что это потому, что определение все еще открыто, предполагая, что это не вопрос того, какой блок запускается последним, который закончен последним, который «побеждает».
Если кто-то действительно знает, как это сделать, и пусть он работает, пожалуйста, просветите меня.
FWIW, да, я думаю, у меня есть веская причина для этого.
Я сразу же узнал о 'prepend', задав вопрос. Мне это нравится! Все еще любопытно, есть ли способ сделать это в версии 1.9. * – Huliax
Есть ли что-то очевидное, что мне не хватает в использовании 'klass.send: prepend' вместо просто' klass.prepend'? – NobodysNightmare