aquarium 0.4.0 → 0.4.1

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 (45) hide show
  1. data/CHANGES +26 -5
  2. data/README +8 -8
  3. data/RELEASE-PLAN +20 -2
  4. data/TODO.rb +26 -0
  5. data/UPGRADE +5 -5
  6. data/examples/aspect_design_example.rb +1 -1
  7. data/examples/aspect_design_example_spec.rb +1 -1
  8. data/examples/design_by_contract_example.rb +4 -9
  9. data/examples/design_by_contract_example_spec.rb +7 -9
  10. data/examples/exception_wrapping_example.rb +48 -0
  11. data/examples/exception_wrapping_example_spec.rb +49 -0
  12. data/examples/reusable_aspect_hack_example.rb +56 -0
  13. data/examples/reusable_aspect_hack_example_spec.rb +80 -0
  14. data/lib/aquarium.rb +1 -0
  15. data/lib/aquarium/aspects.rb +1 -1
  16. data/lib/aquarium/aspects/advice.rb +16 -13
  17. data/lib/aquarium/aspects/aspect.rb +81 -56
  18. data/lib/aquarium/aspects/join_point.rb +4 -4
  19. data/lib/aquarium/aspects/pointcut.rb +49 -73
  20. data/lib/aquarium/dsl.rb +2 -0
  21. data/lib/aquarium/dsl/aspect_dsl.rb +77 -0
  22. data/lib/aquarium/{aspects/dsl → dsl}/object_dsl.rb +2 -2
  23. data/lib/aquarium/extras/design_by_contract.rb +1 -1
  24. data/lib/aquarium/finders.rb +1 -1
  25. data/lib/aquarium/finders/method_finder.rb +26 -26
  26. data/lib/aquarium/finders/type_finder.rb +45 -39
  27. data/lib/aquarium/utils/array_utils.rb +6 -5
  28. data/lib/aquarium/utils/default_logger.rb +2 -1
  29. data/lib/aquarium/utils/options_utils.rb +178 -67
  30. data/lib/aquarium/utils/set_utils.rb +8 -3
  31. data/lib/aquarium/version.rb +1 -1
  32. data/spec/aquarium/aspects/aspect_invocation_spec.rb +111 -14
  33. data/spec/aquarium/aspects/aspect_spec.rb +91 -7
  34. data/spec/aquarium/aspects/pointcut_spec.rb +61 -0
  35. data/spec/aquarium/{aspects/dsl → dsl}/aspect_dsl_spec.rb +76 -32
  36. data/spec/aquarium/finders/method_finder_spec.rb +80 -80
  37. data/spec/aquarium/finders/type_finder_spec.rb +57 -52
  38. data/spec/aquarium/finders/type_finder_with_descendents_and_ancestors_spec.rb +12 -12
  39. data/spec/aquarium/spec_example_types.rb +4 -3
  40. data/spec/aquarium/utils/array_utils_spec.rb +9 -7
  41. data/spec/aquarium/utils/options_utils_spec.rb +106 -5
  42. data/spec/aquarium/utils/set_utils_spec.rb +14 -0
  43. metadata +12 -7
  44. data/lib/aquarium/aspects/dsl.rb +0 -2
  45. data/lib/aquarium/aspects/dsl/aspect_dsl.rb +0 -64
@@ -6,14 +6,19 @@ module Aquarium
6
6
 
7
7
  # Return a set containing the input item or list of items. If the input
8
8
  # is a set or an array, it is returned. In all cases, the constructed set is a
9
- # flattened version of the input and any nil elements are removed by #strip_nils.
9
+ # flattened version of the input and any nil elements are removed by #strip_set_nils.
10
10
  # Note that this behavior effectively converts +nil+ to +[]+.
11
11
  def make_set *value_or_set_or_array
12
- strip_nils(convert_to_set(*value_or_set_or_array))
12
+ strip_set_nils(convert_to_set(*value_or_set_or_array))
13
13
  end
14
14
 
15
15
  # Return a new set that is a copy of the input set with all nils removed.
16
- def strip_nils set
16
+ def strip_set_nils set
17
+ set.delete_if {|x| x.nil?}
18
+ end
19
+
20
+ # Return a new set that is a copy of the input set with all nils removed.
21
+ def self.strip_set_nils set
17
22
  set.delete_if {|x| x.nil?}
18
23
  end
19
24
 
@@ -9,7 +9,7 @@ module Aquarium
9
9
  unless defined? MAJOR
10
10
  MAJOR = 0
11
11
  MINOR = 4
12
- TINY = 0
12
+ TINY = 1
13
13
  RELEASE_CANDIDATE = nil
14
14
 
15
15
  # RANDOM_TOKEN: 0.598704893979657
@@ -31,7 +31,7 @@ end
31
31
 
32
32
  module Aquarium
33
33
  class AspectInvocationTestClass
34
- include Aquarium::Aspects::DSL::AspectDSL
34
+ include Aquarium::DSL
35
35
  attr_accessor :public_test_method_args
36
36
  def public_test_method *args; @args=args; end
37
37
  protected
@@ -42,6 +42,16 @@ module Aquarium
42
42
  def self.private_class_test_method *args; end
43
43
  private_class_method :private_class_test_method
44
44
  end
45
+ class AspectInvocationTestClass2
46
+ include Aquarium::DSL
47
+ attr_accessor :public_test_method_args
48
+ def public_test_method *args; @args=args; end
49
+ end
50
+ class AspectInvocationTestClass3
51
+ attr_accessor :public_test_method_args
52
+ attr_accessor :public_test_method_args2
53
+ def public_test_method *args; @args=args; end
54
+ end
45
55
  end
46
56
 
47
57
  describe Aspect, "methods" do
