From: "Volkmann, Mark" Date: 2003-08-07T04:00:44+09:00 Subject: rolling your own AOP This message is in MIME format. Since your mail reader does not understand this format, some or all of this message may not be legible. ------_=_NextPart_001_01C35C4C.BF86E246 Content-Type: text/plain; charset="iso-8859-1" I've been experimenting to see how easy it is to do AOP kinds of things with Ruby. I know I could use the AspectR package and probably should do that, but I wanted to see what was involved. Here's an example of how you could specify code that you want to run at the beginning of each method in some class. It just prints "calling foo" where foo is the name of the method being executed. Feel free to suggest ways I could improve this code. -- class Demo def methodA puts 'methodA is running' end def methodB puts 'methodB is running' end end module AOP def AOP.addBeforeAdvice(klass, &advice) # Add the advice code block as a class variable # of the class being instrumented. klass.class_eval "@@beforeAdvice = advice" # For each instance method in the class, excluding inherited methods ... for method_name in klass.instance_methods(false) do new_name = "__#{method_name}" klass.class_eval <<-HERE # Create an alias for the method. alias_method :#{new_name}, :#{method_name} # Redefine the method. def #{method_name} # Execute the advice code. @@beforeAdvice.call(self) # Execute the original method. #{new_name} end HERE end end end def currentMethodName # Get 2nd to last entry in call stack, # take the last word and remove the quotes around it. caller[-2].split.last[1..-2] end if $0 == __FILE__ AOP.addBeforeAdvice(Demo) { puts "calling #{currentMethodName}" } o = Demo.new o.methodA o.methodB end --- The output is calling methodA methodA is running calling methodB methodB is running ------------------------------------------------------------------------------------------------------------------- A.G. Edwards & Sons' outgoing and incoming e-mails are electronically archived and subject to review and/or disclosure to someone other than the recipient. ------------------------------------------------------------------------------------------------------------------- ------_=_NextPart_001_01C35C4C.BF86E246 Content-Type: text/html; charset="iso-8859-1" RE: adding methods to an existing class
I've been experimenting to see how easy it is to do AOP kinds of things with Ruby.  I know I could use the AspectR package and probably should do that, but I wanted to see what was involved.  Here's an example of how you could specify code that you want to run at the beginning of each method in some class.  It just prints "calling foo" where foo is the name of the method being executed.  Feel free to suggest ways I could improve this code.
 
--
 
class Demo
  def methodA
    puts 'methodA is running'
  end
 
  def methodB
    puts 'methodB is running'
  end
end
 
module AOP
  def AOP.addBeforeAdvice(klass, &advice)
    # Add the advice code block as a class variable
    # of the class being instrumented.
    klass.class_eval "@@beforeAdvice = advice"
   
    # For each instance method in the class, excluding inherited methods ...
    for method_name in klass.instance_methods(false) do
      new_name = "__#{method_name}"
      klass.class_eval <<-HERE
        # Create an alias for the method.
        alias_method :#{new_name}, :#{method_name}
       
        # Redefine the method.
        def #{method_name}
          # Execute the advice code.
          @@beforeAdvice.call(self)
          # Execute the original method.
          #{new_name}
        end
      HERE
    end
  end
end
 
def currentMethodName
  # Get 2nd to last entry in call stack,
  # take the last word and remove the quotes around it.
  caller[-2].split.last[1..-2]
end
 
if $0 == __FILE__
  AOP.addBeforeAdvice(Demo) {
    puts "calling #{currentMethodName}"
  }
 
  o = Demo.new
  o.methodA
  o.methodB
end
 
---
 
The output is
calling methodA
methodA is running
calling methodB
methodB is running


-------------------------------------------------------------------------------------------------------------------
A.G. Edwards & Sons' outgoing and incoming e-mails are electronically
archived and subject to review and/or disclosure to someone other
than the recipient.

-------------------------------------------------------------------------------------------------------------------
------_=_NextPart_001_01C35C4C.BF86E246--