class Aquarium::Aspects::JoinPoint

JoinPoint

Encapsulates information about a Join Point that might be advised. JoinPoint objects are almost value objects; you can change the context object. TODO Separate out the read-only part from the variable part. This might require an API change!

Constants

NIL_OBJECT

A “convenience” JoinPoint supporting the “Null Object Pattern.”

Attributes

context[RW]
instance_or_class_method[R]
method_name[R]
target_object[R]
target_type[R]
visibility[R]

Public Class Methods

new(options = {}) click to toggle source

Create a join point object, specifying either one type or one object and a method. Only method join points are currently supported by Aquarium.

The supported options are

:type => type | type_name | type_name_regexp

A single type, type name or regular expression matching only one type. One and only one type or object is required. An error is raised otherwise.

:object => object

A single object. One and only one type or object is required. An error is raised otherwise.

:method_name | :method => method_name_or_symbol

A single method name or symbol. Only one is allowed, although the special flag :all is allowed, as long as only one method will be found, subject to the next option.

:class_method | :instance_method => true | false

Is the method a class or instance method? Defaults to :instance_method => true.

Note: The range of options is not as rich as for Pointcut, because it is expected that JoinPoint objects will be explicitly created only rarely by users of Aquarium. Most of the time, Pointcuts will be created.

    # File lib/aquarium/aspects/join_point.rb
120 def initialize options = {}
121   @target_type     = resolve_type options
122   @target_object   = options[:object]
123   @method_name     = options[:method_name] || options[:method]
124   class_method     = options[:class_method].nil? ? false : options[:class_method]
125   @instance_method = options[:instance_method].nil? ? (!class_method) : options[:instance_method]
126   @instance_or_class_method  = @instance_method ? :instance : :class
127   @visibility = Aquarium::Utils::MethodUtils.visibility(type_or_object, @method_name, class_or_instance_method_flag)
128   @context = options[:context] || JoinPoint::Context.new
129   assert_valid options
130 end

Public Instance Methods

<=>(other) click to toggle source
    # File lib/aquarium/aspects/join_point.rb
174 def <=> other
175   return 0  if object_id == other.object_id 
176   return 1  if other.nil?
177   result = self.class <=> other.class
178   return result unless result == 0
179   result = compare_field(:target_object, other) {|f1,f2| f1.object_id <=> f2.object_id}
180   return result unless result == 0
181   result = compare_field(:instance_method, other) {|f1,f2| boolean_compare(f1,f2)}
182   return result unless result == 0
183   [:target_type, :method_name, :context].each do |field|
184     result = compare_field field, other
185     return result unless result == 0
186   end
187   0
188 end
==(other)
Alias for: eql?
===(other)
Alias for: eql?
class_method?() click to toggle source
    # File lib/aquarium/aspects/join_point.rb
 99 def class_method?
100   !@instance_method
101 end
dup() click to toggle source
Calls superclass method
    # File lib/aquarium/aspects/join_point.rb
132 def dup
133   jp = super
134   jp.context = @context.dup unless @context.nil?
135   jp
136 end
eql?(other) click to toggle source
    # File lib/aquarium/aspects/join_point.rb
190 def eql? other
191   return (self <=> other) == 0
192 end
Also aliased as: ==, ===
exists?() click to toggle source
    # File lib/aquarium/aspects/join_point.rb
144 def exists?
145   type_or_object_sym = @target_type ? :type : :object
146   results = Aquarium::Finders::MethodFinder.new.find type_or_object_sym => type_or_object, 
147                       :method => method_name, 
148                       :method_options => [visibility, instance_or_class_method]
149   raise Aquarium::Utils::LogicError("MethodFinder returned more than one item! #{results.inspect}") if (results.matched.size + results.not_matched.size) != 1
150   return results.matched.size == 1 ? true : false
151 end
inspect() click to toggle source

todo: restore context output.

    # File lib/aquarium/aspects/join_point.rb