@@ -60,15 +70,15 @@ describe Aspect, "methods" do
60
70
  end
61
71
 
62
72
  it "should warn about no join point matches if the :ignore_no_matching_join_points is not specified." do
63
- lambda {Aspect.new(:after, :logger_stream => @log_stream) {|jp, obj, *args| true}}.should raise_error(Aquarium::Utils::InvalidOptions)
73
+ lambda {Aspect.new(:after, :logger_stream => @log_stream) {true}}.should raise_error(Aquarium::Utils::InvalidOptions)
64
74
  @log_stream.string.should_not be_empty
65
75
  end
66
76
  it "should warn about no join point matches if :ignore_no_matching_join_points => false is specified." do
67
- lambda {Aspect.new(:after, :logger_stream => @log_stream, :ignore_no_matching_join_points => false) {|jp, obj, *args| true}}.should raise_error(Aquarium::Utils::InvalidOptions)
77
+ lambda {Aspect.new(:after, :logger_stream => @log_stream, :ignore_no_matching_join_points => false) {true}}.should raise_error(Aquarium::Utils::InvalidOptions)
68
78
  @log_stream.string.should_not be_empty
69
79
  end
70
80
  it "should not warn about no join point matches if :ignore_no_matching_join_points => true is specified." do
71
- lambda {Aspect.new(:after, :logger_stream => @log_stream, :ignore_no_matching_join_points => true) {|jp, obj, *args| true}}.should raise_error(Aquarium::Utils::InvalidOptions)
81
+ lambda {Aspect.new(:after, :logger_stream => @log_stream, :ignore_no_matching_join_points => true) {true}}.should raise_error(Aquarium::Utils::InvalidOptions)
72
82
  @log_stream.string.should be_empty
73
83
  end
74
84
  end
@@ -111,10 +121,18 @@ describe Aspect, "methods" do
111
121
  lambda { Aspect.new :before, :after_raising => Exception, :pointcut => @pointcut_opts, :noop => true }.should_not raise_error(Aquarium::Utils::InvalidOptions)
112
122
  end
113
123
 
114
- it "should accept a a list of exceptions specified with :after_raising." do
124
+ it "should accept a list of exceptions specified with :after_raising." do
115
125
  lambda { Aspect.new :before, :after_raising => [Exception, String], :pointcut => @pointcut_opts, :noop => true }.should_not raise_error(Aquarium::Utils::InvalidOptions)
116
126
  end
117
- end
127
+
128
+ it "should accept a separate :exceptions => list of exceptions specified with :after_raising." do
129
+ lambda { Aspect.new :before, :after_raising, :exceptions => [Exception, String], :pointcut => @pointcut_opts, :noop => true }.should_not raise_error(Aquarium::Utils::InvalidOptions)
130
+ end
131
+
132
+ it "should reject the :exceptions argument unless specified with :after_raising." do
133
+ lambda { Aspect.new :before, :after, :exceptions => [Exception, String], :pointcut => @pointcut_opts, :noop => true }.should raise_error(Aquarium::Utils::InvalidOptions)
134
+ end
135
+ end
118
136
 
119
137
  describe Aspect, ".new (parameters that specify pointcuts)" do
120
138
  before :all do
@@ -122,22 +140,83 @@ describe Aspect, "methods" do
122
140
  end
123
141
 
124
142
  it "should contain at least one of :method(s), :pointcut(s), :type(s), or :object(s)." do
125
- lambda {Aspect.new(:after, :ignore_no_matching_join_points => true) {|jp, obj, *args| true}}.should raise_error(Aquarium::Utils::InvalidOptions)
143
+ lambda {Aspect.new(:after, :ignore_no_matching_join_points => true) {true}}.should raise_error(Aquarium::Utils::InvalidOptions)
126
144
  end
127
145
 
128
146
  it "should contain at least one of :pointcut(s), :type(s), or :object(s) unless :default_objects => object is given." do
