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.
Files changed (80) hide show
  1. data/CHANGES +4 -0
  2. data/EXAMPLES.rd +4 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README +250 -0
  5. data/RELEASE-PLAN +1 -0
  6. data/Rakefile +236 -0
  7. data/UPGRADE +3 -0
  8. data/examples/aspect_design_example.rb +36 -0
  9. data/examples/design_by_contract_example.rb +88 -0
  10. data/examples/method_missing_example.rb +44 -0
  11. data/examples/method_tracing_example.rb +64 -0
  12. data/lib/aquarium.rb +7 -0
  13. data/lib/aquarium/aspects.rb +6 -0
  14. data/lib/aquarium/aspects/advice.rb +189 -0
  15. data/lib/aquarium/aspects/aspect.rb +577 -0
  16. data/lib/aquarium/aspects/default_object_handler.rb +27 -0
  17. data/lib/aquarium/aspects/dsl.rb +1 -0
  18. data/lib/aquarium/aspects/dsl/aspect_dsl.rb +61 -0
  19. data/lib/aquarium/aspects/join_point.rb +158 -0
  20. data/lib/aquarium/aspects/pointcut.rb +254 -0
  21. data/lib/aquarium/aspects/pointcut_composition.rb +36 -0
  22. data/lib/aquarium/extensions.rb +5 -0
  23. data/lib/aquarium/extensions/hash.rb +85 -0
  24. data/lib/aquarium/extensions/regexp.rb +20 -0
  25. data/lib/aquarium/extensions/set.rb +49 -0
  26. data/lib/aquarium/extensions/string.rb +13 -0
  27. data/lib/aquarium/extensions/symbol.rb +22 -0
  28. data/lib/aquarium/extras.rb +4 -0
  29. data/lib/aquarium/extras/design_by_contract.rb +64 -0
  30. data/lib/aquarium/finders.rb +4 -0
  31. data/lib/aquarium/finders/finder_result.rb +121 -0
  32. data/lib/aquarium/finders/method_finder.rb +228 -0
  33. data/lib/aquarium/finders/object_finder.rb +74 -0
  34. data/lib/aquarium/finders/type_finder.rb +127 -0
  35. data/lib/aquarium/utils.rb +9 -0
  36. data/lib/aquarium/utils/array_utils.rb +29 -0
  37. data/lib/aquarium/utils/hash_utils.rb +28 -0
  38. data/lib/aquarium/utils/html_escaper.rb +17 -0
  39. data/lib/aquarium/utils/invalid_options.rb +9 -0
  40. data/lib/aquarium/utils/method_utils.rb +18 -0
  41. data/lib/aquarium/utils/nil_object.rb +13 -0
  42. data/lib/aquarium/utils/set_utils.rb +32 -0
  43. data/lib/aquarium/version.rb +30 -0
  44. data/rake_tasks/examples.rake +7 -0
  45. data/rake_tasks/examples_specdoc.rake +8 -0
  46. data/rake_tasks/examples_with_rcov.rake +8 -0
  47. data/rake_tasks/verify_rcov.rake +7 -0
  48. data/spec/aquarium/aspects/advice_chain_node_spec.rb +34 -0
  49. data/spec/aquarium/aspects/advice_spec.rb +103 -0
  50. data/spec/aquarium/aspects/aspect_invocation_spec.rb +111 -0
  51. data/spec/aquarium/aspects/aspect_spec.rb +978 -0
  52. data/spec/aquarium/aspects/aspect_with_nested_types_spec.rb +129 -0
  53. data/spec/aquarium/aspects/concurrent_aspects_spec.rb +423 -0
  54. data/spec/aquarium/aspects/concurrent_aspects_with_objects_and_types_spec.rb +103 -0
  55. data/spec/aquarium/aspects/concurrently_accessed.rb +21 -0
  56. data/spec/aquarium/aspects/dsl/aspect_dsl_spec.rb +514 -0
  57. data/spec/aquarium/aspects/join_point_spec.rb +302 -0
  58. data/spec/aquarium/aspects/pointcut_and_composition_spec.rb +131 -0
  59. data/spec/aquarium/aspects/pointcut_or_composition_spec.rb +111 -0
  60. data/spec/aquarium/aspects/pointcut_spec.rb +800 -0
  61. data/spec/aquarium/extensions/hash_spec.rb +187 -0
  62. data/spec/aquarium/extensions/regex_spec.rb +40 -0
  63. data/spec/aquarium/extensions/set_spec.rb +105 -0
  64. data/spec/aquarium/extensions/string_spec.rb +25 -0
  65. data/spec/aquarium/extensions/symbol_spec.rb +37 -0
  66. data/spec/aquarium/extras/design_by_contract_spec.rb +68 -0
  67. data/spec/aquarium/finders/finder_result_spec.rb +359 -0
  68. data/spec/aquarium/finders/method_finder_spec.rb +878 -0
  69. data/spec/aquarium/finders/method_sorting_spec.rb +16 -0
  70. data/spec/aquarium/finders/object_finder_spec.rb +230 -0
  71. data/spec/aquarium/finders/type_finder_spec.rb +210 -0
  72. data/spec/aquarium/spec_example_classes.rb +117 -0
  73. data/spec/aquarium/spec_helper.rb +3 -0
  74. data/spec/aquarium/utils/array_utils_spec.rb +47 -0
  75. data/spec/aquarium/utils/hash_utils_spec.rb +48 -0
  76. data/spec/aquarium/utils/html_escaper_spec.rb +18 -0
  77. data/spec/aquarium/utils/method_utils_spec.rb +50 -0
  78. data/spec/aquarium/utils/nil_object_spec.rb +19 -0
  79. data/spec/aquarium/utils/set_utils_spec.rb +60 -0
  80. metadata +132 -0
