aquarium 0.1.0
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 +4 -0
- data/EXAMPLES.rd +4 -0
- data/MIT-LICENSE +20 -0
- data/README +250 -0
- data/RELEASE-PLAN +1 -0
- data/Rakefile +236 -0
- data/UPGRADE +3 -0
- data/examples/aspect_design_example.rb +36 -0
- data/examples/design_by_contract_example.rb +88 -0
- data/examples/method_missing_example.rb +44 -0
- data/examples/method_tracing_example.rb +64 -0
- data/lib/aquarium.rb +7 -0
- data/lib/aquarium/aspects.rb +6 -0
- data/lib/aquarium/aspects/advice.rb +189 -0
- data/lib/aquarium/aspects/aspect.rb +577 -0
- data/lib/aquarium/aspects/default_object_handler.rb +27 -0
- data/lib/aquarium/aspects/dsl.rb +1 -0
- data/lib/aquarium/aspects/dsl/aspect_dsl.rb +61 -0
- data/lib/aquarium/aspects/join_point.rb +158 -0
- data/lib/aquarium/aspects/pointcut.rb +254 -0
- data/lib/aquarium/aspects/pointcut_composition.rb +36 -0
- data/lib/aquarium/extensions.rb +5 -0
- data/lib/aquarium/extensions/hash.rb +85 -0
- data/lib/aquarium/extensions/regexp.rb +20 -0
- data/lib/aquarium/extensions/set.rb +49 -0
- data/lib/aquarium/extensions/string.rb +13 -0
- data/lib/aquarium/extensions/symbol.rb +22 -0
- data/lib/aquarium/extras.rb +4 -0
- data/lib/aquarium/extras/design_by_contract.rb +64 -0
- data/lib/aquarium/finders.rb +4 -0
- data/lib/aquarium/finders/finder_result.rb +121 -0
- data/lib/aquarium/finders/method_finder.rb +228 -0
- data/lib/aquarium/finders/object_finder.rb +74 -0
- data/lib/aquarium/finders/type_finder.rb +127 -0
- data/lib/aquarium/utils.rb +9 -0
- data/lib/aquarium/utils/array_utils.rb +29 -0
- data/lib/aquarium/utils/hash_utils.rb +28 -0
- data/lib/aquarium/utils/html_escaper.rb +17 -0
- data/lib/aquarium/utils/invalid_options.rb +9 -0
- data/lib/aquarium/utils/method_utils.rb +18 -0
- data/lib/aquarium/utils/nil_object.rb +13 -0
- data/lib/aquarium/utils/set_utils.rb +32 -0
- data/lib/aquarium/version.rb +30 -0
- data/rake_tasks/examples.rake +7 -0
- data/rake_tasks/examples_specdoc.rake +8 -0
- data/rake_tasks/examples_with_rcov.rake +8 -0
- data/rake_tasks/verify_rcov.rake +7 -0
- data/spec/aquarium/aspects/advice_chain_node_spec.rb +34 -0
- data/spec/aquarium/aspects/advice_spec.rb +103 -0
- data/spec/aquarium/aspects/aspect_invocation_spec.rb +111 -0
- data/spec/aquarium/aspects/aspect_spec.rb +978 -0
- data/spec/aquarium/aspects/aspect_with_nested_types_spec.rb +129 -0
- data/spec/aquarium/aspects/concurrent_aspects_spec.rb +423 -0
- data/spec/aquarium/aspects/concurrent_aspects_with_objects_and_types_spec.rb +103 -0
- data/spec/aquarium/aspects/concurrently_accessed.rb +21 -0
- data/spec/aquarium/aspects/dsl/aspect_dsl_spec.rb +514 -0
- data/spec/aquarium/aspects/join_point_spec.rb +302 -0
- data/spec/aquarium/aspects/pointcut_and_composition_spec.rb +131 -0
- data/spec/aquarium/aspects/pointcut_or_composition_spec.rb +111 -0
- data/spec/aquarium/aspects/pointcut_spec.rb +800 -0
- data/spec/aquarium/extensions/hash_spec.rb +187 -0
- data/spec/aquarium/extensions/regex_spec.rb +40 -0
- data/spec/aquarium/extensions/set_spec.rb +105 -0
- data/spec/aquarium/extensions/string_spec.rb +25 -0
- data/spec/aquarium/extensions/symbol_spec.rb +37 -0
- data/spec/aquarium/extras/design_by_contract_spec.rb +68 -0
- data/spec/aquarium/finders/finder_result_spec.rb +359 -0
- data/spec/aquarium/finders/method_finder_spec.rb +878 -0
- data/spec/aquarium/finders/method_sorting_spec.rb +16 -0
- data/spec/aquarium/finders/object_finder_spec.rb +230 -0
- data/spec/aquarium/finders/type_finder_spec.rb +210 -0
- data/spec/aquarium/spec_example_classes.rb +117 -0
- data/spec/aquarium/spec_helper.rb +3 -0
- data/spec/aquarium/utils/array_utils_spec.rb +47 -0
- data/spec/aquarium/utils/hash_utils_spec.rb +48 -0
- data/spec/aquarium/utils/html_escaper_spec.rb +18 -0
- data/spec/aquarium/utils/method_utils_spec.rb +50 -0
- data/spec/aquarium/utils/nil_object_spec.rb +19 -0
- data/spec/aquarium/utils/set_utils_spec.rb +60 -0
- metadata +132 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
# Specifically tests behavior when two or more advices apply to the same join points,
|
2
|
+
# where one advice is for the type and the other is for an object of the type.
|
3
|
+
|
4
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
5
|
+
require File.dirname(__FILE__) + '/../spec_example_classes'
|
6
|
+
require File.dirname(__FILE__) + '/concurrently_accessed'
|
7
|
+
require 'aquarium/aspects'
|
8
|
+
|
9
|
+
def make_aspect method, advice_kind, type_or_object_key, type_or_object
|
10
|
+
advise(advice_kind, :pointcut => {type_or_object_key => type_or_object, :method => method}) do |jp, *args|
|
11
|
+
@invoked << type_or_object_key
|
12
|
+
jp.proceed if advice_kind == :around
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "Advising an object join point and then the corresponding type join point" do
|
17
|
+
before :each do
|
18
|
+
@aspects = []
|
19
|
+
@invoked = []
|
20
|
+
@accessed = ConcurrentlyAccessed.new
|
21
|
+
end
|
22
|
+
after :each do
|
23
|
+
@aspects.each {|a| a.unadvise}
|
24
|
+
end
|
25
|
+
|
26
|
+
Aquarium::Aspects::Advice.kinds.each do |advice_kind|
|
27
|
+
it "should invoke only the advice on the object join point for :#{advice_kind} advice" do
|
28
|
+
method = advice_kind == :after_raising ? :invoke_raises : :invoke
|
29
|
+
@aspects << make_aspect(method, advice_kind, :object, @accessed)
|
30
|
+
@aspects << make_aspect(method, advice_kind, :type, ConcurrentlyAccessed)
|
31
|
+
begin
|
32
|
+
@accessed.method(method).call :a1, :a2
|
33
|
+
fail if advice_kind == :after_raising
|
34
|
+
rescue ConcurrentlyAccessed::Error
|
35
|
+
fail unless advice_kind == :after_raising
|
36
|
+
end
|
37
|
+
@invoked.should == [:object]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "Advising a type join point and then the corresponding join point on an object of the type" do
|
43
|
+
before :each do
|
44
|
+
@aspects = []
|
45
|
+
@invoked = []
|
46
|
+
@accessed = ConcurrentlyAccessed.new
|
47
|
+
end
|
48
|
+
after :each do
|
49
|
+
@aspects.each {|a| a.unadvise}
|
50
|
+
end
|
51
|
+
|
52
|
+
[:around, :before].each do |advice_kind|
|
53
|
+
it "should invoke first the advice on the object join point and then invoke the advice on the type join point for :#{advice_kind} advice" do
|
54
|
+
method = advice_kind == :after_raising ? :invoke_raises : :invoke
|
55
|
+
@aspects << make_aspect(:invoke, advice_kind, :type, ConcurrentlyAccessed)
|
56
|
+
@aspects << make_aspect(:invoke, advice_kind, :object, @accessed)
|
57
|
+
@accessed.invoke :a1, :a2
|
58
|
+
@invoked.should == [:object, :type]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
[:after, :after_returning, :after_raising].each do |advice_kind|
|
63
|
+
it "should invoke first the advice on the type join point and then invoke the advice on the object join point for :#{advice_kind} advice" do
|
64
|
+
method = advice_kind == :after_raising ? :invoke_raises : :invoke
|
65
|
+
@aspects << make_aspect(method, advice_kind, :type, ConcurrentlyAccessed)
|
66
|
+
@aspects << make_aspect(method, advice_kind, :object, @accessed)
|
67
|
+
begin
|
68
|
+
@accessed.method(method).call :a1, :a2
|
69
|
+
fail if advice_kind == :after_raising
|
70
|
+
rescue ConcurrentlyAccessed::Error
|
71
|
+
fail unless advice_kind == :after_raising
|
72
|
+
end
|
73
|
+
@invoked.should == [:type, :object]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "Removing two advices, one from an object join point and one from the corresponding type join point" do
|
79
|
+
before :each do
|
80
|
+
@aspects = []
|
81
|
+
@invoked = []
|
82
|
+
@accessed = ConcurrentlyAccessed.new
|
83
|
+
end
|
84
|
+
|
85
|
+
Aquarium::Aspects::Advice.kinds.each do |advice_kind|
|
86
|
+
it "should be removable for :#{advice_kind} advice only when the object join point was advised first" do
|
87
|
+
method = advice_kind == :after_raising ? :invoke_raises : :invoke
|
88
|
+
@aspects << make_aspect(method, advice_kind, :object, @accessed)
|
89
|
+
@aspects << make_aspect(method, advice_kind, :type, ConcurrentlyAccessed)
|
90
|
+
@aspects.each {|a| a.unadvise}
|
91
|
+
begin
|
92
|
+
@accessed.method(method).call :a1, :a2
|
93
|
+
fail if advice_kind == :after_raising
|
94
|
+
rescue ConcurrentlyAccessed::Error
|
95
|
+
fail unless advice_kind == :after_raising
|
96
|
+
end
|
97
|
+
@invoked.should == []
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class ConcurrentlyAccessed
|
2
|
+
class Error < Exception; end
|
3
|
+
|
4
|
+
def invoke *args
|
5
|
+
@invoked_count += 1
|
6
|
+
@invoked_args = args
|
7
|
+
end
|
8
|
+
|
9
|
+
def invoke_raises *args
|
10
|
+
@invoked_count += 1
|
11
|
+
@invoked_args = args
|
12
|
+
raise Error.new(args.inspect)
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@invoked_count = 0
|
17
|
+
@invoked_args = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :invoked_count, :invoked_args
|
21
|
+
end
|
@@ -0,0 +1,514 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper.rb'
|
2
|
+
require File.dirname(__FILE__) + '/../../spec_example_classes'
|
3
|
+
require 'aquarium/aspects/dsl/aspect_dsl'
|
4
|
+
|
5
|
+
describe Object, "#before" do
|
6
|
+
before :each do
|
7
|
+
@advice = proc {|jp,*args| "advice"}
|
8
|
+
@aspects = []
|
9
|
+
end
|
10
|
+
after :each do
|
11
|
+
@aspects.each {|a| a.unadvise}
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should be equivalent to advise :before." do
|
15
|
+
@aspects << advise(:before, :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
16
|
+
@aspects << before( :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
17
|
+
@aspects[1].should == @aspects[0]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Object, "#after" do
|
22
|
+
before :each do
|
23
|
+
@advice = proc {|jp,*args| "advice"}
|
24
|
+
@aspects = []
|
25
|
+
end
|
26
|
+
after :each do
|
27
|
+
@aspects.each {|a| a.unadvise}
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should be equivalent to advise :after." do
|
31
|
+
@aspects << advise(:after, :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
32
|
+
@aspects << after( :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
33
|
+
@aspects[1].should == @aspects[0]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe Object, "#after_raising_within_or_returning_from" do
|
38
|
+
before :each do
|
39
|
+
@advice = proc {|jp,*args| "advice"}
|
40
|
+
@aspects = []
|
41
|
+
end
|
42
|
+
after :each do
|
43
|
+
@aspects.each {|a| a.unadvise}
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should be equivalent to advise :after." do
|
47
|
+
@aspects << after( :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
48
|
+
@aspects << after_raising_within_or_returning_from(:noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
49
|
+
@aspects[1].should == @aspects[0]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe Object, "#after_returning" do
|
54
|
+
before :each do
|
55
|
+
@advice = proc {|jp,*args| "advice"}
|
56
|
+
@aspects = []
|
57
|
+
end
|
58
|
+
after :each do
|
59
|
+
@aspects.each {|a| a.unadvise}
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should be equivalent to advise :after_returning." do
|
63
|
+
@aspects << advise(:after_returning, :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
64
|
+
@aspects << after_returning( :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
65
|
+
@aspects[1].should == @aspects[0]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe Object, "#after_returning_from" do
|
70
|
+
before :each do
|
71
|
+
@advice = proc {|jp,*args| "advice"}
|
72
|
+
@aspects = []
|
73
|
+
end
|
74
|
+
after :each do
|
75
|
+
@aspects.each {|a| a.unadvise}
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should be equivalent to advise :after_returning." do
|
79
|
+
@aspects << advise(:after_returning, :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
80
|
+
@aspects << after_returning_from( :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
81
|
+
@aspects[1].should == @aspects[0]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe Object, "#after_raising" do
|
86
|
+
before :each do
|
87
|
+
@advice = proc {|jp,*args| "advice"}
|
88
|
+
@aspects = []
|
89
|
+
end
|
90
|
+
after :each do
|
91
|
+
@aspects.each {|a| a.unadvise}
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should be equivalent to advise :after_raising." do
|
95
|
+
class ThrowsUp
|
96
|
+
def tosses_cookies *args; raise Exception.new(args.inspect); end
|
97
|
+
end
|
98
|
+
@aspects << advise(:after_raising, :noop, :pointcut => {:type => ThrowsUp, :methods => :tosses_cookies}, &@advice)
|
99
|
+
@aspects << after_raising( :noop, :pointcut => {:type => ThrowsUp, :methods => :tosses_cookies}, &@advice)
|
100
|
+
@aspects[1].should == @aspects[0]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe Object, "#after_raising_within" do
|
105
|
+
before :each do
|
106
|
+
@advice = proc {|jp,*args| "advice"}
|
107
|
+
@aspects = []
|
108
|
+
end
|
109
|
+
after :each do
|
110
|
+
@aspects.each {|a| a.unadvise}
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should be equivalent to advise :after_raising." do
|
114
|
+
class ThrowsUp
|
115
|
+
def tosses_cookies *args; raise Exception.new(args.inspect); end
|
116
|
+
end
|
117
|
+
@aspects << advise(:after_raising, :noop, :pointcut => {:type => ThrowsUp, :methods => :tosses_cookies}, &@advice)
|
118
|
+
@aspects << after_raising_within( :noop, :pointcut => {:type => ThrowsUp, :methods => :tosses_cookies}, &@advice)
|
119
|
+
@aspects[1].should == @aspects[0]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe Object, "#before_and_after" do
|
124
|
+
before :each do
|
125
|
+
@advice = proc {|jp,*args| "advice"}
|
126
|
+
@aspects = []
|
127
|
+
end
|
128
|
+
after :each do
|
129
|
+
@aspects.each {|a| a.unadvise}
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should be equivalent to advise :before, :after." do
|
133
|
+
@aspects << advise(:before, :after, :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
134
|
+
@aspects << before_and_after(:noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
135
|
+
@aspects[1].should == @aspects[0]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe Object, "#before_and_after_raising_within_or_returning_from" do
|
140
|
+
before :each do
|
141
|
+
@advice = proc {|jp,*args| "advice"}
|
142
|
+
@aspects = []
|
143
|
+
end
|
144
|
+
after :each do
|
145
|
+
@aspects.each {|a| a.unadvise}
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should be equivalent to advise :before and advise :after." do
|
149
|
+
@aspects << advise(:before, :after, :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
150
|
+
@aspects << before_and_after_raising_within_or_returning_from(:noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
151
|
+
@aspects[1].should == @aspects[0]
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe Object, "#before_and_after_returning" do
|
156
|
+
before :each do
|
157
|
+
@advice = proc {|jp,*args| "advice"}
|
158
|
+
@aspects = []
|
159
|
+
end
|
160
|
+
after :each do
|
161
|
+
@aspects.each {|a| a.unadvise}
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should be equivalent to advise :before and advise :after_returning." do
|
165
|
+
@aspects << advise(:before, :after_returning, :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
166
|
+
@aspects << before_and_after_returning( :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
167
|
+
@aspects[1].should == @aspects[0]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe Object, "#before_and_after_returning_from" do
|
172
|
+
before :each do
|
173
|
+
@advice = proc {|jp,*args| "advice"}
|
174
|
+
@aspects = []
|
175
|
+
end
|
176
|
+
after :each do
|
177
|
+
@aspects.each {|a| a.unadvise}
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should be equivalent to advise :before and advise :after_returning." do
|
181
|
+
@aspects << advise(:before, :after_returning, :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
182
|
+
@aspects << before_and_after_returning_from(:noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
183
|
+
@aspects[1].should == @aspects[0]
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe Object, "#before_and_after_raising" do
|
188
|
+
before :each do
|
189
|
+
@advice = proc {|jp,*args| "advice"}
|
190
|
+
@aspects = []
|
191
|
+
end
|
192
|
+
after :each do
|
193
|
+
@aspects.each {|a| a.unadvise}
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should be equivalent to advise :before and advise :after_raising." do
|
197
|
+
@aspects << advise(:before, :after_raising, :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
198
|
+
@aspects << before_and_after_raising(:noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
199
|
+
@aspects[1].should == @aspects[0]
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
describe Object, "#around" do
|
204
|
+
before :each do
|
205
|
+
@advice = proc {|jp,*args| "advice"}
|
206
|
+
@aspects = []
|
207
|
+
end
|
208
|
+
after :each do
|
209
|
+
@aspects.each {|a| a.unadvise}
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should be equivalent to advise :around." do
|
213
|
+
@aspects << advise(:around, :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
214
|
+
@aspects << around( :noop, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, &@advice)
|
215
|
+
@aspects[1].should == @aspects[0]
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe Object, "#advise (inferred arguments)" do
|
220
|
+
before :each do
|
221
|
+
@watchful = Watchful.new
|
222
|
+
@aspects = []
|
223
|
+
end
|
224
|
+
after :each do
|
225
|
+
@aspects.each {|a| a.unadvise}
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should ignore the default object \"self\" when an :object is specified." do
|
229
|
+
class Watchful
|
230
|
+
@@watchful = Watchful.new
|
231
|
+
@@aspect = after(:object => @@watchful, :method => :public_watchful_method) {|jp,*args|}
|
232
|
+
def self.watchful; @@watchful; end
|
233
|
+
def self.aspect; @@aspect; end
|
234
|
+
end
|
235
|
+
@aspects << after(:object => Watchful.watchful, :method => :public_watchful_method) {|jp,*args|}
|
236
|
+
@aspects << Watchful.aspect
|
237
|
+
@aspects[1].join_points_matched.should == @aspects[0].join_points_matched
|
238
|
+
@aspects[1].pointcuts.should == @aspects[0].pointcuts
|
239
|
+
end
|
240
|
+
|
241
|
+
it "should ignore the default object \"self\" when a :type is specified." do
|
242
|
+
class Watchful
|
243
|
+
@@aspect = after(:type => Watchful, :method => :public_watchful_method) {|jp,*args|}
|
244
|
+
def self.aspect; @@aspect; end
|
245
|
+
end
|
246
|
+
@aspects << after(:type => Watchful, :method => :public_watchful_method) {|jp,*args|}
|
247
|
+
@aspects << Watchful.aspect
|
248
|
+
@aspects[1].join_points_matched.should == @aspects[0].join_points_matched
|
249
|
+
@aspects[1].pointcuts.should == @aspects[0].pointcuts
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should infer the type to advise as \"self\" when no :object, :type, or :pointcut is specified." do
|
253
|
+
@aspects << after(:type => Watchful, :method => :public_watchful_method) {|jp,*args|}
|
254
|
+
class Watchful
|
255
|
+
@@aspect = after(:method => :public_watchful_method) {|jp,*args|}
|
256
|
+
def self.aspect; @@aspect; end
|
257
|
+
end
|
258
|
+
@aspects << Watchful.aspect
|
259
|
+
@aspects[1].join_points_matched.should == @aspects[0].join_points_matched
|
260
|
+
@aspects[1].pointcuts.should == @aspects[0].pointcuts
|
261
|
+
end
|
262
|
+
|
263
|
+
it "should treat \"ClassName.advise\" as advising instance methods, by default." do
|
264
|
+
class WatchfulExampleWithSeparateAdviseCall
|
265
|
+
def public_watchful_method *args; end
|
266
|
+
end
|
267
|
+
advice_called = 0
|
268
|
+
WatchfulExampleWithSeparateAdviseCall.before :public_watchful_method do |jp, *args|
|
269
|
+
advice_called += 1
|
270
|
+
end
|
271
|
+
WatchfulExampleWithSeparateAdviseCall.new.public_watchful_method :a1, :a2
|
272
|
+
WatchfulExampleWithSeparateAdviseCall.new.public_watchful_method :a3, :a4
|
273
|
+
advice_called.should == 2
|
274
|
+
end
|
275
|
+
|
276
|
+
it "should treat \"ClassName.advise\" as advising instance methods when the :instance method option is specified." do
|
277
|
+
class WatchfulExampleWithSeparateAdviseCall2
|
278
|
+
def self.class_public_watchful_method *args; end
|
279
|
+
def public_watchful_method *args; end
|
280
|
+
end
|
281
|
+
advice_called = 0
|
282
|
+
Aquarium::Aspects::Aspect.new :before, :type => WatchfulExampleWithSeparateAdviseCall2, :methods => /public_watchful_method/, :method_options =>[:instance] do |jp, *args|
|
283
|
+
advice_called += 1
|
284
|
+
end
|
285
|
+
WatchfulExampleWithSeparateAdviseCall2.class_public_watchful_method :a1, :a2
|
286
|
+
WatchfulExampleWithSeparateAdviseCall2.class_public_watchful_method :a3, :a4
|
287
|
+
advice_called.should == 0
|
288
|
+
WatchfulExampleWithSeparateAdviseCall2.new.public_watchful_method :a1, :a2
|
289
|
+
WatchfulExampleWithSeparateAdviseCall2.new.public_watchful_method :a3, :a4
|
290
|
+
advice_called.should == 2
|
291
|
+
end
|
292
|
+
|
293
|
+
it "should treat \"ClassName.advise\" as advising class methods when the :class method option is specified." do
|
294
|
+
class WatchfulExampleWithSeparateAdviseCall
|
295
|
+
def self.class_public_watchful_method *args; end
|
296
|
+
def public_watchful_method *args; end
|
297
|
+
end
|
298
|
+
advice_called = 0
|
299
|
+
WatchfulExampleWithSeparateAdviseCall.before :methods => /public_watchful_method/, :method_options =>[:class] do |jp, *args|
|
300
|
+
advice_called += 1
|
301
|
+
end
|
302
|
+
WatchfulExampleWithSeparateAdviseCall.class_public_watchful_method :a1, :a2
|
303
|
+
WatchfulExampleWithSeparateAdviseCall.class_public_watchful_method :a3, :a4
|
304
|
+
advice_called.should == 2
|
305
|
+
WatchfulExampleWithSeparateAdviseCall.new.public_watchful_method :a1, :a2
|
306
|
+
WatchfulExampleWithSeparateAdviseCall.new.public_watchful_method :a3, :a4
|
307
|
+
advice_called.should == 2
|
308
|
+
end
|
309
|
+
|
310
|
+
it "should invoke the type-based advise for all objects when the aspect is defined by calling #advise within the class definition." do
|
311
|
+
class WatchfulExampleWithBeforeAdvice
|
312
|
+
@@advice_called = 0
|
313
|
+
def public_watchful_method *args; end
|
314
|
+
before :public_watchful_method do |jp, *args|
|
315
|
+
@@advice_called += 1
|
316
|
+
end
|
317
|
+
def self.advice_called; @@advice_called; end
|
318
|
+
end
|
319
|
+
WatchfulExampleWithBeforeAdvice.new.public_watchful_method :a1, :a2
|
320
|
+
WatchfulExampleWithBeforeAdvice.new.public_watchful_method :a3, :a4
|
321
|
+
WatchfulExampleWithBeforeAdvice.advice_called.should == 2
|
322
|
+
end
|
323
|
+
|
324
|
+
it "should infer the object to advise as \"self\" when no :object, :type, or :pointcut is specified." do
|
325
|
+
@aspects << @watchful.after(:method => :public_watchful_method) {|jp,*args|}
|
326
|
+
@aspects << advise( :after, :pointcut => {:object => @watchful, :method => :public_watchful_method}) {|jp,*args|}
|
327
|
+
@aspects[1].join_points_matched.should == @aspects[0].join_points_matched
|
328
|
+
@aspects[1].pointcuts.should == @aspects[0].pointcuts
|
329
|
+
end
|
330
|
+
|
331
|
+
it "should infer no types or objects if a :pointcut => {...} parameter is used and it does not specify a type or object." do
|
332
|
+
@aspects << after(:pointcut => {:method => /method/}) {|jp,*args|}
|
333
|
+
@aspects[0].join_points_matched.size.should == 0
|
334
|
+
end
|
335
|
+
|
336
|
+
it "should infer the first symbol parameter after the advice kind parameter is the method name to advise if no other :method => ... parameter is used." do
|
337
|
+
@aspects << @watchful.after( :public_watchful_method) {|jp,*args|}
|
338
|
+
@aspects.each do |aspect|
|
339
|
+
aspect.join_points_matched.size.should == 1
|
340
|
+
aspect.specification[:methods].should == Set.new([:public_watchful_method])
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
describe Object, "advice kind convenience methods (inferred arguments)" do
|
346
|
+
before :each do
|
347
|
+
@advice = proc {|jp,*args| "advice"}
|
348
|
+
@watchful = Watchful.new
|
349
|
+
@aspects = []
|
350
|
+
end
|
351
|
+
after :each do
|
352
|
+
@aspects.each {|a| a.unadvise}
|
353
|
+
end
|
354
|
+
|
355
|
+
(Aquarium::Aspects::Advice.kinds + [:after_raising_within_or_returning_from]).each do |advice_kind|
|
356
|
+
it "##{advice_kind} method should infer the first symbol parameter as the method name to advise if no other :method => ... parameter is used." do
|
357
|
+
@aspects << @watchful.method(advice_kind).call(:public_watchful_method, &@advice)
|
358
|
+
@aspects.each do |aspect|
|
359
|
+
aspect.join_points_matched.size.should == 1
|
360
|
+
aspect.specification[:methods].should == Set.new([:public_watchful_method])
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
describe "Synonyms for :types" do
|
367
|
+
before :each do
|
368
|
+
@advice = proc {|jp,*args| "advice"}
|
369
|
+
@aspects = [after(:noop, :types => Watchful, :methods => :public_watchful_method, &@advice)]
|
370
|
+
end
|
371
|
+
after :each do
|
372
|
+
@aspects.each {|a| a.unadvise}
|
373
|
+
end
|
374
|
+
|
375
|
+
it ":type is a synonym for :types" do
|
376
|
+
@aspects << after(:noop, :type => Watchful, :methods => :public_watchful_method, &@advice)
|
377
|
+
@aspects[1].should == @aspects[0]
|
378
|
+
end
|
379
|
+
|
380
|
+
it ":within_types is a synonym for :types" do
|
381
|
+
@aspects << after(:noop, :within_type => Watchful, :methods => :public_watchful_method, &@advice)
|
382
|
+
@aspects[1].should == @aspects[0]
|
383
|
+
end
|
384
|
+
|
385
|
+
it ":within_types is a synonym for :types" do
|
386
|
+
@aspects << after(:noop, :within_types => Watchful, :methods => :public_watchful_method, &@advice)
|
387
|
+
@aspects[1].should == @aspects[0]
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
describe "Synonyms for :objects" do
|
392
|
+
before :each do
|
393
|
+
@advice = proc {|jp,*args| "advice"}
|
394
|
+
@watchful = Watchful.new
|
395
|
+
@aspects = [after(:noop, :objects => @watchful, :methods => :public_watchful_method, &@advice)]
|
396
|
+
end
|
397
|
+
after :each do
|
398
|
+
@aspects.each {|a| a.unadvise}
|
399
|
+
end
|
400
|
+
|
401
|
+
it ":object is a synonym for :objects" do
|
402
|
+
@aspects << after(:noop, :object => @watchful, :methods => :public_watchful_method, &@advice)
|
403
|
+
@aspects[1].should == @aspects[0]
|
404
|
+
end
|
405
|
+
|
406
|
+
it ":within_objects is a synonym for :objects" do
|
407
|
+
@aspects << after(:noop, :within_object => @watchful, :methods => :public_watchful_method, &@advice)
|
408
|
+
@aspects[1].should == @aspects[0]
|
409
|
+
end
|
410
|
+
|
411
|
+
it ":within_objects is a synonym for :objects" do
|
412
|
+
@aspects << after(:noop, :within_objects => @watchful, :methods => :public_watchful_method, &@advice)
|
413
|
+
@aspects[1].should == @aspects[0]
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
describe "Synonyms for :methods" do
|
418
|
+
before :each do
|
419
|
+
@advice = proc {|jp,*args| "advice"}
|
420
|
+
@watchful = Watchful.new
|
421
|
+
@aspects = [after(:noop, :objects => @watchful, :methods => :public_watchful_method, &@advice)]
|
422
|
+
end
|
423
|
+
after :each do
|
424
|
+
@aspects.each {|a| a.unadvise}
|
425
|
+
end
|
426
|
+
|
427
|
+
it ":method is a synonym for :methods" do
|
428
|
+
@aspects << after(:noop, :object => @watchful, :method => :public_watchful_method, &@advice)
|
429
|
+
@aspects[1].should == @aspects[0]
|
430
|
+
end
|
431
|
+
|
432
|
+
it ":within_methods is a synonym for :methods" do
|
433
|
+
@aspects << after(:noop, :within_object => @watchful, :within_methods => :public_watchful_method, &@advice)
|
434
|
+
@aspects[1].should == @aspects[0]
|
435
|
+
end
|
436
|
+
|
437
|
+
it ":within_methods is a synonym for :methods" do
|
438
|
+
@aspects << after(:noop, :within_objects => @watchful, :within_method => :public_watchful_method, &@advice)
|
439
|
+
@aspects[1].should == @aspects[0]
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
describe "Synonyms for :pointcut" do
|
444
|
+
before :each do
|
445
|
+
@advice = proc {|jp,*args| "advice"}
|
446
|
+
@watchful = Watchful.new
|
447
|
+
@aspects = [after(:noop, :pointcut => {:objects => @watchful, :methods => :public_watchful_method}, &@advice)]
|
448
|
+
end
|
449
|
+
after :each do
|
450
|
+
@aspects.each {|a| a.unadvise}
|
451
|
+
end
|
452
|
+
|
453
|
+
it ":pointcuts is a synonym for :pointcut" do
|
454
|
+
@aspects << after(:noop, :pointcuts => {:objects => @watchful, :methods => :public_watchful_method}, &@advice)
|
455
|
+
@aspects[1].should == @aspects[0]
|
456
|
+
end
|
457
|
+
|
458
|
+
it "should accept :within_pointcuts as a synonym for :pointcut." do
|
459
|
+
@aspects << after(:noop, :within_pointcuts => {:objects => @watchful, :methods => :public_watchful_method}, &@advice)
|
460
|
+
@aspects[1].should == @aspects[0]
|
461
|
+
end
|
462
|
+
|
463
|
+
it "should accept :within_pointcut as a synonym for :pointcut." do
|
464
|
+
@aspects << after(:noop, :within_pointcut => {:objects => @watchful, :methods => :public_watchful_method}, &@advice)
|
465
|
+
@aspects[1].should == @aspects[0]
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
describe Object, "#advise (or synonyms) called within a type body" do
|
470
|
+
it "will not advise a method whose definition hasn't been seen yet in the type body." do
|
471
|
+
class WatchfulWithMethodAlreadyDefined
|
472
|
+
@@advice_called = 0
|
473
|
+
def public_watchful_method *args; end
|
474
|
+
before :public_watchful_method do |jp, *args|
|
475
|
+
@@advice_called += 1
|
476
|
+
end
|
477
|
+
def self.advice_called; @@advice_called; end
|
478
|
+
end
|
479
|
+
WatchfulWithMethodAlreadyDefined.new.public_watchful_method :a1, :a2
|
480
|
+
WatchfulWithMethodAlreadyDefined.new.public_watchful_method :a3, :a4
|
481
|
+
WatchfulWithMethodAlreadyDefined.advice_called.should == 2
|
482
|
+
class WatchfulWithMethodNotYetDefined
|
483
|
+
@@advice_called = 0
|
484
|
+
before(:public_watchful_method) {|jp, *args| @@advice_called += 1}
|
485
|
+
def public_watchful_method *args; end
|
486
|
+
def self.advice_called; @@advice_called; end
|
487
|
+
end
|
488
|
+
WatchfulWithMethodNotYetDefined.new.public_watchful_method :a1, :a2
|
489
|
+
WatchfulWithMethodNotYetDefined.new.public_watchful_method :a3, :a4
|
490
|
+
WatchfulWithMethodNotYetDefined.advice_called.should == 0
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
describe Object, "#pointcut" do
|
495
|
+
class PC1;
|
496
|
+
def doit; end
|
497
|
+
end
|
498
|
+
|
499
|
+
it "should match equivalent join points as Pointcut.new" do
|
500
|
+
pointcut1 = pointcut :type => PC1, :method => :doit
|
501
|
+
pointcut2 = Aquarium::Aspects::Pointcut.new :type => PC1, :method => :doit
|
502
|
+
pointcut1.join_points_matched.should == pointcut2.join_points_matched
|
503
|
+
pointcut1.join_points_not_matched.should == pointcut2.join_points_not_matched
|
504
|
+
end
|
505
|
+
|
506
|
+
it "should use self as the object if no object or type is specified." do
|
507
|
+
class PC1
|
508
|
+
POINTCUT = pointcut :method => :doit
|
509
|
+
end
|
510
|
+
pointcut2 = Aquarium::Aspects::Pointcut.new :type => PC1, :method => :doit
|
511
|
+
PC1::POINTCUT.join_points_matched.should == pointcut2.join_points_matched
|
512
|
+
PC1::POINTCUT.join_points_not_matched.should == pointcut2.join_points_not_matched
|
513
|
+
end
|
514
|
+
end
|