Мой подход к этому состоит в том, чтобы обернуть объект, который я пытаюсь записать, с помощью объекта оболочки Logger, который просто вызывает исходный объект. Приведенный ниже код работает, оборачивая объект, который вы хотите зарегистрировать, с классом, который просто вызывает любые методы, которые вы хотите, для базового объекта, но обеспечивает способ перехватывать эти вызовы и регистрировать (или что-то еще) каждое событие доступа.
class Test
def self.items
puts " Class Items run"
"Return"
end
def item
puts " Instance item run"
return 47, 11
end
end
class GenericLogger
@@klass = Object # put the class you want to log into @@klass in a sub-class
def initialize(*args)
@instance = @@klass.new(*args)
end
def self.method_missing(meth, *args, &block)
retval = handle_missing(@@klass, meth, *args, &block)
if !retval[0]
super
end
retval[1]
end
def method_missing(meth, *args, &block)
retval = self.class.handle_missing(@instance, meth, *args, &block)
if !retval[0]
super
end
retval[1]
end
def self.handle_missing(obj, meth, *args, &block)
retval = nil
if obj.respond_to?(meth.to_s)
# PUT YOUR LOGGING CODE HERE
if obj.class.name == "Class"
puts "Logger code run for #{obj.name}.#{meth.to_s}"
else
puts "Logger code run for instance of #{obj.class.name}.#{meth.to_s}"
end
retval = obj.send(meth, *args)
return true, retval
else
return false, retval
end
end
end
# When you want to log a class, create one of these sub-classes
# and place the correct class you are logging in @@klass
class TestLogger < GenericLogger
@@klass = Test
end
retval = TestLogger.items
puts "Correctly handles return values: #{retval}"
tl = TestLogger.new
retval = tl.item
puts "Correctly handles return values: #{retval}"
begin
tl.itemfoo
rescue NoMethodError => e
puts "Correctly fails with unknown methods for instance of Test:"
puts e.message
end
begin
TestLogger.itemsfoo
rescue NoMethodError => e
puts "Correctly fails with unknown methods for class Test"
puts e.message
end
Выходные данные из этого примера кода:
Logger code run for Test.items
Class Items run
Correctly handles return values: Return
Logger code run for instance of Test.item
Instance item run
Correctly handles return values: [47, 11]
Correctly fails with unknown methods for instance of Test:
undefined method `itemfoo' for #<TestLogger:0x2962038 @instance=#<Test:0x2962008>>
Correctly fails with unknown methods for class Test
undefined method `itemsfoo' for TestLogger:Class