prepend
в основном похоже на импорт модуля, но в конечном итоге он оказывается «перед» другим кодом (поэтому модуль может вызвать super
для запуска кода, перед которым он находится).
Это Это работоспособный пример с чем-то близким к вашей ситуации.
module MyModule
def read_attribute(attr_name)
super("modified_#{attr_name}")
end
end
class Example
prepend MyModule
def read_attribute(attr_name)
puts "Reading #{attr_name}"
end
end
Example.new.read_attribute(:foo)
# Outputs: Reading modified_foo
Я определил read_attribute
непосредственно на Example
, но он также мог бы быть методом, унаследованным от суперкласса (например, ActiveRecord::Base
).
Это более короткая, но более криптовая версия c, в которой используется анонимный модуль:
class Example
prepend(Module.new do
def read_attribute(attr_name)
super("modified_#{attr_name}")
end
end)
def read_attribute(attr_name)
puts "Reading #{attr_name}"
end
end
Example.new.read_attribute(:foo)
# Outputs: Reading modified_foo
ОБНОВЛЕНИЕ:
Просто для удовольствия и по адресу вопрос ниже, вот как это можно сделать без необходимости явно создавать какие-либо модули самостоятельно. Я не думаю, что решил бы сделать это сам, так как это скрывает общий шаблон.
# You'd do this once somewhere, e.g. config/initializers/prepend_block.rb in a Rails app.
class Module
def prepend_block(&block)
prepend Module.new.tap { |m| m.module_eval(&block) }
end
end
# Now you can do:
class Example
prepend_block do
def read_attribute(attr_name)
super("modified_#{attr_name}")
end
end
def read_attribute(attr_name)
puts "Reading #{attr_name}"
end
end
Example.new.read_attribute(:foo)
# Outputs: Reading modified_foo