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, line 120
def initialize options = {}
  @target_type     = resolve_type options
  @target_object   = options[:object]
  @method_name     = options[:method_name] || options[:method]
  class_method     = options[:class_method].nil? ? false : options[:class_method]
  @instance_method = options[:instance_method].nil? ? (!class_method) : options[:instance_method]
  @instance_or_class_method  = @instance_method ? :instance : :class
  @visibility = Aquarium::Utils::MethodUtils.visibility(type_or_object, @method_name, class_or_instance_method_flag)
  @context = options[:context] || JoinPoint::Context.new
  assert_valid options
end

Public Instance Methods

<=>(other) click to toggle source
# File lib/aquarium/aspects/join_point.rb, line 174
def <=> other
  return 0  if object_id == other.object_id 
  return 1  if other.nil?
  result = self.class <=> other.class
  return result unless result == 0
  result = compare_field(:target_object, other) {|f1,f2| f1.object_id <=> f2.object_id}
  return result unless result == 0
  result = compare_field(:instance_method, other) {|f1,f2| boolean_compare(f1,f2)}
  return result unless result == 0
  [:target_type, :method_name, :context].each do |field|
    result = compare_field field, other
    return result unless result == 0
  end
  0
end
==(other) click to toggle source
Alias for: eql?
===(other) click to toggle source
Alias for: eql?
class_method?() click to toggle source
# File lib/aquarium/aspects/join_point.rb, line 99
def class_method?
  !@instance_method
end
dup() click to toggle source
# File lib/aquarium/aspects/join_point.rb, line 132
def dup
  jp = super
  jp.context = @context.dup unless @context.nil?
  jp
end
eql?(other) click to toggle source
# File lib/aquarium/aspects/join_point.rb, line 190
def eql? other
  return (self <=> other) == 0
end
Also aliased as: ==, ===
exists?() click to toggle source
# File lib/aquarium/aspects/join_point.rb, line 144
def exists?
  type_or_object_sym = @target_type ? :type : :object
  results = Aquarium::Finders::MethodFinder.new.find type_or_object_sym => type_or_object, 
                      :method => method_name, 
                      :method_options => [visibility, instance_or_class_method]
  raise Aquarium::Utils::LogicError("MethodFinder returned more than one item! #{results.inspect}") if (results.matched.size + results.not_matched.size) != 1
  return results.matched.size == 1 ? true : false
end
inspect() click to toggle source

todo: restore context output.

# File lib/aquarium/aspects/join_point.rb, line 198
def inspect
  "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}"
end
Also aliased as: to_s
instance_method() click to toggle source
# File lib/aquarium/aspects/join_point.rb, line 170
def instance_method
  @instance_method
end
instance_method?() click to toggle source
# File lib/aquarium/aspects/join_point.rb, line 95
def instance_method?
  @instance_method
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, line 165
def invoke_original_join_point *args, &block
  raise ContextNotCorrectlyDefined.new(":invoke_original_join_point can't be called unless the join point has a context object.") if context.nil?
  context.invoke_original_join_point self, *args, &block
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, line 156
def proceed *args, &block
  raise ContextNotCorrectlyDefined.new(":proceed can't be called unless the join point has a context object.") if context.nil?
  context.proceed self, *args, &block
end
target_type_or_object() click to toggle source
Alias for: type_or_object
to_s() click to toggle source
Alias for: inspect
type_or_object() click to toggle source
# File lib/aquarium/aspects/join_point.rb, line 138
def type_or_object
  target_type || target_object
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, line 242
def assert_valid options, error_message = ""
  error_message << "Must specify a :method_name. "            unless method_name
  error_message << "Must specify either a :type or :object. " unless (target_type or  target_object)
  error_message << "Can't specify both a :type or :object. "  if     (target_type and target_object)
  bad_attributes(error_message, options) if error_message.length > 0
end
boolean_compare(b1, b2) click to toggle source
# File lib/aquarium/aspects/join_point.rb, line 223
def boolean_compare b1, b2
  return 0 if b1 == b2
  return b1 == true ? 1 : -1
end
class_or_instance_method_flag() click to toggle source
# File lib/aquarium/aspects/join_point.rb, line 249
def class_or_instance_method_flag
  "#{instance_or_class_method.to_s}_method_only".intern
end
compare_field(field_reader, other) { |field1, field2| ... } click to toggle source
# File lib/aquarium/aspects/join_point.rb, line 206
def compare_field field_reader, other
  field1 = self.method(field_reader).call
  field2 = other.method(field_reader).call
  if field1.nil? 
    return field2.nil? ? 0 : -1
  else
    return 1 if field2.nil?
  end
  if block_given?
    yield field1, field2
  elsif field1.respond_to?(:<=>)
    field1 <=> field2
  else
    field1.to_s <=> field2.to_s
  end
end
resolve_type(options) click to toggle source
# File lib/aquarium/aspects/join_point.rb, line 228
def resolve_type options
  type = options[:type]
  return type if type.nil?  # okay, if they specified an object!
  return type if type.kind_of? Module
  found = Aquarium::Finders::TypeFinder.new.find :type => type
  if found.matched.empty?
    bad_attributes("No type matched the string or regular expression: #{type.inspect}", options)
  elsif found.matched.size > 1
    bad_attributes("More than one type matched the string or regular expression: #{type.inspect}", options)
  end
  found.matched.keys.first
end