Class Aquarium::Aspects::JoinPoint
In: lib/aquarium/aspects/join_point.rb
Parent: Object

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!

Methods

Classes and Modules

Class Aquarium::Aspects::JoinPoint::Context
Class Aquarium::Aspects::JoinPoint::ContextNotCorrectlyDefined
Class Aquarium::Aspects::JoinPoint::ProceedMethodNotAvailable

Constants

NIL_OBJECT = Aquarium::Utils::NilObject.new   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

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.

[Source]

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

Public Instance methods

We require the same object id, not just equal objects.

[Source]

     # File lib/aquarium/aspects/join_point.rb, line 170
170:       def <=> other
171:         return 0  if object_id == other.object_id 
172:         return 1  if other.nil?
173:         result = self.class <=> other.class
174:         return result unless result == 0
175:         result = compare_field(:target_object, other) {|f1,f2| f1.object_id <=> f2.object_id}
176:         return result unless result == 0
177:         result = compare_field(:instance_method, other) {|f1,f2| boolean_compare(f1,f2)}
178:         return result unless result == 0
179:         [:target_type, :method_name, :context].each do |field|
180:           result = compare_field field, other
181:           return result unless result == 0
182:         end
183:         0
184:       end
==(other)

Alias for eql?

===(other)

Alias for eql?

[Source]

    # File lib/aquarium/aspects/join_point.rb, line 94
94:       def class_method?
95:         !@instance_method
96:       end

[Source]

     # File lib/aquarium/aspects/join_point.rb, line 127
127:       def dup
128:         jp = super
129:         jp.context = @context.dup unless @context.nil?
130:         jp
131:       end

[Source]

     # File lib/aquarium/aspects/join_point.rb, line 186
186:       def eql? other
187:         return (self <=> other) == 0
188:       end

[Source]

     # File lib/aquarium/aspects/join_point.rb, line 139
139:       def exists?
140:         type_or_object_sym = @target_type ? :type : :object
141:         results = Aquarium::Finders::MethodFinder.new.find type_or_object_sym => type_or_object, 
142:                             :method => method_name, 
143:                             :method_options => [visibility, instance_or_class_method]
144:         raise Aquarium::Utils::LogicError("MethodFinder returned more than one item! #{results.inspect}") if (results.matched.size + results.not_matched.size) != 1
145:         return results.matched.size == 1 ? true : false
146:       end

[Source]

     # File lib/aquarium/aspects/join_point.rb, line 193
193:       def inspect
194:         "JoinPoint: {target_type = #{target_type.inspect}, target_object = #{target_object.inspect}, method_name = #{method_name}, instance_method? #{instance_method?}, context = #{context.inspect}}"
195:       end

[Source]

     # File lib/aquarium/aspects/join_point.rb, line 165
165:       def instance_method
166:         @instance_method
167:       end

[Source]

    # File lib/aquarium/aspects/join_point.rb, line 90
90:       def instance_method?
91:         @instance_method
92:       end

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!

[Source]

     # File lib/aquarium/aspects/join_point.rb, line 160
160:       def invoke_original_join_point *args, &block
161:         raise ContextNotCorrectlyDefined.new(":invoke_original_join_point can't be called unless the join point has a context object.") if context.nil?
162:         context.invoke_original_join_point self, *args, &block
163:       end

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".

[Source]

     # File lib/aquarium/aspects/join_point.rb, line 151
151:       def proceed *args, &block
152:         raise ContextNotCorrectlyDefined.new(":proceed can't be called unless the join point has a context object.") if context.nil?
153:         context.proceed self, *args, &block
154:       end
target_type_or_object()

Alias for type_or_object

to_s()

Alias for inspect

[Source]

     # File lib/aquarium/aspects/join_point.rb, line 133
133:       def type_or_object
134:         target_type || target_object
135:       end

Protected Instance methods

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

[Source]

     # File lib/aquarium/aspects/join_point.rb, line 232
232:       def assert_valid options, error_message = ""
233:         error_message << "Must specify a :method_name. "            unless method_name
234:         error_message << "Must specify either a :type or :object. " unless (target_type or  target_object)
235:         error_message << "Can't specify both a :type or :object. "  if     (target_type and target_object)
236:         bad_attributes(error_message, options) if error_message.length > 0
237:       end

[Source]

     # File lib/aquarium/aspects/join_point.rb, line 213
213:       def boolean_compare b1, b2
214:         return 0 if b1 == b2
215:         return b1 == true ? 1 : -1
216:       end

[Source]

     # File lib/aquarium/aspects/join_point.rb, line 239
239:       def class_or_instance_method_flag
240:         "#{instance_or_class_method.to_s}_method_only".intern
241:       end

[Source]

     # File lib/aquarium/aspects/join_point.rb, line 202
202:       def compare_field field_reader, other
203:         field1 = self.method(field_reader).call
204:         field2 = other.method(field_reader).call
205:         if field1.nil? 
206:           return field2.nil? ? 0 : -1
207:         else
208:           return 1 if field2.nil?
209:         end
210:         block_given? ? (yield field1, field2) : (field1 <=> field2)
211:       end

[Source]

     # File lib/aquarium/aspects/join_point.rb, line 218
218:       def resolve_type options
219:         type = options[:type]
220:         return type if type.nil?  # okay, if they specified an object!
221:         return type if type.kind_of? Module
222:         found = Aquarium::Finders::TypeFinder.new.find :type => type
223:         if found.matched.empty?
224:           bad_attributes("No type matched the string or regular expression: #{type.inspect}", options)
225:         elsif found.matched.size > 1
226:           bad_attributes("More than one type matched the string or regular expression: #{type.inspect}", options)
227:         end
228:         found.matched.keys.first
229:       end

[Validate]