aquarium 0.1.0 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. data/CHANGES +53 -0
  2. data/README +20 -4
  3. data/Rakefile +19 -4
  4. data/UPGRADE +41 -1
  5. data/examples/aspect_design_example.rb +4 -1
  6. data/examples/aspect_design_example_spec.rb +41 -0
  7. data/examples/design_by_contract_example.rb +2 -3
  8. data/examples/design_by_contract_example_spec.rb +92 -0
  9. data/examples/method_missing_example.rb +1 -1
  10. data/examples/method_missing_example_spec.rb +59 -0
  11. data/examples/method_tracing_example.rb +4 -2
  12. data/examples/method_tracing_example_spec.rb +141 -0
  13. data/lib/aquarium/aspects/advice.rb +2 -2
  14. data/lib/aquarium/aspects/aspect.rb +20 -35
  15. data/lib/aquarium/aspects/dsl.rb +2 -1
  16. data/lib/aquarium/aspects/dsl/aspect_dsl.rb +12 -8
  17. data/lib/aquarium/aspects/dsl/object_dsl.rb +8 -0
  18. data/lib/aquarium/aspects/join_point.rb +16 -10
  19. data/lib/aquarium/aspects/pointcut.rb +3 -3
  20. data/lib/aquarium/extras/design_by_contract.rb +20 -11
  21. data/lib/aquarium/utils.rb +1 -0
  22. data/lib/aquarium/utils/method_utils.rb +41 -0
  23. data/lib/aquarium/utils/name_utils.rb +35 -0
  24. data/lib/aquarium/utils/type_utils.rb +9 -0
  25. data/lib/aquarium/version.rb +3 -5
  26. data/rake_tasks/examples.rake +1 -1
  27. data/spec/aquarium/aspects/aspect_invocation_spec.rb +30 -28
  28. data/spec/aquarium/aspects/aspect_spec.rb +90 -0
  29. data/spec/aquarium/aspects/concurrent_aspects_spec.rb +5 -3
  30. data/spec/aquarium/aspects/concurrent_aspects_with_objects_and_types_spec.rb +3 -1
  31. data/spec/aquarium/aspects/dsl/aspect_dsl_spec.rb +174 -110
  32. data/spec/aquarium/aspects/join_point_spec.rb +120 -19
  33. data/spec/aquarium/aspects/pointcut_spec.rb +24 -14
  34. data/spec/aquarium/extras/design_by_contract_spec.rb +3 -0
  35. data/spec/aquarium/finders/finder_result_spec.rb +1 -1
  36. data/spec/aquarium/finders/method_finder_spec.rb +3 -4
  37. data/spec/aquarium/spec_example_classes.rb +4 -0
  38. data/spec/aquarium/utils/method_utils_spec.rb +124 -1
  39. data/spec/aquarium/utils/name_utils_spec.rb +56 -0
  40. data/spec/aquarium/utils/type_utils_spec.rb +17 -0
  41. metadata +12 -4
  42. data/spec/aquarium/finders/method_sorting_spec.rb +0 -16
@@ -36,7 +36,9 @@ foo1.do_it :b1, :b2
36
36
  bar1 = Aquarium::Bar.new :a3, :a4
37
37
  bar1.do_something_else :b3, :b4
38
38
 
39
- around :types => [Aquarium::Foo, Aquarium::Bar], :methods => :all, :method_options => :suppress_ancestor_methods do |execution_point, *args|
39
+ include Aquarium::Aspects
40
+
41
+ Aspect.new :around, :types => [Aquarium::Foo, Aquarium::Bar], :methods => :all, :method_options => :suppress_ancestor_methods do |execution_point, *args|
40
42
  p "Entering: #{execution_point.type.name}##{execution_point.method_name}: args = #{args.inspect}"
41
43
  execution_point.proceed
42
44
  p "Leaving: #{execution_point.type.name}##{execution_point.method_name}: args = #{args.inspect}"
@@ -49,7 +51,7 @@ foo2.do_it :b5, :b6
49
51
  bar1 = Aquarium::Bar.new :a7, :a8
50
52
  bar1.do_something_else :b7, :b8
51
53
 
52
- around :types => [Aquarium::Foo, Aquarium::Bar], :methods => :initialize, :method_options => :private do |execution_point, *args|
54
+ Aspect.new :around, :types => [Aquarium::Foo, Aquarium::Bar], :methods => :initialize, :method_options => :private do |execution_point, *args|
53
55
  p "Entering: #{execution_point.type.name}##{execution_point.method_name}: args = #{args.inspect}"