198 def inspect
199   "JoinPoint: {target_type = #{target_type.nil? ? target_type : target_type.name}, target_object = #{target_object.inspect}, method_name = #{method_name}, instance_method? #{instance_method?}, context = #{context.inspect}"
200 end
Also aliased as: to_s
instance_method() click to toggle source
    # File lib/aquarium/aspects/join_point.rb
170 def instance_method
171   @instance_method
172 end
instance_method?() click to toggle source
   # File lib/aquarium/aspects/join_point.rb
95 def instance_method?
96   @instance_method
97 end
invoke_original_join_point(*args, &block) click to toggle source

Invoke the join point itself, skipping any intermediate advice. This method can only be called if the join point has a context object defined that represents an actual runtime “state”. Use this method cautiously, at it could be “surprising” if some advice is not executed!

    # File lib/aquarium/aspects/join_point.rb
165 def invoke_original_join_point *args, &block
166   raise ContextNotCorrectlyDefined.new(":invoke_original_join_point can't be called unless the join point has a context object.") if context.nil?
167   context.invoke_original_join_point self, *args, &block
168 end
proceed(*args, &block) click to toggle source

Invoke the join point itself (which could actually be aspect advice wrapping the original join point…). This method can only be called if the join point has a context object defined that represents an actual runtime “state”.

    # File lib/aquarium/aspects/join_point.rb
156 def proceed *args, &block
157   raise ContextNotCorrectlyDefined.new(":proceed can't be called unless the join point has a context object.") if context.nil?
158   context.proceed self, *args, &block
159 end
target_type_or_object()
Alias for: type_or_object
to_s()
Alias for: inspect
type_or_object() click to toggle source
    # File lib/aquarium/aspects/join_point.rb
138 def type_or_object
139   target_type || target_object
140 end
Also aliased as: target_type_or_object

Protected Instance Methods

assert_valid(options, error_message = "") click to toggle source

Since JoinPoints can be declared for non-existent methods, tolerate “nil” for the visibility.

    # File lib/aquarium/aspects/join_point.rb
242 def assert_valid options, error_message = ""
243   error_message << "Must specify a :method_name. "            unless method_name
244   error_message << "Must specify either a :type or :object. " unless (target_type or  target_object)
245   error_message << "Can't specify both a :type or :object. "  if     (target_type and target_object)
246   bad_attributes(error_message, options) if error_message.length > 0
247 end
boolean_compare(b1, b2) click to toggle source
    # File lib/aquarium/aspects/join_point.rb
223 def boolean_compare b1, b2
224   return 0 if b1 == b2
225   return b1 == true ? 1 : -1
226 end
class_or_instance_method_flag() click to toggle source
    # File lib/aquarium/aspects/join_point.rb
249 def class_or_instance_method_flag
250   "#{instance_or_class_method.to_s}_method_only".intern
251 end
compare_field(field_reader, other) { |field1, field2| ... } click to toggle source
    # File lib/aquarium/aspects/join_point.rb
206 def compare_field field_reader, other
207   field1 = self.method(field_reader).call
208   field2 = other.method(field_reader).call
209   if field1.nil? 
210     return field2.nil? ? 0 : -1
211   else
212     return 1 if field2.nil?
213   end
214   if block_given?
215     yield field1, field2
216   elsif field1.respond_to?(:<=>)
217     field1 <=> field2
218   else
219     field1.to_s <=> field2.to_s
220   end
221 end
resolve_type(options) click to toggle source
    # File lib/aquarium/aspects/join_point.rb
228 def resolve_type options
229   type = options[:type]
230   return type if type.nil?  # okay, if they specified an object!
231   return type if type.kind_of? Module
232   found = Aquarium::Finders::TypeFinder.new.find :type => type
233   if found.matched.empty?
234     bad_attributes("No type matched the string or regular expression: #{type.inspect}", options)
235   elsif found.matched.size > 1
236     bad_attributes("More than one type matched the string or regular expression: #{type.inspect}", options)
237   end
238   found.matched.keys.first
239 end