Another alternative is to use unrelated methods:
class A original_test = instance_method(:test) define_method(:test) do puts "Log Message!" original_test.bind(self).call end end class A original_test = instance_method(:test) counter = 0 define_method(:test) do counter += 1 puts "Counter = #{counter}" original_test.bind(self).call end end irb> A.new.test Counter = 1 Log Message!
This has the advantage that it does not pollute the namespace with additional method names and is fairly easy to abstract if you want to create an add_logging class add_logging or whatever you have.
class Module def add_logging(*method_names) method_names.each do |method_name| original_method = instance_method(method_name) define_method(method_name) do |*args,&blk| puts "logging #{method_name}" original_method.bind(self).call(*args,&blk) end end end end class A add_logging :test end
Or, if you want to be able to make a bunch of aspects without a lot of boiler plates, you can write a method that writes methods for adding an aspect!
class Module def self.define_aspect(aspect_name, &definition) define_method(:"add_#{aspect_name}") do |*method_names| method_names.each do |method_name| original_method = instance_method(method_name) define_method(method_name, &(definition[method_name, original_method])) end end end # make an add_logging method define_aspect :logging do |method_name, original_method| lambda do |*args, &blk| puts "Logging #{method_name}" original_method.bind(self).call(*args, &blk) end end # make an add_counting method global_counter = 0 define_aspect :counting do |method_name, original_method| local_counter = 0 lambda do |*args, &blk| global_counter += 1 local_counter += 1 puts "Counters: global@ #{global_counter}, local@ #{local_counter}" original_method.bind(self).call(*args, &blk) end end end class A def test puts "I'm Doing something..." end def test1 puts "I'm Doing something once..." end def test2 puts "I'm Doing something twice..." puts "I'm Doing something twice..." end def test3 puts "I'm Doing something thrice..." puts "I'm Doing something thrice..." puts "I'm Doing something thrice..." end def other_tests puts "I'm Doing something else..." end add_logging :test, :test2, :test3 add_counting :other_tests, :test1, :test3 end
source share