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
: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
# 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