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
Attributes
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
:allis 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
# 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
# File lib/aquarium/aspects/join_point.rb 99 def class_method? 100 !@instance_method 101 end
# 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
# File lib/aquarium/aspects/join_point.rb 190 def eql? other 191 return (self <=> other) == 0 192 end
# 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
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
# File lib/aquarium/aspects/join_point.rb 170 def instance_method 171 @instance_method 172 end
# File lib/aquarium/aspects/join_point.rb 95 def instance_method? 96 @instance_method 97 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!
# 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
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
# File lib/aquarium/aspects/join_point.rb 138 def type_or_object 139 target_type || target_object 140 end
Protected Instance Methods
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
# 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
# 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
# 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
# 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