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.
- data/CHANGES +53 -0
- data/README +20 -4
- data/Rakefile +19 -4
- data/UPGRADE +41 -1
- data/examples/aspect_design_example.rb +4 -1
- data/examples/aspect_design_example_spec.rb +41 -0
- data/examples/design_by_contract_example.rb +2 -3
- data/examples/design_by_contract_example_spec.rb +92 -0
- data/examples/method_missing_example.rb +1 -1
- data/examples/method_missing_example_spec.rb +59 -0
- data/examples/method_tracing_example.rb +4 -2
- data/examples/method_tracing_example_spec.rb +141 -0
- data/lib/aquarium/aspects/advice.rb +2 -2
- data/lib/aquarium/aspects/aspect.rb +20 -35
- data/lib/aquarium/aspects/dsl.rb +2 -1
- data/lib/aquarium/aspects/dsl/aspect_dsl.rb +12 -8
- data/lib/aquarium/aspects/dsl/object_dsl.rb +8 -0
- data/lib/aquarium/aspects/join_point.rb +16 -10
- data/lib/aquarium/aspects/pointcut.rb +3 -3
- data/lib/aquarium/extras/design_by_contract.rb +20 -11
- data/lib/aquarium/utils.rb +1 -0
- data/lib/aquarium/utils/method_utils.rb +41 -0
- data/lib/aquarium/utils/name_utils.rb +35 -0
- data/lib/aquarium/utils/type_utils.rb +9 -0
- data/lib/aquarium/version.rb +3 -5
- data/rake_tasks/examples.rake +1 -1
- data/spec/aquarium/aspects/aspect_invocation_spec.rb +30 -28
- data/spec/aquarium/aspects/aspect_spec.rb +90 -0
- data/spec/aquarium/aspects/concurrent_aspects_spec.rb +5 -3
- data/spec/aquarium/aspects/concurrent_aspects_with_objects_and_types_spec.rb +3 -1
- data/spec/aquarium/aspects/dsl/aspect_dsl_spec.rb +174 -110
- data/spec/aquarium/aspects/join_point_spec.rb +120 -19
- data/spec/aquarium/aspects/pointcut_spec.rb +24 -14
- data/spec/aquarium/extras/design_by_contract_spec.rb +3 -0
- data/spec/aquarium/finders/finder_result_spec.rb +1 -1
- data/spec/aquarium/finders/method_finder_spec.rb +3 -4
- data/spec/aquarium/spec_example_classes.rb +4 -0
- data/spec/aquarium/utils/method_utils_spec.rb +124 -1
- data/spec/aquarium/utils/name_utils_spec.rb +56 -0
- data/spec/aquarium/utils/type_utils_spec.rb +17 -0
- metadata +12 -4
- 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
|
-
|
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.
|
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.
|
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
|
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
|
155
|
-
@original_options =
|
156
|
-
make_specification
|
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
|
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.
|
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.
|
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
|
256
|
-
return "" if
|
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
|
263
|
-
return "" if
|
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.
|
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
|
-
|
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.
|
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.
|
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 =
|
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 =
|
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 =
|
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
|
data/lib/aquarium/aspects/dsl.rb
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
require
|
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
|
-
|
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
|
-
|
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
|
@@ -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
|
73
|
-
@
|
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
|
-
@
|
81
|
-
|
82
|
-
@
|
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.
|
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},
|
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
|