@@ -0,0 +1,129 @@
1
+
2
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
3
+ require File.dirname(__FILE__) + '/../spec_example_classes'
4
+ require 'aquarium/aspects'
5
+
6
+ include Aquarium::Aspects
7
+
8
+ # Explicitly check that nested types are handled correctly.
9
+
10
+ module Nested1
11
+ module Nested2
12
+ class MyClass
13
+ def do1 *args
14
+ yield
15
+ end
16
+ end
17
+
18
+ module MyModule
19
+ def do2 *args
20
+ yield
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ describe Aspect, "#new when advising methods in a nested class" do
27
+ after(:each) do
28
+ @aspect.unadvise if @aspect
29
+ end
30
+
31
+ it "should correctly advise methods in a nested class." do
32
+ myclass = Nested1::Nested2::MyClass.new
33
+ context = nil
34
+ @aspect = Aspect.new :before, :pointcut => {:type => Nested1::Nested2::MyClass, :methods => :do1} do |jp, *args|
35
+ context = jp.context
36
+ end
37
+ block_called = 0
38
+ myclass.do1(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }
39
+ block_called.should == 1
40
+ context.advice_kind.should == :before
41
+ context.advised_object.should == myclass
42
+ context.parameters.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
43
+ context.returned_value.should == nil
44
+ context.raised_exception.should == nil
45
+ end
46
+
47
+ it "should correctly advise methods in an instance of the nested class." do
48
+ myclass = Nested1::Nested2::MyClass.new
49
+ context = nil
50
+ @aspect = Aspect.new :before, :pointcut => {:object => myclass, :methods => :do1} do |jp, *args|
51
+ context = jp.context
52
+ end
53
+ block_called = 0
54
+ myclass.do1(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }
55
+ block_called.should == 1
56
+ context.advice_kind.should == :before
57
+ context.advised_object.should == myclass
58
+ context.parameters.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
59
+ context.returned_value.should == nil
60
+ context.raised_exception.should == nil
61
+ end
62
+ end
63
+
64
+ describe Aspect, "#new when advising methods in a nested module included by a class" do
65
+ after(:each) do
66
+ @aspect.unadvise if @aspect
67
+ end
68
+
69
+ it "should correctly advise the module's methods when the nested module is specified." do
70
+ class MyClassWithModule1
71
+ include Nested1::Nested2::MyModule
72
+ end
73
+
74
+ myclass = MyClassWithModule1.new
75
+ context = nil
76
+ @aspect = Aspect.new :before, :pointcut => {:type => Nested1::Nested2::MyModule, :methods => :do2} do |jp, *args|
77
+ context = jp.context
78
+ end
79
+ block_called = 0
80
+ myclass.do2(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }
81
+ block_called.should == 1
82
+ context.advice_kind.should == :before
83
+ context.advised_object.should == myclass
84
+ context.parameters.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
85
+ context.returned_value.should == nil
86
+ context.raised_exception.should == nil
87
+ end
88
+
89
+ it "should correctly advise the module's methods when the class is specified." do
90
+ class MyClassWithModule2
91
+ include Nested1::Nested2::MyModule
92
+ end
93
+
94
+ myclass = MyClassWithModule2.new
95
+ context = nil
96
+ @aspect = Aspect.new :before, :pointcut => {:type => MyClassWithModule2, :methods => :do2} do |jp, *args|
97
+ context = jp.context
98
+ end
99
+ block_called = 0
100
+ myclass.do2(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }
101
+ block_called.should == 1
102
+ context.advice_kind.should == :before
103
+ context.advised_object.should == myclass
104
+ context.parameters.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
105
+ context.returned_value.should == nil
106
+ context.raised_exception.should == nil
107
+ end
108
+
109
+ it "should correctly advise the module's methods when an instance of the class is specified." do
110
+ class MyClassWithModule3
111
+ include Nested1::Nested2::MyModule
112
+ end
113
+
114
+ myclass = MyClassWithModule3.new
115
+ context = nil
116
+ @aspect = Aspect.new :before, :pointcut => {:object => myclass, :methods => :do2} do |jp, *args|
117
+ context = jp.context
118
+ end
119
+ block_called = 0
120
+ myclass.do2(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }
121
+ block_called.should == 1
122
+ context.advice_kind.should == :before
123
+ context.advised_object.should == myclass
124
+ context.parameters.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
125
+ context.returned_value.should == nil
126
+ context.raised_exception.should == nil
127
+ end
128
+ end
129
+
@@ -0,0 +1,423 @@
1
+ # Specifically tests behavior when two or more advices apply to the same join point(s).
2
+
3
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
4
+ require File.dirname(__FILE__) + '/../spec_example_classes'
5
+ require File.dirname(__FILE__) + '/concurrently_accessed'
6
+ require 'aquarium/aspects'
7
+
8
+ module ConcurrentAspectsSpecSupport
9
+ def add_m_then_remove_n_aspects_and_run iteration, for_type
10
+ reset_attrs
11
+ add_all_aspects_then_unadvise iteration, for_type
12
+ invoke
13
+ check_results_for iteration
14
+ unadvise_remaining iteration
15
+ end
16
+
17
+ def reset_attrs
18
+ @contexts = []
19
+ @argss = []
20
+ @aspects = []
21
+ @advice_invocation_counts = []
22
+ @accessed = nil
23
+ end
24
+
25
+ def add_all_aspects_then_unadvise number_to_unadvise, for_type
26
+ @accessed = ConcurrentlyAccessed.new
27
+ @advice_kinds.size.times do |n|
28
+ make_aspect_for_index n, for_type
29
+ end
30
+ number_to_unadvise.times {|n| @aspects[n].unadvise}
31
+ end
32
+
33
+ def invoke accessed = @accessed, advice_kinds = @advice_kinds
34
+ advice_kinds.size.times do |n|
35
+ (advice_kinds[n] == :after_raising) ? do_invoke_raises(accessed) : do_invoke(accessed)
36
+ end
37
+ end
38
+
39
+ def do_invoke_raises accessed
40
+ lambda {accessed.invoke_raises :a1, :a2}.should raise_error(ConcurrentlyAccessed::Error)
41
+ end
42
+
43
+ def do_invoke accessed
44
+ accessed.invoke :a1, :a2
45
+ end
46
+
47
+ def check_results_for iteration
48
+ number_of_unadvised_aspects = iteration + 1
49
+ @accessed.invoked_count.should == @aspects.size
50
+ @accessed.invoked_args.should == [:a1, :a2]
51
+ iteration.times do |n|
52
+ @advice_invocation_counts[n].should == 0
53
+ @contexts[n].should be_nil
54
+ @argss[n].should be_nil
55
+ end
56
+ (@aspects.size - iteration).times do |n|
57
+ n2 = n + iteration
58
+ @advice_invocation_counts[n2].should == expected_number_of_advice_invocations(@advice_kinds, n2)
59
+ @contexts[n2].should_not be_nil
60
+ @argss[n2].should == [:a1, :a2]
61
+ end
62
+ end
63
+
64
+ def unadvise_remaining number_to_unadvise
65
+ (@aspects.size - number_to_unadvise).times {|n| @aspects[n + number_to_unadvise].unadvise}
66
+ end
67
+
68
+ def make_aspect_for_index n, for_type
69
+ method = @advice_kinds[n] == :after_raising ? :invoke_raises : :invoke
70
+ @advice_invocation_counts[n] = 0
71
+ if for_type
72
+ pointcut = Aquarium::Aspects::Pointcut.new(:methods => method, :type => ConcurrentlyAccessed)
73
+ else
74
+ pointcut = Aquarium::Aspects::Pointcut.new(:methods => method, :object => @accessed)
75
+ end
76
+ @aspects[n] = advise @advice_kinds[n], :pointcut => pointcut do |jp, *args|
77
+ @contexts[n] = jp.context
78
+ @argss[n] = *args
79
+ @advice_invocation_counts[n] += 1
80
+ jp.proceed if @advice_kinds[n] == :around
81
+ end
82
+ end
83
+
84
+ # Because after_raising advice is invoked by calling ConcurrentlyAccessed#invoke_raises
85
+ # instead of ConcurrentlyAccessed#invoke, we get a lower count, due to non-overlapping JPs.
86
+ def expected_number_of_advice_invocations advice_kinds, n
87
+ advice_kinds.size - after_raising_factor(advice_kinds, n)
88
+ end
89
+
90
+ def after_raising_factor advice_kinds, n
91
+ raising, not_raising = advice_kinds.partition {|x| x == :after_raising}
92
+ total = advice_kinds.size
93
+ total - ((advice_kinds[n] == :after_raising) ? raising.size : not_raising.size)
94
+ end
95
+ end
96
+
97
+ describe "concurrent advice", :shared => true do
98
+ include ConcurrentAspectsSpecSupport
99
+
100
+ before :all do
101
+ @advice_kinds = []
102
+ end
103
+
104
+ it "should allow concurrent advice on the same join point, where type-based advices can be added and removed independently" do
105
+ (@advice_kinds.size+1).times do |n|
106
+ add_m_then_remove_n_aspects_and_run n, true
107
+ end
108
+ end
109
+
110
+ it "should allow concurrent advice on the same join point, where object-based advices can be added and removed independently" do
111
+ (@advice_kinds.size+1).times do |n|
112
+ add_m_then_remove_n_aspects_and_run n, false
113
+ end
114
+ end
115
+ end
116
+
117
+ describe "Using two :before advices" do
118
+ setup do
119
+ @advice_kinds = [:before, :before]
120
+ end
121
+ it_should_behave_like "concurrent advice"
122
+ end
123
+
124
+ describe "Using two :after advices" do
125
+ setup do
126
+ @advice_kinds = [:after, :after]
127
+ end
128
+ it_should_behave_like "concurrent advice"
129
+ end
130
+
131
+ describe "Using two :after_returning advices" do
132
+ setup do
133
+ @advice_kinds = [:after_returning, :after_returning]
134
+ end
135
+ it_should_behave_like "concurrent advice"
136
+ end
137
+
138
+ describe "Using two :after_raising advices" do
139
+ setup do
140
+ @advice_kinds = [:after_raising, :after_raising]
141
+ end
142
+ it_should_behave_like "concurrent advice"
143
+ end
144
+
145
+ describe "Using two :around advices" do
146
+ setup do
147
+ @advice_kinds = [:around, :around]
148
+ end
149
+ it_should_behave_like "concurrent advice"
150
+ end
151
+
152
+ describe "Using :before advice and :after advice" do
153
+ setup do
154
+ @advice_kinds = [:before, :after]
155
+ end
156
+ it_should_behave_like "concurrent advice"
157
+ end
158
+
159
+ describe "Using :before advice and :after_returning advice" do
160
+ setup do
161
+ @advice_kinds = [:before, :after_returning]
162
+ end
163
+ it_should_behave_like "concurrent advice"
164
+ end
165
+
166
+ describe "Using :before advice and :after_raising advice" do
167
+ setup do
168
+ @advice_kinds = [:before, :after_raising]
169
+ end
170
+ it_should_behave_like "concurrent advice"
171
+ end
172
+
173
+ describe "Using :before advice and :around advice" do
174
+ setup do
175
+ @advice_kinds = [:before, :around]
176
+ end
177
+ it_should_behave_like "concurrent advice"
178
+ end
179
+
180
+ describe "Using :after advice and :after_returning advice" do
181
+ setup do
182
+ @advice_kinds = [:after, :after_returning]
183
+ end
184
+ it_should_behave_like "concurrent advice"
185
+ end
186
+
187
+ describe "Using :after advice and :after_raising advice" do
188
+ setup do
189
+ @advice_kinds = [:after, :after_raising]
190
+ end
191
+ it_should_behave_like "concurrent advice"
192
+ end
193
+
194
+ describe "Using :after advice and :around advice" do
195
+ setup do
196
+ @advice_kinds = [:after, :around]
197
+ end
198
+ it_should_behave_like "concurrent advice"
199
+ end
200
+
201
+
202
+ describe "Using :after_returning advice and :after_raising advice" do
203
+ setup do
204
+ @advice_kinds = [:after_returning, :after_raising]
205
+ end
206
+ it_should_behave_like "concurrent advice"
207
+ end
208
+
209
+ describe "Using :after_returning advice and :around advice" do
210
+ setup do
211
+ @advice_kinds = [:after_returning, :around]
212
+ end
213
+ it_should_behave_like "concurrent advice"
214
+ end
215
+
216
+ describe "Using :after_raising advice and :around advice" do
217
+ setup do
218
+ @advice_kinds = [:after_raising, :around]
219
+ end
220
+ it_should_behave_like "concurrent advice"
221
+ end
222
+
223
+ describe "Using three :before advices" do
224
+ setup do
225
+ 3.times {|i| @advice_kinds[i] = :before}
226
+ end
227
+ it_should_behave_like "concurrent advice"
228
+ end
229
+
230
+ describe "Using three :before advices" do
231
+ setup do
232
+ 3.times {|i| @advice_kinds[i] = :before}
233
+ end
234
+ it_should_behave_like "concurrent advice"
235
+ end
236
+
237
+ describe "Using three :after advices" do
238
+ setup do
239
+ 3.times {|i| @advice_kinds[i] = :after}
240
+ end
241
+ it_should_behave_like "concurrent advice"
242
+ end
243
+
244
+ describe "Using three :after_returning advices" do
245
+ setup do
246
+ 3.times {|i| @advice_kinds[i] = :after_returning}
247
+ end
248
+ it_should_behave_like "concurrent advice"
249
+ end
250
+
251
+ describe "Using three :after_raising advices" do
252
+ setup do
253
+ 3.times {|i| @advice_kinds[i] = :after_raising}
254
+ end
255
+ it_should_behave_like "concurrent advice"
256
+ end
257
+
258
+ describe "Using three :around advices" do
259
+ setup do
260
+ 3.times {|i| @advice_kinds[i] = :around}
261
+ end
262
+ it_should_behave_like "concurrent advice"
263
+ end
264
+
265
+ describe "Using two :before advices and one :after advice" do
266
+ setup do
267
+ 2.times {|i| @advice_kinds[i] = :before}
268
+ @advice_kinds[2] = :after
269
+ end
270
+ it_should_behave_like "concurrent advice"
271
+ end
272
+
273
+ describe "Using two :before advices and one :after_returning advice" do
274
+ setup do
275
+ 2.times {|i| @advice_kinds[i] = :before}
276
+ @advice_kinds[2] = :after_returning
277
+ end
278
+ it_should_behave_like "concurrent advice"
279
+ end
280
+
281
+ describe "Using two :before advices and one :after_raising advice" do
282
+ setup do
283
+ 2.times {|i| @advice_kinds[i] = :before}
284
+ @advice_kinds[2] = :after_raising
285
+ end
286
+ it_should_behave_like "concurrent advice"
287
+ end
288
+
289
+ describe "Using two :before advices and one :around advice" do
290
+ setup do
291
+ 2.times {|i| @advice_kinds[i] = :before}
292
+ @advice_kinds[2] = :around
293
+ end
294
+ it_should_behave_like "concurrent advice"
295
+ end
296
+
297
+ describe "Using two :after advices and one :before advice" do
298
+ setup do
299
+ 2.times {|i| @advice_kinds[i] = :after}
300
+ @advice_kinds[2] = :before
301
+ end
302
+ it_should_behave_like "concurrent advice"
303
+ end
304
+
305
+ describe "Using two :after advices and one :after_returning advice" do
306
+ setup do
307
+ 2.times {|i| @advice_kinds[i] = :after}
308
+ @advice_kinds[2] = :after_returning
309
+ end
310
+ it_should_behave_like "concurrent advice"
311
+ end
312
+
313
+ describe "Using two :after advices and one :after_raising advice" do
314
+ setup do
315
+ 2.times {|i| @advice_kinds[i] = :after}
316
+ @advice_kinds[2] = :after_raising
317
+ end
318
+ it_should_behave_like "concurrent advice"
319
+ end
320
+
321
+ describe "Using two :after advices and one :around advice" do
322
+ setup do
323
+ 2.times {|i| @advice_kinds[i] = :after}
324
+ @advice_kinds[2] = :around
325
+ end
326
+ it_should_behave_like "concurrent advice"
327
+ end
328
+
329
+ describe "Using two :after_returning advices and one :before advice" do
330
+ setup do
331
+ 2.times {|i| @advice_kinds[i] = :after_returning}
332
+ @advice_kinds[2] = :before
333
+ end
334
+ it_should_behave_like "concurrent advice"
335
+ end
336
+
337
+ describe "Using two :after_returning advices and one :after advice" do
338
+ setup do
339
+ 2.times {|i| @advice_kinds[i] = :after_returning}
340
+ @advice_kinds[2] = :after
341
+ end
342
+ it_should_behave_like "concurrent advice"
343
+ end
344
+
345
+ describe "Using two :after_returning advices and one :after_raising advice" do
346
+ setup do
347
+ 2.times {|i| @advice_kinds[i] = :after_returning}
348
+ @advice_kinds[2] = :after_raising
349
+ end
350
+ it_should_behave_like "concurrent advice"
351
+ end
352
+
353
+ describe "Using two :after_returning advices and one :around advice" do
354
+ setup do
355
+ 2.times {|i| @advice_kinds[i] = :after_returning}
356
+ @advice_kinds[2] = :around
357
+ end
358
+ it_should_behave_like "concurrent advice"
359
+ end
360
+
361
+ describe "Using two :after_raising advices and one :before advice" do
362
+ setup do
363
+ 2.times {|i| @advice_kinds[i] = :after_raising}
364
+ @advice_kinds[2] = :before
365
+ end
366
+ it_should_behave_like "concurrent advice"
367
+ end
368
+
369
+ describe "Using two :after_raising advices and one :after advice" do
370
+ setup do
371
+ 2.times {|i| @advice_kinds[i] = :after_raising}
372
+ @advice_kinds[2] = :after
373
+ end
374
+ it_should_behave_like "concurrent advice"
375
+ end
376
+
377
+ describe "Using two :after_raising advices and one :after_raising advice" do
378
+ setup do
379
+ 2.times {|i| @advice_kinds[i] = :after_raising}
380
+ @advice_kinds[2] = :after_raising
381
+ end
382
+ it_should_behave_like "concurrent advice"
383
+ end
384
+
385
+ describe "Using two :after_raising advices and one :around advice" do
386
+ setup do
387
+ 2.times {|i| @advice_kinds[i] = :after_raising}
388
+ @advice_kinds[2] = :around
389
+ end
390
+ it_should_behave_like "concurrent advice"
391
+ end
392
+
393
+ describe "Using two :around advices and one :before advice" do
394
+ setup do
395
+ 2.times {|i| @advice_kinds[i] = :around}
396
+ @advice_kinds[2] = :before
397
+ end
398
+ it_should_behave_like "concurrent advice"
399
+ end
400
+
401
+ describe "Using two :around advices and one :after advice" do
402
+ setup do
403
+ 2.times {|i| @advice_kinds[i] = :around}
404
+ @advice_kinds[2] = :after
405
+ end
406
+ it_should_behave_like "concurrent advice"
407
+ end
408
+
409
+ describe "Using two :around advices and one :after_returning advice" do
410
+ setup do
411
+ 2.times {|i| @advice_kinds[i] = :around}
412
+ @advice_kinds[2] = :after_returning
413
+ end
414
+ it_should_behave_like "concurrent advice"
415
+ end
416
+
417
+ describe "Using two :around advices and one :after_raising advice" do
418
+ setup do
419
+ 2.times {|i| @advice_kinds[i] = :around}
420
+ @advice_kinds[2] = :after_raising
421
+ end
422
+ it_should_behave_like "concurrent advice"
423
+ end