54
56
  execution_point.proceed
55
57
  p "Leaving: #{execution_point.type.name}##{execution_point.method_name}: args = #{args.inspect}"
@@ -0,0 +1,141 @@
1
+ require File.dirname(__FILE__) + '/../spec/aquarium/spec_helper.rb'
2
+ require 'aquarium'
3
+
4
+ # Example demonstrating "around" advice that traces calls to all methods in
5
+ # classes Foo and Bar
6
+
7
+ module Aquarium
8
+ module LogModule
9
+ def log message
10
+ @log ||= []
11
+ @log << message
12
+ end
13
+ def logged_messages
14
+ @log
15
+ end
16
+ end
17
+
18
+ class Foo
19
+ include LogModule
20
+ def initialize *args
21
+ log "Inside: Aquarium::Foo#initialize: args = #{args.inspect}"
22
+ end
23
+ def do_it *args
24
+ log "Inside: Aquarium::Foo#do_it: args = #{args.inspect}"
25
+ end
26
+ end
27
+
28
+ module BarModule
29
+ include LogModule
30
+ def initialize *args
31
+ log "Inside: Aquarium::BarModule#initialize: args = #{args.inspect}"
32
+ end
33
+ def do_something_else *args
34
+ log "Inside: Aquarium::BarModule#do_something_else: args = #{args.inspect}"
35
+ end
36
+ end
37
+
38
+ class Bar
39
+ include BarModule
40
+ end
41
+ end
42
+
43
+ describe "An example without advice" do
44
+ it "should not trace any method calls." do
45
+ foo = Aquarium::Foo.new :a1, :a2
46
+ foo.do_it :b1, :b2
47
+ bar = Aquarium::Bar.new :a3, :a4
48
+ bar.do_something_else :b3, :b4
49
+
50
+ foo.logged_messages.size.should == 2
51
+ bar.logged_messages.size.should == 2
52
+ end
53
+ end
54
+
55
+ describe "An example with advice on the public instance methods (excluding ancestor methods) of Foo" do
56
+ it "should trace all calls to the public methods defined by Foo" do
57
+ aspect = Aquarium::Aspects::Aspect.new :around, :type => Aquarium::Foo, :methods => :all, :method_options => :suppress_ancestor_methods do |execution_point, *args|
58
+ o = execution_point.context.advised_object
59
+ o.log "Entering: #{execution_point.type.name}##{execution_point.method_name}: args = #{args.inspect}"
60
+ execution_point.proceed
61
+ o.log "Leaving: #{execution_point.type.name}##{execution_point.method_name}: args = #{args.inspect}"
62
+ end
63
+
64
+ foo = Aquarium::Foo.new :a5, :a6
65
+ foo.do_it :b5, :b6
66
+ foo.logged_messages.size.should == 4
67
+ foo.logged_messages[0].should include("Inside: Aquarium::Foo#initialize")
68
+ foo.logged_messages[1].should include("Entering")
69
+ foo.logged_messages[2].should include("Inside: Aquarium::Foo#do_it")
70
+ foo.logged_messages[3].should include("Leaving")
71
+ aspect.unadvise
72
+ end
73
+ end
74
+
75
+ describe "An example with advice on the public instance methods (excluding ancestor methods) of Bar" do
76
+ it "should not trace any calls to the public methods defined by the included BarModule" do
77
+ aspect = Aquarium::Aspects::Aspect.new :around, :type => Aquarium::Bar, :methods => :all, :method_options => :suppress_ancestor_methods do |execution_point, *args|
78
+ o = execution_point.context.advised_object
79
+ o.log "Entering: #{execution_point.type.name}##{execution_point.method_name}: args = #{args.inspect}"
80
+ execution_point.proceed
81
+ o.log "Leaving: #{execution_point.type.name}##{execution_point.method_name}: args = #{args.inspect}"
82
+ end
83
+
84
+ bar = Aquarium::Bar.new :a7, :a8
85
+ bar.do_something_else :b7, :b8
86
+ bar.logged_messages.size.should == 2
87
+ aspect.unadvise
88
+ end
89
+ end
90
+
91
+ describe "An example with advice on the public instance methods (including ancestor methods) of Bar" do
92
+ it "should trace all calls to the public methods defined by the included BarModule" do
93
+ aspect = Aquarium::Aspects::Aspect.new :around, :type => Aquarium::Bar, :methods => /^do_/ do |execution_point, *args|
94
+ o = execution_point.context.advised_object
95
+ o.log "Entering: #{execution_point.type.name}##{execution_point.method_name}: args = #{args.inspect}"
96
+ execution_point.proceed
97
+ o.log "Leaving: #{execution_point.type.name}##{execution_point.method_name}: args = #{args.inspect}"
98
+ end
99
+
100
+ bar = Aquarium::Bar.new :a9, :a10
101
+ bar.do_something_else :b9, :b10
102
+ bar.logged_messages.size.should == 4
103
+ bar.logged_messages[0].should include("Inside: Aquarium::BarModule#initialize")
104
+ bar.logged_messages[1].should include("Entering: Aquarium::Bar#do_something_else")
105
+ bar.logged_messages[2].should include("Inside: Aquarium::BarModule#do_something_else")
106
+ bar.logged_messages[3].should include("Leaving: Aquarium::Bar#do_something_else")
107
+ aspect.unadvise
108
+ end
109
+ end
110
+
111
+
112
+ describe "An example with advice on the private initialize method of Foo and Bar" do
113
+ it "should trace all calls to initialize" do
114
+ before_methods = Aquarium::Foo.private_instance_methods.sort #- Object.private_methods.sort
115
+ aspect = Aquarium::Aspects::Aspect.new :around, :types => [Aquarium::Foo, Aquarium::Bar], :methods => :initialize, :method_options => :private do |execution_point, *args|
116
+ o = execution_point.context.advised_object
117
+ o.log "Entering: #{execution_point.type.name}##{execution_point.method_name}: args = #{args.inspect}"
118
+ execution_point.proceed
119
+ o.log "Leaving: #{execution_point.type.name}##{execution_point.method_name}: args = #{args.inspect}"
120
+ end
121
+
122
+ foo = Aquarium::Foo.new :a11, :a12
123
+ foo.do_it :b11, :b12
124
+ foo.logged_messages.size.should == 4
125
+ foo.logged_messages[0].should include("Entering: Aquarium::Foo#initialize")
126
+ foo.logged_messages[1].should include("Inside: Aquarium::Foo#initialize")
127
+ foo.logged_messages[2].should include("Leaving: Aquarium::Foo#initialize")
128
+ foo.logged_messages[3].should include("Inside: Aquarium::Foo#do_it")
129
+
130
+ bar = Aquarium::Bar.new :a13, :a14
131
+ bar.do_something_else :b13, :b14
132
+ bar.logged_messages.size.should == 4
133
+ bar.logged_messages[0].should include("Entering: Aquarium::Bar#initialize")
134
+ bar.logged_messages[1].should include("Inside: Aquarium::BarModule#initialize")
135
+ bar.logged_messages[2].should include("Leaving: Aquarium::Bar#initialize")
136
+ bar.logged_messages[3].should include("Inside: Aquarium::BarModule#do_something_else")
137
+ aspect.unadvise
138
+ after_methods = Aquarium::Foo.private_instance_methods.sort #- Object.private_methods.sort
139
+ (before_methods - after_methods).should == []
140
+ end
141
+ end
@@ -41,7 +41,7 @@ module Aquarium
41
41
  begin
