Я пытаюсь обернуть все методы экземпляра TestClass
для выполнения кода до и после . Вызывается метод экземпляра.Пока этот код работает:
module Wrapper
def wrap(*methods)
prependable_module = Module.new do
methods.each do |m|
define_method(m) do |*args, &block|
p 1
super(*args, &block)
p 3
end
end
end
prepend prependable_module
end
end
class TestClass
extend Wrapper
wrap :instance_method1
def instance_method1
p 2
end
end
TestClass.new.instance_method1 # => 1, 2, 3
Я могу вызвать wrap
со всеми именами методов в качестве аргументов.Если я пытаюсь обернуть все методы, не перечисляя их по отдельности, мне нужно вызвать его, используя instance_methods(false)
внизу определения класса.
class TestClass
extend Wrapper
def instance_method1
p 2
end
wrap(*instance_methods(false))
end
В Rails все методы обратного вызова, такие как before_action
или after_create
обычно вызывается поверх определения класса. Моя цель - также вызвать wrap
поверх определения класса (без перечисления всех методов по отдельности).В этом случае я не могу вызвать instance_methods(false)
поверх определения класса, потому что на данный момент метод не определен.
Спасибо за вашу помощь!
Обновление
Благодаря подходу Киммо Лехто я могу обернуть каждый экземплярный метод с помощью хука method_added
.Я не хочу добавлять новый модуль для каждого определенного метода, поэтому я добавляю все переопределенные методы в один и тот же модуль.
module Wrapper
def method_added(method_name)
tmp_module = find_or_initialize_module
return if tmp_module.instance_methods(false).include?(method_name)
tmp_module.define_method(method_name) do |*args, &block|
p 1
super(*args, &block)
p 3
end
end
def find_or_initialize_module
module_name = "#{name}Wrapper"
module_idx = ancestors.map(&:to_s).index(module_name)
unless module_idx
prepend Object.const_set(module_name, Module.new)
return find_or_initialize_module
end
ancestors[module_idx]
end
end
class TestClass
extend Wrapper
def instance_method1
p 2
end
end
tc = TestClass.new
tc.instance_method1 # => 1, 2, 3