Вместо использования псевдонимов методов, что, на мой взгляд, является чем-то ушедшим с момента введения Module#prepend
, мы можем добавить анонимный модуль, который имеет метод для каждого метода экземпляра класса, вбыть измеренным.Это приведет к вызову MyClass#a
для вызова метода в этом анонимном модуле, который измеряет время и просто обращается к super
для вызова фактической MyClass#a
реализации.
def measure(klass)
mod = Module.new do
klass.instance_methods(false).each do |method|
define_method(method) do |*args, &blk|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
value = super(*args, &blk)
finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
puts "elapsed: #{finish - start} seconds, value: #{value}."
value
end
end
end
klass.prepend(mod)
end
В качестве альтернативы вы можете использоватьclass_eval
, который также быстрее и позволяет просто вызывать super
без указания каких-либо аргументов для пересылки всех аргументов из вызова метода, что невозможно при define_method
.
def measure(klass)
mod = Module.new do
klass.instance_methods(false).each do |method|
class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{method}(*)
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
value = super
finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
puts "elapsed: \#{finish - start} seconds, value: \#{value}."
value
end
CODE
end
end
klass.prepend(mod)
end
Toиспользуйте это, просто сделайте:
measure(MyClass)