129
- aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass.new, :methods => :public_test_method, :noop => true) {|jp, obj, *args| true}
147
+ aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass.new, :method => :public_test_method, :noop => true) {true}
148
+ end
149
+
150
+ it "should ignore the :default_objects if at least one other :object is given and the :default_objects are objects." do
151
+ object1 = Aquarium::AspectInvocationTestClass.new
152
+ object2 = Aquarium::AspectInvocationTestClass2.new
153
+ aspect = Aspect.new(:after, :default_objects => object1, :object => object2, :method => :public_test_method) {true}
154
+ aspect.join_points_matched.size.should == 1
155
+ aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == object1}
156
+ end
157
+
158
+ it "should ignore the :default_objects if at least one other :object is given and the :default_objects are types." do
159
+ object = Aquarium::AspectInvocationTestClass2.new
160
+ aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass,
161
+ :object => object, :method => :public_test_method) {true}
162
+ aspect.join_points_matched.size.should == 1
163
+ aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == Aquarium::AspectInvocationTestClass}
164
+ end
165
+
166
+ it "should ignore the :default_objects if at least one :pointcut is given and the :default_objects are objects." do
167
+ object = Aquarium::AspectInvocationTestClass.new
168
+ aspect = Aspect.new(:after, :default_objects => object,
169
+ :pointcut => {:type => Aquarium::AspectInvocationTestClass2, :method => :public_test_method}, :method => :public_test_method) {true}
170
+ aspect.join_points_matched.size.should == 1
171
+ aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == object}
172
+ end
173
+
174
+ it "should ignore the :default_objects if at least one :pointcut is given and the :default_objects are types." do
175
+ aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass,
176
+ :pointcut => {:type => Aquarium::AspectInvocationTestClass2, :method => :public_test_method}, :method => :public_test_method) {true}
177
+ aspect.join_points_matched.size.should == 1
178
+ aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == Aquarium::AspectInvocationTestClass}
179
+ end
180
+
181
+ it "should ignore the :default_objects if at least one :join_point is given and the :default_objects are objects." do
182
+ join_point = JoinPoint.new :type => Aquarium::AspectInvocationTestClass2, :method => :public_test_method
183
+ object = Aquarium::AspectInvocationTestClass.new
184
+ aspect = Aspect.new(:after, :default_objects => object, :join_point => join_point, :method => :public_test_method) {true}
185
+ aspect.join_points_matched.size.should == 1
186
+ aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == object}
187
+ end
188
+
189
+ it "should ignore the :default_objects if at least one :join_point is given and the :default_objects are types." do
190
+ join_point = JoinPoint.new :type => Aquarium::AspectInvocationTestClass2, :method => :public_test_method
191
+ aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass, :join_point => join_point, :method => :public_test_method) {true}
192
+ aspect.join_points_matched.size.should == 1
193
+ aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == Aquarium::AspectInvocationTestClass}
194
+ end
195
+
196
+ [:type, :type_and_descendents, :type_and_ancestors].each do |type_key|
197
+ it "should ignore the :default_objects if at least one :#{type_key} is given and the :default_objects are objects." do
198
+ object = Aquarium::AspectInvocationTestClass.new
199
+ aspect = Aspect.new(:after, :default_objects => object, type_key => Aquarium::AspectInvocationTestClass2, :method => :public_test_method, :method => :public_test_method) {true}
200
+ aspect.join_points_matched.size.should == 1
201
+ aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == object}
202
+ end
203
+
204
+ it "should ignore the :default_objects if at least one :#{type_key} is given and the :default_objects are types." do
205
+ aspect = Aspect.new(:after, :default_objects => Aquarium::AspectInvocationTestClass, type_key => Aquarium::AspectInvocationTestClass2, :method => :public_test_method, :method => :public_test_method) {true}
206
+ aspect.join_points_matched.size.should == 1
207
+ aspect.join_points_matched.each {|jp| jp.type_or_object.should_not == Aquarium::AspectInvocationTestClass}
208
+ end
130
209
  end
131
210
 
132
211
  Aspect::CANONICAL_OPTIONS["default_objects"].each do |key|
133
212
  it "should accept :#{key} as a synonym for :default_objects." do
134
- aspect = Aspect.new(:after, key.intern => Aquarium::AspectInvocationTestClass.new, :methods => :public_test_method, :noop => true) {|jp, obj, *args| true}
213
+ aspect = Aspect.new(:after, key.intern => Aquarium::AspectInvocationTestClass.new, :method => :public_test_method, :noop => true) {true}
135
214
  end
136
215
  end
137
216
 
138
217
  it "should not contain :pointcut(s) and either :type(s) or :object(s)." do
139
- lambda {Aspect.new(:after, :pointcuts => @pointcut_opts, :type => Aquarium::AspectInvocationTestClass, :methods => :public_test_method) {|jp, obj, *args| true}}.should raise_error(Aquarium::Utils::InvalidOptions)
140
- lambda {Aspect.new(:after, :pointcuts => @pointcut_opts, :object => Aquarium::AspectInvocationTestClass.new, :methods => :public_test_method) {|jp, obj, *args| true}}.should raise_error(Aquarium::Utils::InvalidOptions)
218
+ lambda {Aspect.new(:after, :pointcuts => @pointcut_opts, :type => Aquarium::AspectInvocationTestClass, :method => :public_test_method) {true}}.should raise_error(Aquarium::Utils::InvalidOptions)
219
+ lambda {Aspect.new(:after, :pointcuts => @pointcut_opts, :object => Aquarium::AspectInvocationTestClass.new, :method => :public_test_method) {true}}.should raise_error(Aquarium::Utils::InvalidOptions)
141
220
  end
142
221
  end
143
222
 
@@ -218,6 +297,18 @@ describe Aspect, "methods" do
218
297
  end
219
298
  end
220
299
 
300
+ it "should require the values for :reading => ... and :writing => ... to be equal if both are specified." do
301
+ @advice = Proc.new {}
302
+ lambda {Aspect.new :before, :type => Aquarium::AspectInvocationTestClass3,
303
+ :reading => :public_test_method_args, :writing => :public_test_method_args2, :advice => @advice}.should raise_error(Aquarium::Utils::InvalidOptions)
304
+ end
305
+
306
+ it "should require the values for :reading => ... and :changing => ... to be equal if both are specified." do
307
+ @advice = Proc.new {}
308
+ lambda {Aspect.new :before, :type => Aquarium::AspectInvocationTestClass3,
309
+ :reading => :public_test_method_args, :changing => :public_test_method_args2, :advice => @advice}.should raise_error(Aquarium::Utils::InvalidOptions)
310
+ end
311
+
221
312
  it "should accept :reading => ... as a synonym for :attributes => ..., :attribute_options => [:readers]." do
222
313
  @advice = Proc.new {}
223
314
  @expected_methods = [:public_test_method_args]
@@ -1283,12 +1374,11 @@ describe Aspect, "methods" do
1283
1374
  advice_called.should be_true
1284
1375
  aspect.unadvise
1285
1376
  end
1286
-
1287
1377
  end
1288
1378
 
1289
1379
  describe Aspect, ".new (advice block or proc parameter list)" do
1290
1380
  it "should raise unless an advice block or :advice => advice parameter is specified." do
1291
- lambda {Aspect.new(:after, :type => Aquarium::AspectInvocationTestClass, :methods => :public_test_method)}.should raise_error(Aquarium::Utils::InvalidOptions)
1381
+ lambda { Aspect.new(:after, :type => Aquarium::AspectInvocationTestClass, :methods => :public_test_method)}.should raise_error(Aquarium::Utils::InvalidOptions)
1292
1382
  end
