aquarium 0.1.0 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
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