CSC/ECE 517 Fall 2007/wiki1b 5 b4: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 12: Line 12:


Example:  
Example:  
     MyAspect.new.wrap(MyClass, :log_entry, :log_exit, /method/)
     <pre>MyAspect.new.wrap(MyClass, :log_entry, :log_exit, /method/)</pre>
    In this case, all calls to methods on MyClass with names beginning with "method" will be wrapped by calls to log_entry and log_exit.
 
In this case, all calls to methods on MyClass with names beginning with "method" will be wrapped by calls to log_entry and log_exit.
===unwrap===


     
Arguments: ''target, pre, post, *args''
 
Removes the advice specified by ''pre'' and ''post'' from all methods specified in ''args'' on the class or object ''target''.  To specify more than one method, pass a regular expression to ''args''.
 
Example:
    <pre>MyAspect.new.unwrap(MyClass, :log_entry, :log_exit, /method/)</pre>
 
In this case, the advice log_entry and log_exit will no longer be executed when calls to methods on MyClass with names beginning with "method" are made.


get_methods(target, args).each do |method_to_wrap|
===wrap_with_code===
add_advice(target, PRE, method_to_wrap, pre)
    def wrap_with_code(target, preCode, postCode, *args)
add_advice(target, POST, method_to_wrap, post)
      prepare(target)
      get_methods(target, args).each do |method_to_wrap|
target.__aop_wrap_with_code(method_to_wrap, preCode, postCode)
       end
       end
     end
     end
 
   
     def unwrap(target, pre, post, *args)
===add_advice===
       get_methods(target, args).each do |method_to_unwrap|
     def add_advice(target, joinpoint, method, advice)
remove_advice(target, PRE, method_to_unwrap, pre)
       prepare(target)
remove_advice(target, POST, method_to_unwrap , post)
      if advice
target.__aop_install_dispatcher(method)
target.__aop_add_advice(joinpoint, method, self, advice)
       end
       end
     end
     end
   
===remove_advice===
    def remove_advice(target, joinpoint, method, advice)
      target.__aop_remove_advice(joinpoint, method, self, advice) if advice
    end




     
==Example: Profiler Aspect==
==Example: Profiler Aspect==
One common use of AOP is profiling.  Profiling refers to the collection of data about the dynamic behavior of a system.  It is done to determine a breakdown of where time and memory are being consumed at runtime and make optimizations based on the results.  In the example below, which is based off a sample found in '''make a link -- Ruby Developer's Guide''', we create an aspect that will determine the number of (milli)seconds spent in a single method.  It is kept very simple to clearly illustrate the functionality of AspectR; a full-featured profiler would need to account for non-serialized and nested method invocations, aggregate the results, etc.
One common use of AOP is profiling.  Profiling refers to the collection of data about the dynamic behavior of a system.  It is done to determine a breakdown of where time and memory are being consumed at runtime and make optimizations based on the results.  In the example below, which is based off a sample found in '''make a link -- Ruby Developer's Guide''', we create an aspect that will determine the number of (milli)seconds spent in a single method.  It is kept very simple to clearly illustrate the functionality of AspectR; a full-featured profiler would need to account for non-serialized and nested method invocations, aggregate the results, etc.

Revision as of 02:35, 1 October 2007

Hold for Robin Yehle Wiki Assignment 1b AspectR is a very useful Ruby module, but it is not easy to find documentation on it that is appropriate for students taking this class. Find, or construct, documentation that explains what it does without presuming previous knowledge of AspectJ, that describes many or all methods of the module and how they work. Also find or produce an easy-to-understand example that does not involve logging.


AspectR Method Documentation

wrap

Arguments: target, pre, post, *args

Adds the advice specified by pre and post to all methods specified in args on the class or object target. To specify more than one method, pass a regular expression to args.

Example:

MyAspect.new.wrap(MyClass, :log_entry, :log_exit, /method/)

In this case, all calls to methods on MyClass with names beginning with "method" will be wrapped by calls to log_entry and log_exit.

unwrap

Arguments: target, pre, post, *args

Removes the advice specified by pre and post from all methods specified in args on the class or object target. To specify more than one method, pass a regular expression to args.

Example:

MyAspect.new.unwrap(MyClass, :log_entry, :log_exit, /method/)

In this case, the advice log_entry and log_exit will no longer be executed when calls to methods on MyClass with names beginning with "method" are made.

wrap_with_code

   def wrap_with_code(target, preCode, postCode, *args)
     prepare(target)
     get_methods(target, args).each do |method_to_wrap|

target.__aop_wrap_with_code(method_to_wrap, preCode, postCode)

     end
   end
   

add_advice

   def add_advice(target, joinpoint, method, advice)
     prepare(target)
     if advice

target.__aop_install_dispatcher(method) target.__aop_add_advice(joinpoint, method, self, advice)

     end
   end
   

remove_advice

   def remove_advice(target, joinpoint, method, advice)
     target.__aop_remove_advice(joinpoint, method, self, advice) if advice
   end



Example: Profiler Aspect

One common use of AOP is profiling. Profiling refers to the collection of data about the dynamic behavior of a system. It is done to determine a breakdown of where time and memory are being consumed at runtime and make optimizations based on the results. In the example below, which is based off a sample found in make a link -- Ruby Developer's Guide, we create an aspect that will determine the number of (milli)seconds spent in a single method. It is kept very simple to clearly illustrate the functionality of AspectR; a full-featured profiler would need to account for non-serialized and nested method invocations, aggregate the results, etc.

The Profiler class, which inherits Aspect, contains two methods: profiler_enter and profiler_exit. The before advice, profiler_enter, records the time immediately before the method is invoked. The after advice, profiler_exit, records the time immediately after the method exits and prints out the duration of the method invocation.

require 'aspectr'
include AspectR
class Profiler < Aspect
   
  def profiler_enter(method, object, exitstatus, *args) 
    @enter_time = Time.now
    puts "#{@enter_time.strftime('%Y-%m-%d %X')} #{self.class}##{method}: #{args.inspect}" 
   end
   
  def profiler_exit(method, object, exitstatus, *args) 
    @exit_time = Time.now
    print "#{@exit_time.strftime('%Y-%m-%d %X')} #{self.class}##{method}: exited " 
    if exitstatus.kind_of?(Array) 
      print "normally returning #{exitstatus[0].inspect} " 
    elsif exitstatus == true 
      print "with exception '#{$!}' " 
    else 
      print "normally " 
    end 
    puts "after #{@exit_time.to_f - @enter_time.to_f} seconds"
  end
end

A user of Profiler would need to wrap all methods that she is interested in profiling. The program below uses the Profiler aspect to calculate the amount of time spent in the SomeClass.method1 method call.

class SomeClass
  def method1(str)
    puts "entering SomeClass.method1 #{str}"
    sleep 5.3
    puts "exiting SomeClass.method1"
  end
end

Profiler.new.wrap(SomeClass, :profiler_enter, :profiler_exit, :method1)
SomeClass.new.method1 "test"

This program generates the following output:

2007-09-30 22:05:51 Profiler#method1: ["test"]
entering SomeClass.method1 test
exiting SomeClass.method1
2007-09-30 22:05:56 Profiler#method1: exited normally returning nil after 5.29699993133545 seconds

You can see from the Profiler output that SomeClass.method1 took approximately 5.3 seconds to execute, as expected.