1293
1383
 
1294
1384
  it "should raise if obsolete |jp, *args| list is used." do
@@ -1315,7 +1405,14 @@ describe Aspect, "methods" do
1315
1405
  lambda { Aspect.new :before, :type => Aquarium::AspectInvocationTestClass, :methods => :public_test_method, :noop => true do; end }.should_not raise_error(Exception)
1316
1406
  end
1317
1407
  end
1318
-
1408
+
1409
+ describe Aspect, ".new (advice block to around advice with just the join_point parameter - Bug #19262)" do
1410
+ it "should work not raise an error" do
1411
+ aspect = Aspect.new :around, :type => Aquarium::AspectInvocationTestClass, :methods => :public_test_method do |jp|; jp.proceed; end
1412
+ Aquarium::AspectInvocationTestClass.new.public_test_method
1413
+ aspect.unadvise
1414
+ end
1415
+ end
1319
1416
 
1320
1417
  class ExcludeBase
1321
1418
  def doit; end
@@ -220,6 +220,10 @@ describe Aspect, " with :after_returning advice" do
220
220
  end
221
221
  end
222
222
 
223
+ class MyError1 < StandardError; end
224
+ class MyError2 < StandardError; end
225
+ class MyError3 < StandardError; end
226
+
223
227
  describe Aspect, " with :after_raising advice" do
224
228
  after(:each) do
225
229
  @aspect.unadvise if @aspect
@@ -248,10 +252,39 @@ describe Aspect, " with :after_raising advice" do
248
252
  do_watchful_public_protected_private true
249
253
  end
250
254
 
