Module: Aspekt::Weaver
Overview
Responsible for weaving code into methods.
You can use Weaver so:
… in method call to Aspekt::Weaver
Aspekt::Weaver.before class: ExistingClass, method: :existing_method do |joinpoint|
puts "before context: '#{joinpoint[:context]}' and method '#{joinpoint[:method]}'"
end
… in where you want to (for example class definition body).
include Aspekt::Weaver
# for object derived from this class:
before method: :my_method |joinpoint| # if :type(s)|:method(s) is missing, then automatically type will be self.
puts "before #{joinpoint[:method]}"
end
before type: self, method: :my_method do |joinpoint| # remember that self in class body will be Class
puts "before #{joinpoint[:method]}"
end
# singleton
before instance: self, method: :my_method do |joinpoint| # remember that self in class body will be Class and its treated as instance now
puts "before #{joinpoint[:method]}"
end
before type: (class<<self; self; end), method: :my_method do |joinpoint| # accessing self metaclass
puts "before #{joinpoint[:method]}"
end
More complicated examples:
Aspekt::Weaver.before instances: [Object1, :ClassHereForSingletonMethods], types: [Class1, :Class2], methods: [:method1, 'method2', /d3/] do |joinpoint|
puts "Called in the context of a object: #{joinpoint[:context]} and method is: #{joinpoint[:method]}"
end
Aspekt::Weaver.before types: //, methods: /secure/ do |joinpoint|
throw SecurityException, "not secure enough" unless authenticated_user.is_secured?
end
More examples can be found in Rspec tests: github.com/tione/aspekt/blob/development/spec/aspekt/weaver_spec.rb
Weaver does not support Regexp in its object and method matching
Therefore its recommended to use Aspects, Advices and Pointcuts that do support Regexp.
Class Method Summary collapse
-
.included(base) ⇒ Object
When included to a Class or Object, there will be Weaver methods available.
Instance Method Summary collapse
-
#after(opts, &block) ⇒ Object
Weaves Proc after the method.
-
#around(opts, &block) ⇒ Object
Wheaves Proc for around.
-
#before(opts, &block) ⇒ Object
Weaves Proc before the method.
-
#weave(*pointcuts_or_matchers) ⇒ Object
Weaves Proc to method.
Class Method Details
.included(base) ⇒ Object
When included to a Class or Object, there will be Weaver methods available.
60 61 62 |
# File 'lib/aspekt/weaver.rb', line 60 def self.included base #:nodoc: base.extend self end |
Instance Method Details
#after(opts, &block) ⇒ Object
Weaves Proc after the method.
151 152 153 154 155 156 157 158 |
# File 'lib/aspekt/weaver.rb', line 151 def after opts, &block self.weave opts do |joinpoint| retval = joinpoint.proceed # call orginal method joinpoint.merge! retval: retval # add orginal method retval joinpoint[:context].instance_exec joinpoint, &block # call block with argument joinpoint retval end end |
#around(opts, &block) ⇒ Object
Wheaves Proc for around.
Example usage
hash = {key: :value}
puts "Hash ID is: #{hash.object_id}"
Aspekt::Weaver.around object: hash, method: :has_key? do |joinpoint|
puts "Enter: #{joinpoint}"
puts "My self ID is: through self #{self.object_id} and through joinpoint[:context] #{joinpoint[:context].object_id}"
result = joinpoint.proceed
puts "Exit with result #{result}: #{joinpoint}"
end
# Calling `hash.has_key?(:key)` outputs:
# Hash ID is: 15441680
# Enter: {:args=>[:key], :block=>nil, :context=>{:key=>:value}, :method=>:has_key?, :bound_method=>#<Method: Hash(Hash)#has_key?>}
# My self ID is: through self 15441680 and through joinpoint[:context] 15441680
# Exit with result true: {:args=>[:key], :block=>nil, :context=>{:key=>:value}, :method=>:has_key?, :bound_method=>#<Method: Hash(Hash)#has_key?>}
181 182 183 184 185 186 |
# File 'lib/aspekt/weaver.rb', line 181 def around opts, &block self.weave opts do |joinpoint| joinpoint[:context].instance_exec joinpoint, &block # call block with argument joinpoint # calling joinpoint.proceed should be done in the block end end |
#before(opts, &block) ⇒ Object
Weaves Proc before the method.
Example usage for object
string = "trolololo"
Aspekt::Weaver.before object: string, method: :to_s do |joinpoint|
puts "Before self: #{self} joinpoint: #{joinpoint}"
end
new_string = string.to_s # output: Before trolololo at {:args=>[], :block=>nil, :context=>"trolololo", :method=>:to_s, :bound_method=>#<Method: String(String)#to_s>}
puts new_string # output: "trolololo"
Example usage for all objects that derive from certain classes
Aspekt::Weaver.before classes: [Array, String], methods: [:initialize, :to_s] do
puts "#{self} is doing something important #{joinpoint}"
end
140 141 142 143 144 145 |
# File 'lib/aspekt/weaver.rb', line 140 def before opts, &block self.weave opts do |joinpoint| joinpoint[:context].instance_exec joinpoint, &block # call block with argument joinpoint joinpoint.proceed # call orginal method end end |
#weave(*pointcuts_or_matchers) ⇒ Object
Weaves Proc to method.
If argument matcher is a Hash not a Aspekt::Pointcut, it will be converted to it.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/aspekt/weaver.rb', line 71 def weave *pointcuts_or_matchers # if not pointcut, convert to it. (it might be a regexp matcher?) pointcuts = pointcuts_or_matchers.flatten.collect do |pom| case pom when Aspekt::Pointcut pom when Hash # Add DSL support for if include Aspekt::Weaver was called in a class. pom[:type] = self if !(pom[:type] or pom[:types] or pom[:instance] or pom[:instances]) and self != Aspekt::Weaver Aspekt::Pointcut.new pom else raise ArgumentError, "should be Hash or Aspekt::Pointcut but was #{pom.class} (#{pom})" end end # iterate over pointcuts pointcuts.each do |pointcut| # objects to be weaved into matching = pointcut.matching objects = matching[:types] || {} matching[:instances].each do |instance, methods| singleton = class<<instance; self; end objects[singleton] ||= [] objects[singleton].concat methods end if matching[:instances] # iterate through objects (classes and singleton classes) objects.each do |object, method_matchers| object.module_exec do weave_methods = object.instance_methods.select {|meth| method_matchers.include_same? meth } weave_methods.each do |weave_method| m = instance_method(weave_method) # replace orginal method with orginal method + what we got as block to yield define_method(weave_method) do |*args, &block| bm = m.bind self joinpoint = Aspekt::Joinpoint.new args: args, block: block, context: self, method: weave_method, bound_method: bm yield(joinpoint) end end end end end end |