42
42
  @proc.call jp, *args
43
43
  rescue => e
44
- class_or_instance_method_separater = jp.is_instance_method? ? "#" : "."
44
+ class_or_instance_method_separater = jp.instance_method? ? "#" : "."
45
45
  context_message = "Exception raised while executing \"#{jp.context.advice_kind}\" advice for \"#{jp.type_or_object.inspect}#{class_or_instance_method_separater}#{jp.method_name}\": "
46
46
  backtrace = e.backtrace
47
47
  e2 = e.exception(context_message + e.message)
@@ -80,7 +80,7 @@ module Aquarium
80
80
  def initialize options = {}
81
81
  super(options) { |jp, *args|
82
82
  block_for_method = jp.context.block_for_method
83
- invoking_object = jp.is_instance_method? ? jp.context.advised_object : jp.type
83
+ invoking_object = jp.instance_method? ? jp.context.advised_object : jp.type
84
84
  method = invoking_object.method(@alias_method_name)
85
85
  block_for_method.nil? ?
86
86
  method.call(*args) :
@@ -109,7 +109,7 @@ module Aquarium
109
109
  # <tt>:writers</tt>, and/or <tt>:writer</tt> (synonymous). By default, both
110
110
  # readers and writers are matched.
111
111
  def initialize *options, &block
112
- process_input *options, &block
112
+ process_input options, &block
113
113
  init_pointcuts
114
114
  return if specification[:noop]
115
115
  advise_join_points
@@ -151,16 +151,16 @@ module Aquarium
151
151
 
152
152
  protected
153
153
 
154
- def process_input *options, &block
155
- @original_options = *options
156
- make_specification *options, &block
154
+ def process_input options, &block
155
+ @original_options = options
156
+ make_specification options, &block
157
157
  @verbose = @specification[:verbose] || false
158
158
  @log = @specification[:log] || ""
159
159
  validate_specification
160
160
  end
161
161
 
162
- def make_specification *options, &block
163
- opts = options.dup
162
+ def make_specification options, &block
163
+ opts = options.flatten.dup
164
164
  rationalize_parameters opts
165
165
  @specification = Aquarium::Utils::MethodUtils.method_args_to_hash(*opts) {|option| ""} # set other hash values to an empty string
166
166
  use_default_object_if_defined unless (types_given? || objects_given? || pointcuts_given?)
@@ -240,9 +240,9 @@ module Aquarium
240
240
  alias_method_name = (saved_method_name join_point).intern
241
241
  return if private_method_defined? join_point.type_or_object, alias_method_name
242
242
  type_to_advise.class_eval(<<-EVAL_WRAPPER, __FILE__, __LINE__)
243
- #{static_method_prefix join_point.is_instance_method?}
243
+ #{static_method_prefix join_point.instance_method?}
244
244
  #{alias_original_method_text alias_method_name, join_point}
245
- #{static_method_suffix join_point.is_instance_method?}
245
+ #{static_method_suffix join_point.instance_method?}
246
246
  EVAL_WRAPPER
247
247
  Aspect.set_advice_chain join_point.type_or_object, join_point.method_name, Aquarium::Aspects::AdviceChainNodeFactory.make_node(
248
248
  :aspect => nil, # Belongs to all aspects that might advise this join point!
@@ -252,15 +252,15 @@ module Aquarium
252
252
  advice_chain = Aspect.get_advice_chain join_point.type_or_object, join_point.method_name
253
253
  end
254
254
 
255
- def static_method_prefix is_instance_method
256
- return "" if is_instance_method
255
+ def static_method_prefix instance_method
256
+ return "" if instance_method
257
257
  <<-EOF
258
258
  class << self
259
259
  EOF
260
260
  end
261
261
 
262
- def static_method_suffix is_instance_method
263
- return "" if is_instance_method
262
+ def static_method_suffix instance_method
263
+ return "" if instance_method
264
264
  <<-EOF
265
265
  end
266
266
  EOF
@@ -271,7 +271,7 @@ module Aquarium
271
271
  # idiom when invoking it.
272
272
  def alias_original_method_text alias_method_name, join_point
273
273
  self_name = join_point.type.nil? ? "self" : join_point.type.name
274
- target_self = join_point.is_instance_method? ? "self" : join_point.type.name
274
+ target_self = join_point.instance_method? ? "self" : join_point.type.name
275
275
  <<-EOF
276
276
  alias_method :#{alias_method_name}, :#{join_point.method_name}
277
277
  def #{join_point.method_name} *args, &block_for_method
@@ -280,6 +280,7 @@ module Aquarium
280
280
  advice_join_point = Aspect.make_advice_join_point static_join_point, #{target_self}, args, block_for_method
281
281
  advice_chain.call advice_join_point, *args
282
282
  end
283
+ #{join_point.visibility.to_s} :#{join_point.method_name}
283
284
  private :#{alias_method_name}
284
285
  EOF
285
286
  end
@@ -288,7 +289,7 @@ module Aquarium
288
289
  self_name = join_point.type.nil? ? "self" : join_point.type.name
289
290
  <<-EOF
290
291
  alias_method :#{join_point.method_name}, :#{alias_method_name}
291
- public :#{join_point.method_name}
292
+ #{join_point.visibility.to_s} :#{join_point.method_name}
292
293
  undef_method :#{alias_method_name}
293
294
  EOF
294
295
  end
@@ -345,9 +346,9 @@ module Aquarium
345
346
  def restore_type_method join_point
346
347
  alias_method_name = (saved_method_name join_point).intern
347
348
  join_point.type.class_eval(<<-EVAL_WRAPPER, __FILE__, __LINE__)
348
- #{static_method_prefix join_point.is_instance_method?}
349
+ #{static_method_prefix join_point.instance_method?}
349
350
  #{unalias_original_method_text alias_method_name, join_point}
350
- #{static_method_suffix join_point.is_instance_method?}
351
+ #{static_method_suffix join_point.instance_method?}
351
352
  #{remove_advice_chain_class_variable_text alias_method_name, join_point}
352
353
  EVAL_WRAPPER
353
354
  end
@@ -417,9 +418,9 @@ module Aquarium
417
418
  end
418
419
 
419
420
  def self.advice_chain_attr_name type_or_object, method_name
420
- type_or_object_key = self.make_type_or_object_key(type_or_object)
421
+ type_or_object_key = Aquarium::Utils::NameUtils.make_type_or_object_key(type_or_object)
421
422
  class_or_object_prefix = is_type?(type_or_object) ? "class_" : ""
422
- valid_name = self.make_valid_attr_name_from_method_name method_name
423
+ valid_name = Aquarium::Utils::NameUtils.make_valid_attr_name_from_method_name method_name
423
424
  "#{self.aspect_method_prefix}#{class_or_object_prefix}advice_chain_#{type_or_object_key}_#{valid_name}"
424
425
  end
425
426
 
@@ -428,26 +429,10 @@ module Aquarium
428
429
  end
429
430
 
430
431
  def saved_method_name join_point
431
- to_key = Aspect.make_type_or_object_key(join_point.type_or_object)
432
+ to_key = Aquarium::Utils::NameUtils.make_type_or_object_key(join_point.type_or_object)
432
433
  "#{Aspect.aspect_method_prefix}saved_#{to_key}_#{join_point.method_name}"
433
434
  end
434
435
 
435
- def self.make_type_or_object_key type_or_object
436
- if is_type?(type_or_object)
437
- make_valid_type_name type_or_object.name
438
- else
439
- "#{make_valid_type_name(type_or_object.class.name)}_#{type_or_object.object_id}"
440
- end
441
- end
442
-
443
- def self.make_valid_type_name type_name
444
- type_name.gsub(/:/, '_')
445
- end
446
-
447
- def self.make_valid_attr_name_from_method_name method_name
448
- method_name.to_s.gsub("=","equalsign").gsub("?", "questionmark").gsub("!", "exclamation").gsub("~", "tilde").intern
449
- end
450
-
451
436
  def specified_advice_kinds
452
437
  @specification.keys.select do |key|
453
438
  Aquarium::Aspects::Advice.kinds.include? key
@@ -1 +1,2 @@
1
- require 'aquarium/aspects/dsl/aspect_dsl'
1
+ # NEVER require 'aquarium/aspects/dsl/object_dsl' here!
2
+ require 'aquarium/aspects/dsl/aspect_dsl'
@@ -1,4 +1,5 @@
1
1
  require 'aquarium/aspects/aspect'
2
+ require 'aquarium/utils/type_utils'
2
3
 
3
4
  # Convenience methods added to Object to promote an AOP DSL. If you don't want these methods added to Object,
4
5
  # then only require aspect.rb and create instances of Aspect.
@@ -7,13 +8,14 @@ module Aquarium
7
8
  module Aspects
8
9
  module DSL
9
10
  module AspectDSL
11
+
10
12
  def advise *options, &block
11
13
  o = append_implicit_self options
12
14
  Aspect.new *o, &block
13
15
  end
14
16
 
15
17
  %w[before after after_returning after_raising around].each do |advice_kind|
16
- class_eval(<<-ADVICE_METHODS, __FILE__, __LINE__)
18
+ module_eval(<<-ADVICE_METHODS, __FILE__, __LINE__)
17
19
  def #{advice_kind} *options, &block
18
20
  advise :#{advice_kind}, *options, &block
19
21
  end
@@ -21,7 +23,7 @@ module Aquarium
21
23
  end
22
24
 
23
25
  %w[after after_returning after_raising].each do |after_kind|
24
- class_eval(<<-AFTER, __FILE__, __LINE__)
26
+ module_eval(<<-AFTER, __FILE__, __LINE__)
25
27
  def before_and_#{after_kind} *options, &block
26
28
  advise(:before, :#{after_kind}, *options, &block)
27
29
  end
@@ -31,16 +33,21 @@ module Aquarium
31
33
  alias :after_returning_from :after_returning
32
34
  alias :after_raising_within :after_raising
33
35
  alias :after_raising_within_or_returning_from :after
34
-
36
+
35
37
  alias :before_and_after_returning_from :before_and_after_returning
36
38
  alias :before_and_after_raising_within :before_and_after_raising
37
39
  alias :before_and_after_raising_within_or_returning_from :before_and_after
38
-
40
+
39
41
  def pointcut *options, &block
40
42
  o = append_implicit_self options
41
43
  Pointcut.new *o, &block
42
44
  end
43
45
 
46
+ # Add the methods as class, not instance, methods.
47
+ def self.append_features clazz
48
+ super(class << clazz; self; end)
49
+ end
50
+
44
51
  private
45
52
  def append_implicit_self options
46
53
  opts = options.dup
@@ -52,10 +59,7 @@ module Aquarium
52
59
  opts
53
60
  end
54
61
  end
62
+
55
63
  end
56
64
  end
57
65
  end
58
-
59
- class Object
60
- include Aquarium::Aspects::DSL::AspectDSL
61
- end
@@ -0,0 +1,8 @@
1
+ require 'aquarium/aspects/dsl/aspect_dsl'
2
+
3
+ # Add aspect convenience methods to Object. Only require this
4
+ # file if you really want these methods on all objects in your runtime!
5
+ class Object
6
+ include Aquarium::Aspects::DSL::AspectDSL
7
+ end
8
+
@@ -67,19 +67,20 @@ module Aquarium
67
67
  end
68
68
  end
69
69
 
70
- attr_accessor :type, :object, :method_name, :context
70
+ attr_accessor :type, :object, :method_name, :visibility, :context
71
71
 
72
- def is_instance_method?
73
- @is_instance_method
72
+ def instance_method?
73
+ @instance_method
74
74
  end
75
75
 
76
76
  def initialize options = {}
77
77
  @type = options[:type]
78
78
  @object = options[:object]
79
79
  @method_name = options[:method_name] || options[:method]
80
- @is_instance_method = options[:is_instance_method]
81
- is_class_method = options[:is_class_method].nil? ? false : options[:is_class_method]
82
- @is_instance_method = (!is_class_method) if @is_instance_method.nil?
80
+ @instance_method = options[:instance_method]
81
+ class_method = options[:class_method].nil? ? false : options[:class_method]
82
+ @instance_method = (!class_method) if @instance_method.nil?
83
+ @visibility = Aquarium::Utils::MethodUtils.visibility(type_or_object, @method_name, class_or_instance_method_flag)
83
84
  assert_valid options
84
85
  end
85
86
 
@@ -91,7 +92,7 @@ module Aquarium
91
92
  def type_or_object
92
93
  @type || @object
93
94
  end
94
-
95
+
95
96
  # TODO while convenient, it couples advice-type information where it doesn't belong!
96
97
  def proceed *args, &block
97
98
  context.method(:proceed).call self, *args, &block
@@ -120,7 +121,7 @@ module Aquarium
120
121
  return result unless result == 0
121
122
  result = (self.method_name.nil? && other.method_name.nil?) ? 0 : self.method_name.to_s <=> other.method_name.to_s
122
123
  return result unless result == 0
123
- result = self.is_instance_method? == other.is_instance_method?
124
+ result = self.instance_method? == other.instance_method?
124
125
  return 1 unless result == true
125
126
  result = (self.context.nil? && other.context.nil?) ? 0 : self.context <=> other.context
126
127
  return result
@@ -134,7 +135,7 @@ module Aquarium
134
135
  alias :=== :eql?
135
136
 
136
137
  def inspect
137
- "JoinPoint: {type = #{type.inspect}, object = #{object.inspect}, method_name = #{method_name}, is_instance_method? #{is_instance_method?}, context = #{context.inspect}}"
138
+ "JoinPoint: {type = #{type.inspect}, object = #{object.inspect}, method_name = #{method_name}, instance_method? #{instance_method?}, context = #{context.inspect}}"
138
139
  end
139
140
 
140
141
  alias :to_s :inspect
@@ -142,6 +143,7 @@ module Aquarium
142
143
 
143
144
  protected
144
145
 
146
+ # Since JoinPoints can be declared for non-existent methods, tolerate "nil" for the visibility.
145
147
  def assert_valid options
146
148
  error_message = ""
147
149
  error_message << "Must specify a :method_name. " unless method_name
@@ -149,7 +151,11 @@ module Aquarium
149
151
  error_message << "Can't specify both a :type or :object. " if (type and object)
150
152
  bad_attributes(error_message, options) if error_message.length > 0
151
153
  end
152
-
154
+
155
+ def class_or_instance_method_flag
156
+ @instance_method ? :instance_method_only : :class_method_only
157
+ end
158
+
153
159
  public
154
160
 
155
161
  NIL_OBJECT = Aquarium::Utils::NilObject.new