251
- it "should not advise rescue clauses for raised exceptions of types that don't match the specified exception" do
252
- class MyError < StandardError; end
255
+ it "should invoke advice when exceptions of the specified type are raised" do
256
+ aspect_advice_invoked = false
257
+ @aspect = Aspect.new(:after_raising => Watchful::WatchfulError, :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
258
+ block_invoked = false
259
+ watchful = Watchful.new
260
+ lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
261
+ aspect_advice_invoked.should be_true
262
+ block_invoked.should be_true
263
+ end
264
+
265
+ it "should invoke advice when exceptions of the specified type are raised, which were specified with :exceptions => ..." do
266
+ aspect_advice_invoked = false
267
+ @aspect = Aspect.new(:after_raising, :exceptions => Watchful::WatchfulError, :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
268
+ block_invoked = false
269
+ watchful = Watchful.new
270
+ lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
271
+ aspect_advice_invoked.should be_true
272
+ block_invoked.should be_true
273
+ end
274
+
275
+ it "should not invoke advice when exceptions of types that don't match the specified exception type are raised" do
276
+ aspect_advice_invoked = false
277
+ @aspect = Aspect.new(:after_raising => MyError1, :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
278
+ block_invoked = false
279
+ watchful = Watchful.new
280
+ lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
281
+ aspect_advice_invoked.should be_false
282
+ block_invoked.should be_true
283
+ end
284
+
285
+ it "should not invoke advice when exceptions of types that don't match the specified exception type are raised, which were specified with :exceptions => ..." do
253
286
  aspect_advice_invoked = false
254
- @aspect = Aspect.new(:after_raising => MyError, :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
287
+ @aspect = Aspect.new(:after_raising, :exceptions => MyError1, :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
255
288
  block_invoked = false
256
289
  watchful = Watchful.new
257
290
  lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
@@ -259,9 +292,17 @@ describe Aspect, " with :after_raising advice" do
259
292
  block_invoked.should be_true
260
293
  end
261
294
 
262
- it "should not advise rescue clauses for raised exceptions of types that don't match the list of specified exceptions" do
263
- class MyError1 < StandardError; end
264
- class MyError2 < StandardError; end
295
+ it "should invoke advice when one exception in the list of the specified types is raised" do
296
+ aspect_advice_invoked = false
297
+ @aspect = Aspect.new(:after_raising => [Watchful::WatchfulError, MyError1], :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
298
+ block_invoked = false
299
+ watchful = Watchful.new
300
+ lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
301
+ aspect_advice_invoked.should be_true
302
+ block_invoked.should be_true
303
+ end
304
+
305
+ it "should not invoke advice when exceptions of types that don't match the specified list of exception types are raised" do
265
306
  aspect_advice_invoked = false
266
307
  @aspect = Aspect.new(:after_raising => [MyError1, MyError2], :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
267
308
  block_invoked = false
@@ -271,7 +312,33 @@ describe Aspect, " with :after_raising advice" do
271
312
  block_invoked.should be_true
272
313
  end
273
314
 
274
- it "should advise all rescue clauses in the matched methods, if no specific exceptions are specified" do
315
+ it "should not invoke advice when exceptions of types that don't match the specified list of exception types are raised, which were specified with :exceptions => ..." do
316
+ aspect_advice_invoked = false
317
+ @aspect = Aspect.new(:after_raising, :exceptions => [MyError1, MyError2], :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
318
+ block_invoked = false
319
+ watchful = Watchful.new
320
+ lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
321
+ aspect_advice_invoked.should be_false
322
+ block_invoked.should be_true
323
+ end
324
+
325
+ it "should treat :exception as a synonym for :exceptions" do
326
+ aspect_advice_invoked = false
327
+ @aspect = Aspect.new(:after_raising, :exception => [MyError1, MyError2], :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
328
+ block_invoked = false
329
+ watchful = Watchful.new
330
+ lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
331
+ aspect_advice_invoked.should be_false
332
+ block_invoked.should be_true
333
+ end
334
+
335
+ it "should merge exceptions specified with :exception(s) and :after_raising" do
336
+ aspect_advice_invoked = false
337
+ @aspect = Aspect.new(:after_raising => MyError1, :exception => [MyError2, MyError3], :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, obj, *args| aspect_advice_invoked = true}
338
+ @aspect.specification[:after_raising].should eql(Set.new([MyError1, MyError2, MyError3]))
339
+ end
340
+
341
+ it "should advise all methods that raise exceptions when no specific exceptions are specified" do
275
342
  class ClassThatRaises
276
343
  class CTRException < Exception; end
277
344
  def raises
@@ -287,6 +354,23 @@ describe Aspect, " with :after_raising advice" do
287
354
  lambda {ctr.raises}.should raise_error(ClassThatRaises::CTRException)
288
355
  aspect_advice_invoked.should be_true
289
356
  end
357
+
358
+ it "should advise all methods that raise strings (which are converted to RuntimeError) when no specific exceptions are specified" do
359
+ class ClassThatRaisesString
360
+ class CTRException < Exception; end
361
+ def raises
362
+ raise "A string exception."
363
+ end
364
+ end
365
+ aspect_advice_invoked = false
366
+ @aspect = Aspect.new :after_raising, :pointcut => {:type => ClassThatRaisesString, :methods => :raises} do |jp, obj, *args|
367
+ aspect_advice_invoked = true
368
+ end
369
+ aspect_advice_invoked.should be_false
370
+ ctr = ClassThatRaisesString.new
371
+ lambda {ctr.raises}.should raise_error(RuntimeError)
372
+ aspect_advice_invoked.should be_true
373
+ end
290
374
  end
291
375
 
292
376
  describe Aspect, " with :before and :after advice" do
@@ -365,6 +365,67 @@ describe Pointcut, "methods" do
365
365
  end
366
366
  end
367
367
 
368
+ describe Pointcut, ".new (default_objects specified)" do
369
+ it "should use the :default_objects if specified and no other :join_point, :type, or :object is given." do
370
+ object1 = ClassWithPublicInstanceMethod.new
371
+ pc = Pointcut.new :default_objects => object1, :method => :public_instance_test_method
372
+ pc.join_points_matched.size.should == 1
373
+ pc.join_points_matched.each {|jp| jp.type_or_object.should == object1}
374
+ end
375
+
376
+ it "should ignore the :default_objects if at least one other :object is given and the :default_objects are objects." do
377
+ object1 = ClassWithPublicInstanceMethod.new
378
+ object2 = ClassWithPublicInstanceMethod.new
379
+ pc = Pointcut.new :default_objects => object1, :object => object2, :method => :public_instance_test_method
380
+ pc.join_points_matched.size.should == 1
381
+ pc.join_points_matched.each {|jp| jp.type_or_object.should == object2}
382
+ end
383
+
384
+ it "should ignore the :default_objects if at least one other :object is given and the :default_objects are types." do
385
+ object = ClassWithProtectedInstanceMethod.new
386
+ pc = Pointcut.new :default_objects => ClassWithPublicInstanceMethod, :object => object, :method => /_instance_test_method/, :method_options => [:public, :protected, :exclude_ancestor_methods]
387
+ pc.join_points_matched.size.should == 1
388
+ pc.join_points_matched.each {|jp| jp.type_or_object.should_not == ClassWithPublicInstanceMethod}
389
+ end
390
+
391
+ it "should ignore the :default_objects if at least one :join_point is given and the :default_objects are objects." do
392
+ join_point = JoinPoint.new :type => ClassWithProtectedInstanceMethod, :method => :protected_instance_test_method
393
+ object = ClassWithProtectedInstanceMethod.new
394
+ pc = Pointcut.new :default_objects => object, :join_point => join_point, :method => /_instance_test_method/, :method_options => [:public, :protected, :exclude_ancestor_methods]
395
+ pc.join_points_matched.size.should == 1
396
+ pc.join_points_matched.each {|jp| jp.type_or_object.should_not == ClassWithPublicInstanceMethod}
397
+ end
398
+
399
+ it "should ignore the :default_objects if at least one :pointcut is given and the :default_objects are types." do
400
+ join_point = JoinPoint.new :type => ClassWithProtectedInstanceMethod, :method => :protected_instance_test_method
401
+ object = ClassWithProtectedInstanceMethod.new
402
+ pc = Pointcut.new :default_objects => ClassWithPublicInstanceMethod, :join_point => join_point, :method => /_instance_test_method/, :method_options => [:public, :protected, :exclude_ancestor_methods]
403
+ pc.join_points_matched.size.should == 1
404
+ pc.join_points_matched.each {|jp| jp.type_or_object.should_not == ClassWithPublicInstanceMethod}
405
+ end
406
+
407
+ [:type, :type_and_descendents, :type_and_ancestors].each do |type_key|
408
+ it "should ignore the :default_objects if at least one :#{type_key} is given and the :default_objects are objects." do
409
+ object = ClassWithPublicInstanceMethod.new
410
+ pc = Pointcut.new :default_objects => object, type_key => ClassWithProtectedInstanceMethod, :method => /_instance_test_method/, :method_options => [:public, :protected, :exclude_ancestor_methods]
411
+ pc.join_points_matched.size.should == 1
412
+ pc.join_points_matched.each {|jp| jp.type_or_object.should_not == ClassWithPublicInstanceMethod}
413
+ end
414
+
415
+ it "should ignore the :default_objects if at least one :#{type_key} is given and the :default_objects are types." do
416
+ pc = Pointcut.new :default_objects => ClassWithPublicInstanceMethod, type_key => ClassWithProtectedInstanceMethod, :method => /_instance_test_method/, :method_options => [:public, :protected, :exclude_ancestor_methods]
417
+ pc.join_points_matched.size.should == 1
418
+ pc.join_points_matched.each {|jp| jp.type_or_object.should_not == ClassWithPublicInstanceMethod}
419
+ end
420
+ end
421
+
422
+ Aspect::CANONICAL_OPTIONS["default_objects"].each do |key|
423
+ it "should accept :#{key} as a synonym for :default_objects." do
424
+ pc = Pointcut.new key.intern => ClassWithPublicInstanceMethod.new, :method => :public_instance_test_method
425
+ end
426
+ end
427
+ end
428
+
368
429
  describe Pointcut, ".new (:exclude_types => types specified)" do
369
430
  before(:each) do
370
431
  before_exclude_spec
@@ -1,12 +1,12 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
2
- require File.dirname(__FILE__) + '/../../spec_example_types'
3
- require 'aquarium/aspects/dsl/aspect_dsl'
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require File.dirname(__FILE__) + '/../spec_example_types'
3
+ require 'aquarium/dsl/aspect_dsl'
4
4
 
5
5
  class DSLClass
6
- include Aquarium::Aspects::DSL::AspectDSL
6
+ include Aquarium::DSL
7
7
  end
8
8
 
9
- describe "Aquarium::Aspects::DSL::AspectDSL" do
9
+ describe "Aquarium::DSL" do
10
10
  before :all do
11
11
  @advice = proc {|jp, obj, *args| "advice"}
12
12
  @pointcut_opts = {:calls_to => :public_watchful_method, :in_type => Watchful}
@@ -20,7 +20,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
20
20
  @aspects.each {|a| a.unadvise}
21
21
  end
22
22
 
23
- it "should be equivalent to advise :before." do
23
+ it "should be equivalent to advice kind :before." do
24
24
  @aspects << DSLClass.advise(:before, :noop => true, :pointcut => @pointcut_opts, &@advice)
25
25
  @aspects << DSLClass.before( :noop => true, :pointcut => @pointcut_opts, &@advice)
26
26
  @aspects[1].should == @aspects[0]
@@ -35,13 +35,36 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
35
35
  @aspects.each {|a| a.unadvise}
36
36
  end
37
37
 
38
- it "should be equivalent to advise :after." do
38
+ it "should be equivalent to advice kind :after." do
39
39
  @aspects << DSLClass.advise(:after, :noop => true, :pointcut => @pointcut_opts, &@advice)
40
40
  @aspects << DSLClass.after( :noop => true, :pointcut => @pointcut_opts, &@advice)
41
41
  @aspects[1].should == @aspects[0]
42
42
  end
43
43
  end
44
44
 
45
+ describe "DSL method #after_raising" do
46
+ before :each do
47
+ @aspects = []
48
+ end
49
+ after :each do
50
+ @aspects.each {|a| a.unadvise}
51
+ end
52
+
53
+ it "should be equivalent to advice kind :after_raising." do
54
+ @aspects << DSLClass.advise(:after_raising, :noop => true, :pointcut => @pointcut_opts, &@advice)
55
+ @aspects << DSLClass.after_raising( :noop => true, :pointcut => @pointcut_opts, &@advice)
56
+ @aspects[1].should == @aspects[0]
57
+ end
58
+
59
+ it "should be equivalent to advice kind :after_raising => exceptions, when used with the :exceptions argument." do
60
+ @aspects << DSLClass.advise(:after_raising, :exceptions => [StandardError], :noop => true, :pointcut => @pointcut_opts, &@advice)
61
+ @aspects << DSLClass.after_raising( :exceptions => [StandardError], :noop => true, :pointcut => @pointcut_opts, &@advice)
62
+ @aspects << Aquarium::Aspects::Aspect.new(:after_raising => [StandardError], :noop => true, :pointcut => @pointcut_opts, &@advice)
63
+ @aspects[1].should == @aspects[0]
64
+ @aspects[2].specification[:after_raising].should == @aspects[0].specification[:after_raising]
65
+ end
66
+ end
67
+
45
68
  describe "DSL method #after_raising_within_or_returning_from" do
46
69
  before :each do
47
70
  @dsl = DSLClass.new
@@ -52,7 +75,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
52
75
  @aspects.each {|a| a.unadvise}
53
76
  end
54
77
 
55
- it "should be equivalent to advise :after." do
78
+ it "should be equivalent to advice kind :after." do
56
79
  @aspects << DSLClass.after( :noop => true, :pointcut => @pointcut_opts, &@advice)
57
80
  @aspects << DSLClass.after_raising_within_or_returning_from(:noop => true, :pointcut => @pointcut_opts, &@advice)
58
81
  @aspects[1].should == @aspects[0]
@@ -69,7 +92,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
69
92
  @aspects.each {|a| a.unadvise}
70
93
  end
71
94
 
72
- it "should be equivalent to advise :after_returning." do
95
+ it "should be equivalent to advice kind :after_returning." do
73
96
  @aspects << DSLClass.advise(:after_returning, :noop => true, :pointcut => @pointcut_opts, &@advice)
74
97
  @aspects << DSLClass.after_returning( :noop => true, :pointcut => @pointcut_opts, &@advice)
75
98
  @aspects[1].should == @aspects[0]
@@ -86,7 +109,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
86
109
  @aspects.each {|a| a.unadvise}
87
110
  end
88
111
 
89
- it "should be equivalent to advise :after_returning." do
112
+ it "should be equivalent to advice kind :after_returning." do
90
113
  @aspects << DSLClass.advise(:after_returning, :noop => true, :pointcut => @pointcut_opts, &@advice)
91
114
  @aspects << DSLClass.after_returning_from( :noop => true, :pointcut => @pointcut_opts, &@advice)
92
115
  @aspects[1].should == @aspects[0]
@@ -103,7 +126,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
103
126
  @aspects.each {|a| a.unadvise}
104
127
  end
105
128
 
106
- it "should be equivalent to advise :after_raising." do
129
+ it "should be equivalent to advice kind :after_raising." do
107
130
  class ThrowsUp
108
131
  def tosses_cookies *args; raise Exception.new(args.inspect); end
109
132
  end
@@ -123,7 +146,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
123
146
  @aspects.each {|a| a.unadvise}
124
147
  end
125
148
 
126
- it "should be equivalent to advise :after_raising." do
149
+ it "should be equivalent to advice kind :after_raising." do
127
150
  class ThrowsUp
128
151
  def tosses_cookies *args; raise Exception.new(args.inspect); end
129
152
  end
@@ -143,7 +166,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
143
166
  @aspects.each {|a| a.unadvise}
144
167
  end
145
168
 
146
- it "should be equivalent to advise :before, :after." do
169
+ it "should be equivalent to advice kind :before, :after." do
147
170
  @aspects << DSLClass.advise(:before, :after, :noop => true, :pointcut => @pointcut_opts, &@advice)
148
171
  @aspects << DSLClass.before_and_after( :noop => true, :pointcut => @pointcut_opts, &@advice)
149
172
  @aspects[1].should == @aspects[0]
@@ -160,7 +183,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
160
183
  @aspects.each {|a| a.unadvise}
161
184
  end
162
185
 
163
- it "should be equivalent to advise :before and advise :after." do
186
+ it "should be equivalent to advice kind :before and advice :after." do
164
187
  @aspects << DSLClass.advise(:before, :after, :noop => true, :pointcut => @pointcut_opts, &@advice)
165
188
  @aspects << DSLClass.before_and_after_raising_within_or_returning_from(:noop => true, :pointcut => @pointcut_opts, &@advice)
166
189
  @aspects[1].should == @aspects[0]
@@ -177,7 +200,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
177
200
  @aspects.each {|a| a.unadvise}
178
201
  end
179
202
 
180
- it "should be equivalent to advise :before and advise :after_returning." do
203
+ it "should be equivalent to advice kind :before and advice :after_returning." do
181
204
  @aspects << DSLClass.advise(:before, :after_returning, :noop => true, :pointcut => @pointcut_opts, &@advice)
182
205
  @aspects << DSLClass.before_and_after_returning( :noop => true, :pointcut => @pointcut_opts, &@advice)
183
206
  @aspects[1].should == @aspects[0]
@@ -194,7 +217,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
194
217
  @aspects.each {|a| a.unadvise}
195
218
  end
196
219
 
197
- it "should be equivalent to advise :before and advise :after_returning." do
220
+ it "should be equivalent to advice kind :before and advice :after_returning." do
198
221
  @aspects << DSLClass.advise(:before, :after_returning, :noop => true, :pointcut => @pointcut_opts, &@advice)
199
222
  @aspects << DSLClass.before_and_after_returning_from( :noop => true, :pointcut => @pointcut_opts, &@advice)
200
223
  @aspects[1].should == @aspects[0]
@@ -211,7 +234,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
211
234
  @aspects.each {|a| a.unadvise}
212
235
  end
213
236
 
214
- it "should be equivalent to advise :before and advise :after_raising." do
237
+ it "should be equivalent to advice kind :before and advice :after_raising." do
215
238
  @aspects << DSLClass.advise(:before, :after_raising, :noop => true, :pointcut => @pointcut_opts, &@advice)
216
239
  @aspects << DSLClass.before_and_after_raising( :noop => true, :pointcut => @pointcut_opts, &@advice)
217
240
  @aspects[1].should == @aspects[0]
@@ -228,7 +251,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
228
251
  @aspects.each {|a| a.unadvise}
229
252
  end
230
253
 
231
- it "should be equivalent to advise :around." do
254
+ it "should be equivalent to advice kind :around." do
232
255
  @aspects << DSLClass.advise(:around, :noop => true, :pointcut => @pointcut_opts, &@advice)
233
256
  @aspects << DSLClass.around( :noop => true, :pointcut => @pointcut_opts, &@advice)
234
257
  @aspects[1].should == @aspects[0]
@@ -245,7 +268,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
245
268
 
246
269
  it "should ignore the default object \"self\" when an :object is specified." do
247
270
  class Watchful1
248
- include Aquarium::Aspects::DSL::AspectDSL
271
+ include Aquarium::DSL
249
272
  def public_watchful_method; end
250
273
  @@watchful = Watchful1.new
251
274
  @@aspect = after(:invoking => :public_watchful_method, :on_object => @@watchful) {|jp, obj, *args|}
@@ -261,7 +284,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
261
284
 
262
285
  it "should ignore the default object \"self\" when a :type is specified." do
263
286
  class Watchful2
264
- include Aquarium::Aspects::DSL::AspectDSL
287
+ include Aquarium::DSL
265
288
  def public_watchful_method; end
266
289
  @@aspect = after(:calls_to => :public_watchful_method, :in_type => Watchful2) {|jp, obj, *args|}
267
290
  def self.aspect; @@aspect; end
@@ -282,7 +305,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
282
305
  end
283
306
 
284
307
  class WatchfulSelf
285
- include Aquarium::Aspects::DSL::AspectDSL
308
+ include Aquarium::DSL
286
309
  @@aspect = nil
287
310
  def self.aspect; @@aspect; end
288
311
  def public_watchful_method; "public_watchful_method"; end
@@ -300,7 +323,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
300
323
 
301
324
  it "should infer the object as \"self\" when no :object, :type, or :pointcut is specified." do
302
325
  watchful_self = WatchfulSelf.new
303
- watchful_self.extend Aquarium::Aspects::DSL::AspectDSL
326
+ watchful_self.extend Aquarium::DSL
304
327
  @aspects << WatchfulSelf.advise(:after, :pointcut => {:invoking => :public_watchful_method, :on_object => watchful_self}) {|jp, obj, *args|}
305
328
  @aspects << watchful_self.after(:method => :public_watchful_method) {|jp, obj, *args|}
306
329
  @aspects[1].join_points_matched.should == @aspects[0].join_points_matched
@@ -314,7 +337,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
314
337
 
315
338
  describe "DSL method #advise, when parsing the parameter list," do
316
339
  class Watchful3
317
- include Aquarium::Aspects::DSL::AspectDSL
340
+ include Aquarium::DSL
318
341
  def public_watchful_method; "public_watchful_method"; end
319
342
  end
320
343
 
@@ -344,7 +367,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
344
367
 
345
368
  it "should treat \"ClassName.advise\" as advising instance methods, by default." do
346
369
  class WatchfulExampleWithSeparateAdviseCall
347
- include Aquarium::Aspects::DSL::AspectDSL
370
+ include Aquarium::DSL
348
371
  def public_watchful_method *args; end
349
372
  end
350
373
  advice_called = 0
@@ -358,7 +381,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
358
381
 
359
382
  it "should treat \"ClassName.advise\" as advising instance methods when the :instance method option is specified." do
360
383
  class WatchfulExampleWithSeparateAdviseCall2
361
- include Aquarium::Aspects::DSL::AspectDSL
384
+ include Aquarium::DSL
362
385
  def self.class_public_watchful_method *args; end
363
386
  def public_watchful_method *args; end
364
387
  end
@@ -376,7 +399,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
376
399
 
377
400
  it "should treat \"ClassName.advise\" as advising class methods when the :class method option is specified." do
378
401
  class WatchfulExampleWithSeparateAdviseCall3
379
- include Aquarium::Aspects::DSL::AspectDSL
402
+ include Aquarium::DSL
380
403
  def self.class_public_watchful_method *args; end
381
404
  def public_watchful_method *args; end
382
405
  end
@@ -394,7 +417,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
394
417
 
395
418
  it "should invoke the type-based advise for all objects when the aspect is defined by calling #advise within the class definition." do
396
419
  class WatchfulExampleWithBeforeAdvice
397
- include Aquarium::Aspects::DSL::AspectDSL
420
+ include Aquarium::DSL
398
421
  @@advice_called = 0
399
422
  def public_watchful_method *args; end
400
423
  before :public_watchful_method do |jp, obj, *args|
@@ -410,7 +433,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
410
433
 
411
434
  describe "DSL methods for the advice kind, when determining instance or class methods to advise," do
412
435
  class Watchful4
413
- include Aquarium::Aspects::DSL::AspectDSL
436
+ include Aquarium::DSL
414
437
  def public_watchful_method; "public_watchful_method"; end
415
438
  end
416
439
 
@@ -490,7 +513,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
490
513
  describe "DSL method #advise (or synonyms) called within a type body" do
491
514
  it "will not advise a method whose definition hasn't been seen yet in the type body." do
492
515
  class WatchfulWithMethodAlreadyDefined
493
- include Aquarium::Aspects::DSL::AspectDSL
516
+ include Aquarium::DSL
494
517
  @@advice_called = 0
495
518
  def public_watchful_method *args; end
496
519
  before :public_watchful_method do |jp, obj, *args|
@@ -502,7 +525,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
502
525
  WatchfulWithMethodAlreadyDefined.new.public_watchful_method :a3, :a4
503
526
  WatchfulWithMethodAlreadyDefined.advice_called.should == 2
504
527
  class WatchfulWithMethodNotYetDefined
505
- include Aquarium::Aspects::DSL::AspectDSL
528
+ include Aquarium::DSL
506
529
  @@advice_called = 0
507
530
  before(:public_watchful_method, :ignore_no_matching_join_points=>true) {|jp, obj, *args| @@advice_called += 1}
508
531
  def public_watchful_method *args; end
@@ -528,7 +551,7 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
528
551
 
529
552
  it "should use self as the object if no object or type is specified." do
530
553
  class PC2
531
- include Aquarium::Aspects::DSL::AspectDSL
554
+ include Aquarium::DSL
532
555
  POINTCUT = pointcut :method => :doit
533
556
  end
534
557
  pointcut2 = Aquarium::Aspects::Pointcut.new :type => PC2, :method => :doit
@@ -536,4 +559,25 @@ describe "Aquarium::Aspects::DSL::AspectDSL" do
536
559
  PC2::POINTCUT.join_points_not_matched.should == pointcut2.join_points_not_matched
537
560
  end
538
561
  end
539
- end
562
+
563
+ class OldDSLClass
564
+ include Aquarium::Aspects::DSL::AspectDSL
565
+ end
566
+ describe "DSL methods available through the old package Aquarium::Aspects::DSL::AspectDSL" do
567
+ before :each do
568
+ @dsl = OldDSLClass.new
569
+ @advice = proc {|jp, obj, *args| "advice"}
570
+ @aspects = []
571
+ end
572
+ after :each do
573
+ @aspects.each {|a| a.unadvise}
574
+ end
575
+
576
+ it "should be equivalent to advice kind :around." do
577
+ @aspects << OldDSLClass.advise(:around, :noop => true, :pointcut => @pointcut_opts, &@advice)
578
+ @aspects << OldDSLClass.around( :noop => true, :pointcut => @pointcut_opts, &@advice)
579
+ @aspects[1].should == @aspects[0]
580
+ end
581
+ end
582
+ end
583
+