aquarium 0.1.8 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/CHANGES +59 -2
  2. data/README +33 -16
  3. data/RELEASE-PLAN +28 -5
  4. data/UPGRADE +11 -0
  5. data/examples/aspect_design_example.rb +2 -2
  6. data/examples/aspect_design_example_spec.rb +2 -2
  7. data/examples/design_by_contract_example.rb +4 -4
  8. data/examples/design_by_contract_example_spec.rb +4 -4
  9. data/examples/method_missing_example.rb +4 -1
  10. data/examples/method_missing_example_spec.rb +4 -1
  11. data/examples/method_tracing_example.rb +2 -2
  12. data/examples/method_tracing_example_spec.rb +16 -16
  13. data/lib/aquarium/aspects/advice.rb +47 -25
  14. data/lib/aquarium/aspects/aspect.rb +81 -39
  15. data/lib/aquarium/aspects/dsl/aspect_dsl.rb +1 -1
  16. data/lib/aquarium/aspects/exclusion_handler.rb +2 -2
  17. data/lib/aquarium/aspects/join_point.rb +28 -28
  18. data/lib/aquarium/aspects/pointcut.rb +61 -15
  19. data/lib/aquarium/extras/design_by_contract.rb +7 -7
  20. data/lib/aquarium/finders.rb +0 -1
  21. data/lib/aquarium/finders/method_finder.rb +10 -20
  22. data/lib/aquarium/finders/type_finder.rb +141 -75
  23. data/lib/aquarium/utils.rb +1 -0
  24. data/lib/aquarium/utils/logic_error.rb +9 -0
  25. data/lib/aquarium/utils/method_utils.rb +4 -3
  26. data/lib/aquarium/utils/nil_object.rb +1 -0
  27. data/lib/aquarium/utils/type_utils.rb +19 -0
  28. data/lib/aquarium/version.rb +2 -2
  29. data/spec/aquarium/aspects/advice_chain_node_spec.rb +2 -2
  30. data/spec/aquarium/aspects/advice_spec.rb +28 -5
  31. data/spec/aquarium/aspects/aspect_invocation_spec.rb +522 -289
  32. data/spec/aquarium/aspects/aspect_spec.rb +59 -41
  33. data/spec/aquarium/aspects/aspect_with_nested_types_spec.rb +7 -7
  34. data/spec/aquarium/aspects/aspect_with_subtypes_spec.rb +2 -2
  35. data/spec/aquarium/aspects/concurrent_aspects_spec.rb +1 -2
  36. data/spec/aquarium/aspects/concurrent_aspects_with_objects_and_types_spec.rb +1 -1
  37. data/spec/aquarium/aspects/dsl/aspect_dsl_spec.rb +34 -34
  38. data/spec/aquarium/aspects/join_point_spec.rb +79 -0
  39. data/spec/aquarium/aspects/pointcut_or_composition_spec.rb +13 -3
  40. data/spec/aquarium/aspects/pointcut_spec.rb +310 -63
  41. data/spec/aquarium/extras/design_by_contract_spec.rb +4 -4
  42. data/spec/aquarium/finders/method_finder_spec.rb +208 -54
  43. data/spec/aquarium/finders/type_finder_spec.rb +24 -88
  44. data/spec/aquarium/finders/type_finder_with_descendents_and_ancestors_spec.rb +206 -0
  45. data/spec/aquarium/spec_example_classes.rb +75 -12
  46. data/spec/aquarium/utils/logic_error_spec.rb +10 -0
  47. data/spec/aquarium/utils/type_utils_sample_classes.rb +203 -0
  48. data/spec/aquarium/utils/type_utils_spec.rb +47 -1
  49. metadata +48 -39
  50. data/lib/aquarium/finders/object_finder.rb +0 -75
  51. data/spec/aquarium/finders/object_finder_spec.rb +0 -231
@@ -8,7 +8,7 @@ end
8
8
 
9
9
  describe "DSL method #before" do
10
10
  before :each do
11
- @advice = proc {|jp,*args| "advice"}
11
+ @advice = proc {|jp, obj, *args| "advice"}
12
12
  @aspects = []
13
13
  end
14
14
  after :each do
@@ -24,7 +24,7 @@ end
24
24
 
25
25
  describe "DSL method #after" do
26
26
  before :each do
27
- @advice = proc {|jp,*args| "advice"}
27
+ @advice = proc {|jp, obj, *args| "advice"}
28
28
  @aspects = []
29
29
  end
30
30
  after :each do
@@ -41,7 +41,7 @@ end
41
41
  describe "DSL method #after_raising_within_or_returning_from" do
42
42
  before :each do
43
43
  @dsl = DSLClass.new
44
- @advice = proc {|jp,*args| "advice"}
44
+ @advice = proc {|jp, obj, *args| "advice"}
45
45
  @aspects = []
46
46
  end
47
47
  after :each do
@@ -58,7 +58,7 @@ end
58
58
  describe "DSL method #after_returning" do
59
59
  before :each do
60
60
  @dsl = DSLClass.new
61
- @advice = proc {|jp,*args| "advice"}
61
+ @advice = proc {|jp, obj, *args| "advice"}
62
62
  @aspects = []
63
63
  end
64
64
  after :each do
@@ -75,7 +75,7 @@ end
75
75
  describe "DSL method #after_returning_from" do
76
76
  before :each do
77
77
  @dsl = DSLClass.new
78
- @advice = proc {|jp,*args| "advice"}
78
+ @advice = proc {|jp, obj, *args| "advice"}
79
79
  @aspects = []
80
80
  end
81
81
  after :each do
@@ -92,7 +92,7 @@ end
92
92
  describe "DSL method #after_raising" do
93
93
  before :each do
94
94
  @dsl = DSLClass.new
95
- @advice = proc {|jp,*args| "advice"}
95
+ @advice = proc {|jp, obj, *args| "advice"}
96
96
  @aspects = []
97
97
  end
98
98
  after :each do
@@ -112,7 +112,7 @@ end
112
112
  describe "DSL method #after_raising_within" do
113
113
  before :each do
114
114
  @dsl = DSLClass.new
115
- @advice = proc {|jp,*args| "advice"}
115
+ @advice = proc {|jp, obj, *args| "advice"}
116
116
  @aspects = []
117
117
  end
118
118
  after :each do
@@ -132,7 +132,7 @@ end
132
132
  describe "DSL method #before_and_after" do
133
133
  before :each do
134
134
  @dsl = DSLClass.new
135
- @advice = proc {|jp,*args| "advice"}
135
+ @advice = proc {|jp, obj, *args| "advice"}
136
136
  @aspects = []
137
137
  end
138
138
  after :each do
@@ -149,7 +149,7 @@ end
149
149
  describe "DSL method #before_and_after_raising_within_or_returning_from" do
150
150
  before :each do
151
151
  @dsl = DSLClass.new
152
- @advice = proc {|jp,*args| "advice"}
152
+ @advice = proc {|jp, obj, *args| "advice"}
153
153
  @aspects = []
154
154
  end
155
155
  after :each do
@@ -166,7 +166,7 @@ end
166
166
  describe "DSL method #before_and_after_returning" do
167
167
  before :each do
168
168
  @dsl = DSLClass.new
169
- @advice = proc {|jp,*args| "advice"}
169
+ @advice = proc {|jp, obj, *args| "advice"}
170
170
  @aspects = []
171
171
  end
172
172
  after :each do
@@ -183,7 +183,7 @@ end
183
183
  describe "DSL method #before_and_after_returning_from" do
184
184
  before :each do
185
185
  @dsl = DSLClass.new
186
- @advice = proc {|jp,*args| "advice"}
186
+ @advice = proc {|jp, obj, *args| "advice"}
187
187
  @aspects = []
188
188
  end
189
189
  after :each do
@@ -200,7 +200,7 @@ end
200
200
  describe "DSL method #before_and_after_raising" do
201
201
  before :each do
202
202
  @dsl = DSLClass.new
203
- @advice = proc {|jp,*args| "advice"}
203
+ @advice = proc {|jp, obj, *args| "advice"}
204
204
  @aspects = []
205
205
  end
206
206
  after :each do
@@ -217,7 +217,7 @@ end
217
217
  describe "DSL method #around" do
218
218
  before :each do
219
219
  @dsl = DSLClass.new
220
- @advice = proc {|jp,*args| "advice"}
220
+ @advice = proc {|jp, obj, *args| "advice"}
221
221
  @aspects = []
222
222
  end
223
223
  after :each do
@@ -243,11 +243,11 @@ describe "DSL method #advise, when determining the \"self\" to advise," do
243
243
  class Watchful1
244
244
  include Aquarium::Aspects::DSL::AspectDSL
245
245
  @@watchful = Watchful1.new
246
- @@aspect = after(:object => @@watchful, :method => :public_watchful_method) {|jp,*args|}
246
+ @@aspect = after(:object => @@watchful, :method => :public_watchful_method) {|jp, obj, *args|}
247
247
  def self.watchful; @@watchful; end
248
248
  def self.aspect; @@aspect; end
249
249
  end
250
- @aspects << DSLClass.after(:object => Watchful1.watchful, :method => :public_watchful_method) {|jp,*args|}
250
+ @aspects << DSLClass.after(:object => Watchful1.watchful, :method => :public_watchful_method) {|jp, obj, *args|}
251
251
  @aspects << Watchful1.aspect
252
252
  @aspects[1].join_points_matched.should == @aspects[0].join_points_matched
253
253
  @aspects[1].pointcuts.should == @aspects[0].pointcuts
@@ -256,10 +256,10 @@ describe "DSL method #advise, when determining the \"self\" to advise," do
256
256
  it "should ignore the default object \"self\" when a :type is specified." do
257
257
  class Watchful2
258
258
  include Aquarium::Aspects::DSL::AspectDSL
259
- @@aspect = after(:type => Watchful2, :method => :public_watchful_method) {|jp,*args|}
259
+ @@aspect = after(:type => Watchful2, :method => :public_watchful_method) {|jp, obj, *args|}
260
260
  def self.aspect; @@aspect; end
261
261
  end
262
- @aspects << DSLClass.after(:type => Watchful2, :method => :public_watchful_method) {|jp,*args|}
262
+ @aspects << DSLClass.after(:type => Watchful2, :method => :public_watchful_method) {|jp, obj, *args|}
263
263
  @aspects << Watchful2.aspect
264
264
  @aspects[1].join_points_matched.should == @aspects[0].join_points_matched
265
265
  @aspects[1].pointcuts.should == @aspects[0].pointcuts
@@ -282,9 +282,9 @@ describe "DSL method #advise, when determining the type or object to advise," do
282
282
  end
283
283
 
284
284
  it "should infer the type as \"self\" when no :object, :type, or :pointcut is specified." do
285
- @aspects << DSLClass.after(:type => WatchfulSelf, :method => :public_watchful_method) {|jp,*args|}
285
+ @aspects << DSLClass.after(:type => WatchfulSelf, :method => :public_watchful_method) {|jp, obj, *args|}
286
286
  class WatchfulSelf
287
- @@aspect = after(:method => :public_watchful_method) {|jp,*args|}
287
+ @@aspect = after(:method => :public_watchful_method) {|jp, obj, *args|}
288
288
  end
289
289
  @aspects << WatchfulSelf.aspect
290
290
  @aspects[1].join_points_matched.should == @aspects[0].join_points_matched
@@ -294,14 +294,14 @@ describe "DSL method #advise, when determining the type or object to advise," do
294
294
  it "should infer the object as \"self\" when no :object, :type, or :pointcut is specified." do
295
295
  watchful_self = WatchfulSelf.new
296
296
  watchful_self.extend Aquarium::Aspects::DSL::AspectDSL
297
- @aspects << watchful_self.after(:method => :public_watchful_method) {|jp,*args|}
298
- @aspects << DSLClass.advise( :after, :pointcut => {:object => watchful_self, :method => :public_watchful_method}) {|jp,*args|}
297
+ @aspects << DSLClass.advise(:after, :pointcut => {:object => watchful_self, :method => :public_watchful_method}) {|jp, obj, *args|}
298
+ @aspects << watchful_self.after(:method => :public_watchful_method) {|jp, obj, *args|}
299
299
  @aspects[1].join_points_matched.should == @aspects[0].join_points_matched
300
300
  @aspects[1].pointcuts.should == @aspects[0].pointcuts
301
301
  end
302
302
 
303
303
  it "should infer no types or objects if a :pointcut => {...} parameter is used and it does not specify a type or object." do
304
- @aspects << DSLClass.after(:pointcut => {:method => /method/}) {|jp,*args|}
304
+ @aspects << DSLClass.after(:pointcut => {:method => /method/}) {|jp, obj, *args|}
305
305
  @aspects[0].join_points_matched.size.should == 0
306
306
  end
307
307
  end
@@ -320,7 +320,7 @@ describe "DSL method #advise, when parsing the parameter list," do
320
320
  end
321
321
 
322
322
  it "should infer the first symbol parameter after the advice kind parameter to be the method name to advise if no other :method => ... parameter is used." do
323
- @aspects << Watchful3.after(:public_watchful_method) {|jp,*args|}
323
+ @aspects << Watchful3.after(:public_watchful_method) {|jp, obj, *args|}
324
324
  @aspects.each do |aspect|
325
325
  aspect.join_points_matched.size.should == 1
326
326
  aspect.specification[:methods].should == Set.new([:public_watchful_method])
@@ -342,7 +342,7 @@ describe "DSL method #advise, when determining instance or class methods to advi
342
342
  def public_watchful_method *args; end
343
343
  end
344
344
  advice_called = 0
345
- WatchfulExampleWithSeparateAdviseCall.advise :before, :public_watchful_method do |jp, *args|
345
+ WatchfulExampleWithSeparateAdviseCall.advise :before, :public_watchful_method do |jp, obj, *args|
346
346
  advice_called += 1
347
347
  end
348
348
  WatchfulExampleWithSeparateAdviseCall.new.public_watchful_method :a1, :a2
@@ -357,7 +357,7 @@ describe "DSL method #advise, when determining instance or class methods to advi
357
357
  def public_watchful_method *args; end
358
358
  end
359
359
  advice_called = 0
360
- WatchfulExampleWithSeparateAdviseCall2.advise :before, :type => WatchfulExampleWithSeparateAdviseCall2, :methods => /public_watchful_method/, :method_options =>[:instance] do |jp, *args|
360
+ WatchfulExampleWithSeparateAdviseCall2.advise :before, :type => WatchfulExampleWithSeparateAdviseCall2, :methods => /public_watchful_method/, :method_options =>[:instance] do |jp, obj, *args|
361
361
  advice_called += 1
362
362
  end
363
363
  WatchfulExampleWithSeparateAdviseCall2.class_public_watchful_method :a1, :a2
@@ -375,7 +375,7 @@ describe "DSL method #advise, when determining instance or class methods to advi
375
375
  def public_watchful_method *args; end
376
376
  end
377
377
  advice_called = 0
378
- WatchfulExampleWithSeparateAdviseCall3.advise :before, :methods => /public_watchful_method/, :method_options =>[:class] do |jp, *args|
378
+ WatchfulExampleWithSeparateAdviseCall3.advise :before, :methods => /public_watchful_method/, :method_options =>[:class] do |jp, obj, *args|
379
379
  advice_called += 1
380
380
  end
381
381
  WatchfulExampleWithSeparateAdviseCall3.class_public_watchful_method :a1, :a2
@@ -391,7 +391,7 @@ describe "DSL method #advise, when determining instance or class methods to advi
391
391
  include Aquarium::Aspects::DSL::AspectDSL
392
392
  @@advice_called = 0
393
393
  def public_watchful_method *args; end
394
- before :public_watchful_method do |jp, *args|
394
+ before :public_watchful_method do |jp, obj, *args|
395
395
  @@advice_called += 1
396
396
  end
397
397
  def self.advice_called; @@advice_called; end
@@ -409,7 +409,7 @@ describe "DSL methods for the advice kind, when determining instance or class me
409
409
  end
410
410
 
411
411
  before :each do
412
- @advice = proc {|jp,*args| "advice"}
412
+ @advice = proc {|jp, obj, *args| "advice"}
413
413
  @aspects = []
414
414
  end
415
415
  after :each do
@@ -429,7 +429,7 @@ end
429
429
 
430
430
  describe "Synonyms for :types" do
431
431
  before :each do
432
- @advice = proc {|jp,*args| "advice"}
432
+ @advice = proc {|jp, obj, *args| "advice"}
433
433
  @aspects = [DSLClass.after(:noop, :types => Watchful, :methods => :public_watchful_method, &@advice)]
434
434
  end
435
435
  after :each do
@@ -454,7 +454,7 @@ end
454
454
 
455
455
  describe "Synonyms for :objects" do
456
456
  before :each do
457
- @advice = proc {|jp,*args| "advice"}
457
+ @advice = proc {|jp, obj, *args| "advice"}
458
458
  @aspects = [DSLClass.after(:noop, :objects => @watchful, :methods => :public_watchful_method, &@advice)]
459
459
  end
460
460
  after :each do
@@ -479,7 +479,7 @@ end
479
479
 
480
480
  describe "Synonyms for :methods" do
481
481
  before :each do
482
- @advice = proc {|jp,*args| "advice"}
482
+ @advice = proc {|jp, obj, *args| "advice"}
483
483
  @aspects = [DSLClass.after(:noop, :objects => @watchful, :methods => :public_watchful_method, &@advice)]
484
484
  end
485
485
  after :each do
@@ -504,7 +504,7 @@ end
504
504
 
505
505
  describe "Synonyms for :pointcut" do
506
506
  before :each do
507
- @advice = proc {|jp,*args| "advice"}
507
+ @advice = proc {|jp, obj, *args| "advice"}
508
508
  @aspects = [DSLClass.after(:noop, :pointcut => {:objects => @watchful, :methods => :public_watchful_method}, &@advice)]
509
509
  end
510
510
  after :each do
@@ -533,7 +533,7 @@ describe "DSL method #advise (or synonyms) called within a type body" do
533
533
  include Aquarium::Aspects::DSL::AspectDSL
534
534
  @@advice_called = 0
535
535
  def public_watchful_method *args; end
536
- before :public_watchful_method do |jp, *args|
536
+ before :public_watchful_method do |jp, obj, *args|
537
537
  @@advice_called += 1
538
538
  end
539
539
  def self.advice_called; @@advice_called; end
@@ -544,7 +544,7 @@ describe "DSL method #advise (or synonyms) called within a type body" do
544
544
  class WatchfulWithMethodNotYetDefined
545
545
  include Aquarium::Aspects::DSL::AspectDSL
546
546
  @@advice_called = 0
547
- before(:public_watchful_method) {|jp, *args| @@advice_called += 1}
547
+ before(:public_watchful_method) {|jp, obj, *args| @@advice_called += 1}
548
548
  def public_watchful_method *args; end
549
549
  def self.advice_called; @@advice_called; end
550
550
  end
@@ -181,6 +181,85 @@ describe Aquarium::Aspects::JoinPoint, "#target_object" do
181
181
  jp.target_object.should be_eql(example)
182
182
  end
183
183
  end
184
+
185
+ class InvokeOriginalClass
186
+ def invoke; @called = true; end
187
+ def called; @called; end
188
+ end
189
+
190
+ describe Aquarium::Aspects::JoinPoint, "#proceed" do
191
+ it "should raise when the join point doesn't have a context" do
192
+ jp = Aquarium::Aspects::JoinPoint.new :type => InvokeOriginalClass, :method => :invoke
193
+ lambda { jp.proceed }.should raise_error(Aquarium::Aspects::JoinPoint::ContextNotDefined)
194
+ end
195
+
196
+ it "should raise when the the context object doesn't have a 'proceed proc'" do
197
+ jp = Aquarium::Aspects::JoinPoint.new :type => InvokeOriginalClass, :method => :invoke
198
+ ioc = InvokeOriginalClass.new
199
+ context_opts = {
200
+ :advice_kind => :around,
201
+ :advised_object => ioc,
202
+ :parameters => [],
203
+ :proceed_proc => nil
204
+ }
205
+ jp2 = jp.make_current_context_join_point context_opts
206
+ lambda { jp2.proceed }.should raise_error(Aquarium::Aspects::JoinPoint::ProceedMethodNotAvailable)
207
+ end
208
+
209
+ it "should not raise when the advice is :around advice" do
210
+ jp = Aquarium::Aspects::JoinPoint.new :type => InvokeOriginalClass, :method => :invoke
211
+ ioc = InvokeOriginalClass.new
212
+ context_opts = {
213
+ :advice_kind => :around,
214
+ :advised_object => ioc,
215
+ :parameters => [],
216
+ :proceed_proc => Aquarium::Aspects::NoAdviceChainNode.new({:alias_method_name => :invoke})
217
+ }
218
+ jp2 = jp.make_current_context_join_point context_opts
219
+ lambda { jp2.proceed }.should_not raise_error(Aquarium::Aspects::JoinPoint::ProceedMethodNotAvailable)
220
+ end
221
+
222
+ it "should invoke the actual join point" do
223
+ jp = Aquarium::Aspects::JoinPoint.new :type => InvokeOriginalClass, :method => :invoke
224
+ ioc = InvokeOriginalClass.new
225
+ context_opts = {
226
+ :advice_kind => :around,
227
+ :advised_object => ioc,
228
+ :parameters => [],
229
+ :proceed_proc => Aquarium::Aspects::NoAdviceChainNode.new({:alias_method_name => :invoke})
230
+ }
231
+ jp2 = jp.make_current_context_join_point context_opts
232
+ jp2.proceed
233
+ ioc.called.should be_true
234
+ end
235
+ end
236
+
237
+ class InvokeOriginalClass
238
+ def invoke; @called = true; end
239
+ def called; @called; end
240
+ end
241
+
242
+ describe Aquarium::Aspects::JoinPoint, "#invoke_original_join_point" do
243
+ it "should raise when the join point doesn't have a context" do
244
+ jp = Aquarium::Aspects::JoinPoint.new :type => InvokeOriginalClass, :method => :invoke
245
+ lambda { jp.invoke_original_join_point }.should raise_error(Aquarium::Aspects::JoinPoint::ContextNotDefined)
246
+ end
247
+
248
+ it "should invoke the original join point" do
249
+ jp = Aquarium::Aspects::JoinPoint.new :type => InvokeOriginalClass, :method => :invoke
250
+ ioc = InvokeOriginalClass.new
251
+ context_opts = {
252
+ :advice_kind => :around,
253
+ :advised_object => ioc,
254
+ :parameters => [],
255
+ :proceed_proc => Aquarium::Aspects::NoAdviceChainNode.new({:alias_method_name => :invoke})
256
+ }
257
+ jp2 = jp.make_current_context_join_point context_opts
258
+ jp2.invoke_original_join_point
259
+ ioc.called.should be_true
260
+ end
261
+ end
262
+
184
263
 
185
264
  describe Aquarium::Aspects::JoinPoint, "#dup" do
186
265
  it "should duplicate the fields in the join point." do
@@ -9,7 +9,15 @@ describe "Union of Pointcuts", :shared => true do
9
9
  include Aquarium::Utils::HashUtils
10
10
 
11
11
  before(:each) do
12
- classes = [ClassWithProtectedInstanceMethod, ClassWithPrivateInstanceMethod, ClassWithPublicClassMethod, ClassWithPrivateClassMethod]
12
+ classes = [
13
+ ClassWithProtectedInstanceMethod,
14
+ ClassWithPrivateInstanceMethod,
15
+ ClassWithPublicClassMethod,
16
+ ClassWithPrivateClassMethod,
17
+ ClassIncludingModuleWithPrivateClassMethod,
18
+ ClassIncludingModuleWithPublicClassMethod,
19
+ ClassIncludingModuleWithProtectedInstanceMethod,
20
+ ClassIncludingModuleWithPrivateInstanceMethod]
13
21
  jps_array = classes.map {|c| Aquarium::Aspects::JoinPoint.new :type => c, :method => :all}
14
22
  @not_matched_jps = Set.new(jps_array)
15
23
  end
@@ -32,14 +40,16 @@ describe "Union of Pointcuts", :shared => true do
32
40
 
33
41
  it "should return a new Aquarium::Aspects::Pointcut whose join points are the union of the left- and right-hand side Aquarium::Aspects::Pointcuts for type-based Aquarium::Aspects::Pointcuts." do
34
42
  pc1 = Aquarium::Aspects::Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/], :attribute_options => [:writers, :exclude_ancestor_methods]
35
- # "[^F]" excludes the ClassWithFunkyMethodNames...
43
+ # "[^F]" excludes the ClassWithFunkyMethodNames ...
36
44
  pc2 = Aquarium::Aspects::Pointcut.new :types => /Class[^F]+Method/, :method_options => :exclude_ancestor_methods
37
45
  pc = pc1.or pc2
38
46
  jp1 = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method => :attrRW_ClassWithAttribs=
39
47
  jp2 = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method => :attrW_ClassWithAttribs=
40
48
  jp3 = Aquarium::Aspects::JoinPoint.new :type => ClassWithPublicInstanceMethod, :method => :public_instance_test_method
41
49
  jp4 = Aquarium::Aspects::JoinPoint.new :type => ClassWithPublicInstanceMethod2, :method => :public_instance_test_method2
42
- pc.join_points_matched.should == Set.new([jp1, jp2, jp3, jp4])
50
+ jp5 = Aquarium::Aspects::JoinPoint.new :type => ClassDerivedFromClassIncludingModuleWithPublicInstanceMethod, :method => :public_instance_class_derived_from_class_including_module_test_method
51
+ jp6 = Aquarium::Aspects::JoinPoint.new :type => ClassIncludingModuleWithPublicInstanceMethod, :method => :public_instance_class_including_module_test_method
52
+ pc.join_points_matched.should == Set.new([jp1, jp2, jp3, jp4, jp5, jp6])
43
53
  pc.join_points_not_matched.should == @not_matched_jps
44
54
  end
45
55
 
@@ -33,10 +33,10 @@ def before_exclude_spec
33
33
  @all_jps = @all_type_jps + @all_object_jps
34
34
  end
35
35
 
36
- def before_pointcut_spec
37
- @example_types_without_public_instance_method =
36
+ def before_pointcut_class_spec
37
+ @example_classes_without_public_instance_method =
38
38
  [ClassWithProtectedInstanceMethod, ClassWithPrivateInstanceMethod, ClassWithPublicClassMethod, ClassWithPrivateClassMethod]
39
- @example_types = ([ClassWithPublicInstanceMethod] + @example_types_without_public_instance_method)
39
+ @example_classes = ([ClassWithPublicInstanceMethod] + @example_classes_without_public_instance_method)
40
40
  @pub_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithPublicInstanceMethod, :method_name => :public_instance_test_method
41
41
  @pro_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithProtectedInstanceMethod, :method_name => :protected_instance_test_method
42
42
  @pri_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithPrivateInstanceMethod, :method_name => :private_instance_test_method
@@ -46,17 +46,64 @@ def before_pointcut_spec
46
46
  @apri_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithPrivateInstanceMethod, :method_name => :all
47
47
  @acpub_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithPublicClassMethod, :method_name => :all
48
48
  @acpri_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithPrivateClassMethod, :method_name => :all
49
- @expected_matched_jps = Set.new [@pub_jp]
50
- @expected_not_matched_jps = Set.new [@apro_jp, @apri_jp, @acpub_jp, @acpri_jp]
49
+ @cdcimpub_jp = Aquarium::Aspects::JoinPoint.new :type => ClassDerivedFromClassIncludingModuleWithPublicInstanceMethod, :method_name => :public_instance_class_derived_from_class_including_module_test_method
50
+ @expected_classes_matched_jps = Set.new [@pub_jp]
51
+ @expected_classes_not_matched_jps = Set.new [@apro_jp, @apri_jp, @acpub_jp, @acpri_jp]
51
52
  end
52
53
 
53
- describe Aquarium::Aspects::Pointcut, "#new (invalid arguments)" do
54
+ def before_pointcut_module_spec
55
+ @example_modules_with_public_instance_method = [
56
+ ClassDerivedFromClassIncludingModuleWithPublicInstanceMethod,
57
+ ClassIncludingModuleWithPublicInstanceMethod,
58
+ ModuleIncludingModuleWithPublicInstanceMethod,
59
+ ModuleWithPublicInstanceMethod]
60
+ @example_modules_without_public_instance_method = [
61
+ ClassIncludingModuleWithProtectedInstanceMethod,
62
+ ClassIncludingModuleWithPrivateInstanceMethod,
63
+ ClassIncludingModuleWithPublicClassMethod,
64
+ ClassIncludingModuleWithPrivateClassMethod,
65
+ ModuleWithProtectedInstanceMethod,
66
+ ModuleWithPrivateInstanceMethod,
67
+ ModuleWithPublicClassMethod,
68
+ ModuleWithPrivateClassMethod]
69
+ @example_modules = (@example_modules_with_public_instance_method + @example_modules_without_public_instance_method)
70
+ @mimpub_jp = Aquarium::Aspects::JoinPoint.new :type => ModuleIncludingModuleWithPublicInstanceMethod, :method_name => :public_instance_module_including_module_test_method
71
+ @mpub_jp = Aquarium::Aspects::JoinPoint.new :type => ModuleWithPublicInstanceMethod, :method_name => :public_instance_module_test_method
72
+ @mpro_jp = Aquarium::Aspects::JoinPoint.new :type => ModuleWithProtectedInstanceMethod, :method_name => :protected_instance_module_test_method
73
+ @mpri_jp = Aquarium::Aspects::JoinPoint.new :type => ModuleWithPrivateInstanceMethod, :method_name => :private_instance_module_test_method
74
+ @cmpub_jp = Aquarium::Aspects::JoinPoint.new :type => ModuleWithPublicClassMethod, :method_name => :public_class_module_test_method, :class_method => true
75
+ @cmpri_jp = Aquarium::Aspects::JoinPoint.new :type => ModuleWithPrivateClassMethod, :method_name => :private_class_module_test_method, :class_method => true
76
+ @ampro_jp = Aquarium::Aspects::JoinPoint.new :type => ModuleWithProtectedInstanceMethod, :method_name => :all
77
+ @ampri_jp = Aquarium::Aspects::JoinPoint.new :type => ModuleWithPrivateInstanceMethod, :method_name => :all
78
+ @acmpub_jp = Aquarium::Aspects::JoinPoint.new :type => ModuleWithPublicClassMethod, :method_name => :all
79
+ @acmpri_jp = Aquarium::Aspects::JoinPoint.new :type => ModuleWithPrivateClassMethod, :method_name => :all
80
+ @cdcimpub_jp = Aquarium::Aspects::JoinPoint.new :type => ClassDerivedFromClassIncludingModuleWithPublicInstanceMethod, :method_name => :public_instance_class_derived_from_class_including_module_test_method
81
+ @cimpub_jp = Aquarium::Aspects::JoinPoint.new :type => ClassIncludingModuleWithPublicInstanceMethod, :method_name => :public_instance_class_including_module_test_method
82
+ @cimpro_jp = Aquarium::Aspects::JoinPoint.new :type => ClassIncludingModuleWithProtectedInstanceMethod, :method_name => :protected_instance_class_including_module_test_method
83
+ @cimpri_jp = Aquarium::Aspects::JoinPoint.new :type => ClassIncludingModuleWithPrivateInstanceMethod, :method_name => :private_instance_class_including_module_test_method
84
+ @ccimpub_jp = Aquarium::Aspects::JoinPoint.new :type => ClassIncludingModuleWithPublicClassMethod, :method_name => :public_class_class_including_module_test_method, :class_method => true
85
+ @ccimpri_jp = Aquarium::Aspects::JoinPoint.new :type => ClassIncludingModuleWithPrivateClassMethod, :method_name => :private_class_class_including_module_test_method, :class_method => true
86
+ @acimpro_jp = Aquarium::Aspects::JoinPoint.new :type => ClassIncludingModuleWithProtectedInstanceMethod, :method_name => :all
87
+ @acimpri_jp = Aquarium::Aspects::JoinPoint.new :type => ClassIncludingModuleWithPrivateInstanceMethod, :method_name => :all
88
+ @accimpub_jp = Aquarium::Aspects::JoinPoint.new :type => ClassIncludingModuleWithPublicClassMethod, :method_name => :all
89
+ @accimpri_jp = Aquarium::Aspects::JoinPoint.new :type => ClassIncludingModuleWithPrivateClassMethod, :method_name => :all
90
+ @expected_modules_matched_jps = Set.new [@mimpub_jp, @mpub_jp, @cdcimpub_jp, @cimpub_jp]
91
+ @expected_modules_not_matched_jps = Set.new [@ampro_jp, @ampri_jp, @acmpub_jp, @acmpri_jp, @acimpro_jp, @acimpri_jp, @accimpub_jp, @accimpri_jp]
92
+ end
93
+
94
+ def ignored_join_point jp
95
+ # Ignore any types introduced by RSpec, other Aquarium types, and the "pretty printer" module (which Rake uses?)
96
+ jp.target_type.name =~ /^Spec/ or jp.target_type.name =~ /^Aquarium::(Aspects|Extras|Utils)/ or jp.target_type.name =~ /^PP/
97
+ end
98
+
99
+
100
+ describe Aquarium::Aspects::Pointcut, ".new (invalid arguments)" do
54
101
  it "should raise if an unknown argument is specified" do
55
102
  lambda { Aquarium::Aspects::Pointcut.new :foo => :bar }.should raise_error(Aquarium::Utils::InvalidOptions)
56
103
  end
57
104
  end
58
105
 
59
- describe Aquarium::Aspects::Pointcut, "#new (empty)" do
106
+ describe Aquarium::Aspects::Pointcut, ".new (empty)" do
60
107
  it "should match no join points by default." do
61
108
  pc = Aquarium::Aspects::Pointcut.new
62
109
  pc.should be_empty
@@ -121,57 +168,134 @@ describe Aquarium::Aspects::Pointcut, "#empty?" do
121
168
  end
122
169
  end
123
170
 
124
- describe Aquarium::Aspects::Pointcut, " (types specified using regular expressions)" do
171
+ describe Aquarium::Aspects::Pointcut, " (classes specified using regular expressions)" do
125
172
  before(:each) do
126
- before_pointcut_spec
173
+ before_pointcut_class_spec
127
174
  end
128
175
 
129
- it "should match multiple types using regular expressions that cover the full class names." do
130
- pc = Aquarium::Aspects::Pointcut.new :types => /Class.*Method\Z/, :method_options => :exclude_ancestor_methods
131
- pc.join_points_matched.should == @expected_matched_jps
132
- pc.join_points_not_matched.should == @expected_not_matched_jps
176
+ it "should match multiple classes using regular expressions that cover the full class names." do
177
+ pc = Aquarium::Aspects::Pointcut.new :types => /\AClass(?!IncludingModule).*Method\Z/, :method_options => :exclude_ancestor_methods
178
+ pc.join_points_matched.should == (@expected_classes_matched_jps + [@cdcimpub_jp])
179
+ pc.join_points_not_matched.should == @expected_classes_not_matched_jps
133
180
  end
134
181
 
135
- it "should match types using regular expressions that only cover partial class names." do
136
- pc = Aquarium::Aspects::Pointcut.new :types => /lass.*Pro.*Inst.*Met/, :method_options => [:public, :protected, :exclude_ancestor_methods]
182
+ it "should match clases using regular expressions that only cover partial class names." do
183
+ pc = Aquarium::Aspects::Pointcut.new :types => /lass(?!IncludingModule).*Pro.*Inst.*Met/, :method_options => [:public, :protected, :exclude_ancestor_methods]
137
184
  pc.join_points_matched.should == Set.new([@pro_jp])
138
185
  pc.join_points_not_matched.size.should == 0
139
186
  end
140
187
  end
141
188
 
142
- describe Aquarium::Aspects::Pointcut, " (types specified using names)" do
189
+ describe Aquarium::Aspects::Pointcut, " (classes specified using names)" do
143
190
  before(:each) do
144
- before_pointcut_spec
191
+ before_pointcut_class_spec
192
+ end
193
+
194
+ it "should match multiple classes using names." do
195
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_classes.map {|t| t.to_s}, :method_options => :exclude_ancestor_methods
196
+ pc.join_points_matched.should == @expected_classes_matched_jps
197
+ pc.join_points_not_matched.should == @expected_classes_not_matched_jps
198
+ end
199
+
200
+ it "should match multiple classes using classes themselves." do
201
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_classes, :method_options => :exclude_ancestor_methods
202
+ pc.join_points_matched.should == @expected_classes_matched_jps
203
+ pc.join_points_not_matched.should == @expected_classes_not_matched_jps
204
+ end
205
+
206
+ it "should match :all public instance methods for classes by default." do
207
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_classes, :method_options => :exclude_ancestor_methods
208
+ pc.join_points_matched.should == @expected_classes_matched_jps
209
+ pc.join_points_not_matched.should == @expected_classes_not_matched_jps
210
+ end
211
+
212
+ it "should support MethodFinder's :exclude_ancestor_methods option when using classes." do
213
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_classes, :method_options => :exclude_ancestor_methods
214
+ pc.join_points_matched.should == @expected_classes_matched_jps
215
+ pc.join_points_not_matched.should == @expected_classes_not_matched_jps
216
+ end
217
+ end
218
+
219
+ describe Aquarium::Aspects::Pointcut, " (modules specified using regular expressions)" do
220
+ it "should match multiple types using regular expressions that cover the full module names." do
221
+ pc = Aquarium::Aspects::Pointcut.new :types => /\AModule.*Method\Z/, :method_options => :exclude_ancestor_methods
222
+ pc.join_points_matched.size.should == 2
223
+ pc.join_points_matched.each do |jp|
224
+ [ModuleIncludingModuleWithPublicInstanceMethod, ModuleWithPublicInstanceMethod].should include(jp.target_type)
225
+ end
226
+ pc.join_points_not_matched.size.should == 4
227
+ pc.join_points_not_matched.each do |jp|
228
+ [ModuleWithPrivateInstanceMethod, ModuleWithProtectedInstanceMethod,
229
+ ModuleWithPublicClassMethod, ModuleWithPrivateClassMethod].should include(jp.target_type)
230
+ end
145
231
  end
232
+ end
146
233
 
147
- it "should match multiple types using names." do
148
- pc = Aquarium::Aspects::Pointcut.new :types => @example_types.map {|t| t.to_s}, :method_options => :exclude_ancestor_methods
149
- pc.join_points_matched.should == @expected_matched_jps
150
- pc.join_points_not_matched.should == @expected_not_matched_jps
234
+ describe Aquarium::Aspects::Pointcut, " (modules specified using names)" do
235
+ def do_module type_spec
236
+ pc = Aquarium::Aspects::Pointcut.new :types => type_spec, :method_options => :exclude_ancestor_methods
237
+ pc.join_points_matched.size.should == 1
238
+ pc.join_points_matched.each do |jp|
239
+ jp.target_type.should == ModuleWithPublicInstanceMethod
240
+ jp.method_name.should == :public_instance_module_test_method
241
+ end
242
+ pc.join_points_not_matched.size.should == 1
243
+ pc.join_points_not_matched.each do |jp|
244
+ jp.target_type.should == ModuleWithPublicClassMethod
245
+ jp.method_name.should == :all
246
+ end
247
+ end
248
+
249
+ it "should match multiple types using module names." do
250
+ do_module ["ModuleWithPublicInstanceMethod", "ModuleWithPublicClassMethod"]
151
251
  end
152
252
 
153
- it "should match multiple types using types themselves." do
154
- pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :method_options => :exclude_ancestor_methods
155
- pc.join_points_matched.should == @expected_matched_jps
156
- pc.join_points_not_matched.should == @expected_not_matched_jps
253
+ it "should match multiple types using module-name regular expressions." do
254
+ do_module /^ModuleWithPublic.*Method/
157
255
  end
158
256
 
159
- it "should match :all public instance methods for types by default." do
160
- pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :method_options => :exclude_ancestor_methods
161
- pc.join_points_matched.should == @expected_matched_jps
162
- pc.join_points_not_matched.should == @expected_not_matched_jps
257
+ it "should match multiple types using modules themselves." do
258
+ do_module [ModuleWithPublicInstanceMethod, ModuleWithPublicClassMethod]
259
+ end
260
+
261
+ it "should match :all public instance methods for modules by default." do
262
+ do_module [ModuleWithPublicInstanceMethod, ModuleWithPublicClassMethod]
163
263
  end
164
264
 
165
- it "should support MethodFinder's :exclude_ancestor_methods option when using types." do
166
- pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :method_options => :exclude_ancestor_methods
167
- pc.join_points_matched.should == @expected_matched_jps
168
- pc.join_points_not_matched.should == @expected_not_matched_jps
265
+ it "should support MethodFinder's :exclude_ancestor_methods option when using modules." do
266
+ do_module [ModuleWithPublicInstanceMethod, ModuleWithPublicClassMethod]
169
267
  end
170
268
  end
171
269
 
270
+ describe Aquarium::Aspects::Pointcut, " (types and their descendents and ancestors)" do
271
+ before(:each) do
272
+ before_pointcut_module_spec
273
+ end
274
+
275
+ it "should match classes specified and their ancestor and descendent modules and classes." do
276
+ pc = Aquarium::Aspects::Pointcut.new :types_and_ancestors => /^Class(Including|DerivedFrom).*Method/, :types_and_descendents => /^Class(Including|DerivedFrom).*Method/, :methods => :all, :method_options => :exclude_ancestor_methods
277
+ expected_types = @example_modules_with_public_instance_method + [Kernel, Module, Object]
278
+ pc.join_points_matched.each do |jp|
279
+ next if ignored_join_point(jp)
280
+ expected_types.should include(jp.target_type)
281
+ end
282
+ not_expected_types = @expected_modules_not_matched_jps.map {|jp| jp.target_type}
283
+ pc.join_points_not_matched.each do |jp|
284
+ next if ignored_join_point(jp)
285
+ not_expected_types.should include(jp.target_type)
286
+ end
287
+ end
288
+
289
+ it "should match modules specified, their ancestor and descendent modules, and including classes." do
290
+ pc = Aquarium::Aspects::Pointcut.new :types_and_ancestors => /^Module.*Method/, :types_and_descendents => /^Module.*Method/, :methods => :all, :method_options => :exclude_ancestor_methods
291
+ pc.join_points_matched.should == (@expected_modules_matched_jps + [@mimpub_jp])
292
+ pc.join_points_not_matched.should == @expected_modules_not_matched_jps
293
+ end
294
+ end
295
+
172
296
  describe Aquarium::Aspects::Pointcut, " (objects specified)" do
173
297
  before(:each) do
174
- before_pointcut_spec
298
+ before_pointcut_class_spec
175
299
  end
176
300
 
177
301
  it "should match :all public instance methods for objects by default." do
@@ -301,6 +425,124 @@ describe Aquarium::Aspects::Pointcut, " (:exclude_types => types specified)" do
301
425
  end
302
426
  end
303
427
 
428
+ describe Aquarium::Aspects::Pointcut, " (exclude types and their descendents and ancestors)" do
429
+ before(:each) do
430
+ before_pointcut_module_spec
431
+ end
432
+
433
+ def check_module_ancestors pc
434
+ expected_types = [
435
+ ClassDerivedFromClassIncludingModuleWithPublicInstanceMethod,
436
+ ClassIncludingModuleWithPublicInstanceMethod,
437
+ Kernel,
438
+ Object]
439
+ found_types = {}
440
+ pc.join_points_matched.each do |jp|
441
+ next if ignored_join_point(jp)
442
+ expected_types.should include(jp.target_type)
443
+ found_types[jp.target_type] = true
444
+ end
445
+ found_types.size.should == 4
446
+ not_expected_types = @expected_modules_not_matched_jps.map {|jp| jp.target_type}
447
+ pc.join_points_not_matched.each do |jp|
448
+ next if ignored_join_point(jp)
449
+ not_expected_types.should include(jp.target_type)
450
+ end
451
+ end
452
+
453
+ it "should exclude modules specified and their included modules when excluding ancestors." do
454
+ pc = Aquarium::Aspects::Pointcut.new :types_and_ancestors => /^Class(Including|DerivedFrom).*Method/,
455
+ :exclude_types_and_ancestors => ModuleIncludingModuleWithPublicInstanceMethod, :methods => :all, :method_options => :exclude_ancestor_methods
456
+ check_module_ancestors pc
457
+ end
458
+ it "should exclude join_points whose types match an excluded ancestor modules." do
459
+ pc = Aquarium::Aspects::Pointcut.new :join_point => @mimpub_jp, :types_and_ancestors => /^Class(Including|DerivedFrom).*Method/,
460
+ :exclude_types_and_ancestors => ModuleIncludingModuleWithPublicInstanceMethod, :methods => :all, :method_options => :exclude_ancestor_methods
461
+ check_module_ancestors pc
462
+ end
463
+
464
+ def check_module_descendents pc
465
+ expected_types = [Kernel, Object]
466
+ found_types = {}
467
+ pc.join_points_matched.each do |jp|
468
+ next if ignored_join_point(jp)
469
+ expected_types.should include(jp.target_type)
470
+ found_types[jp.target_type] = true
471
+ end
472
+ found_types.size.should == 2
473
+ not_expected_types = @expected_modules_not_matched_jps.map {|jp| jp.target_type}
474
+ pc.join_points_not_matched.each do |jp|
475
+ next if ignored_join_point(jp)
476
+ not_expected_types.should include(jp.target_type)
477
+ end
478
+ end
479
+
480
+ it "should exclude modules specified and their including modules and classes when excluding descendents." do
481
+ pc = Aquarium::Aspects::Pointcut.new :types_and_ancestors => /^Class(Including|DerivedFrom).*Method/,
482
+ :exclude_types_and_descendents => ModuleWithPublicInstanceMethod, :methods => :all, :method_options => :exclude_ancestor_methods
483
+ check_module_descendents pc
484
+ end
485
+ it "should exclude join_points whose types match an excluded descendent modules." do
486
+ pc = Aquarium::Aspects::Pointcut.new :join_point => @mpub_jp, :types_and_ancestors => /^Class(Including|DerivedFrom).*Method/,
487
+ :exclude_types_and_descendents => ModuleWithPublicInstanceMethod, :methods => :all, :method_options => :exclude_ancestor_methods
488
+ check_module_descendents pc
489
+ end
490
+
491
+ def check_class_ancestors pc
492
+ expected_types = [ClassDerivedFromClassIncludingModuleWithPublicInstanceMethod, ModuleIncludingModuleWithPublicInstanceMethod]
493
+ found_types = {}
494
+ pc.join_points_matched.each do |jp|
495
+ next if ignored_join_point(jp)
496
+ expected_types.should include(jp.target_type)
497
+ found_types[jp.target_type] = true
498
+ end
499
+ found_types.size.should == 2
500
+ not_expected_types = @expected_modules_not_matched_jps.map {|jp| jp.target_type}
501
+ pc.join_points_not_matched.each do |jp|
502
+ next if ignored_join_point(jp)
503
+ not_expected_types.should include(jp.target_type)
504
+ end
505
+ end
506
+
507
+ it "should exclude classes specified and their included modules and ancestor classes when excluding ancestors." do
508
+ pc = Aquarium::Aspects::Pointcut.new :types_and_ancestors => /^Class(Including|DerivedFrom).*Method/,
509
+ :exclude_types_and_ancestors => ClassIncludingModuleWithPublicInstanceMethod, :methods => :all, :method_options => :exclude_ancestor_methods
510
+ check_class_ancestors pc
511
+ end
512
+ it "should exclude join_points whose types match an excluded ancestor classes." do
513
+ pc = Aquarium::Aspects::Pointcut.new :join_point => @cimpub_jp, :types_and_ancestors => /^Class(Including|DerivedFrom).*Method/,
514
+ :exclude_types_and_ancestors => ClassIncludingModuleWithPublicInstanceMethod, :methods => :all, :method_options => :exclude_ancestor_methods
515
+ check_class_ancestors pc
516
+ end
517
+
518
+ def check_class_descendents pc
519
+ expected_types = [Kernel, ModuleIncludingModuleWithPublicInstanceMethod, ModuleWithPublicInstanceMethod, Object]
520
+ found_types = {}
521
+ pc.join_points_matched.each do |jp|
522
+ next if ignored_join_point(jp)
523
+ expected_types.should include(jp.target_type)
524
+ found_types[jp.target_type] = true
525
+ end
526
+ found_types.size.should == 4
527
+ not_expected_types = @expected_modules_not_matched_jps.map {|jp| jp.target_type}
528
+ pc.join_points_not_matched.each do |jp|
529
+ next if ignored_join_point(jp)
530
+ not_expected_types.should include(jp.target_type)
531
+ end
532
+ end
533
+
534
+ it "should exclude classes specified and their including modules and descendent classes when excluding descendents." do
535
+ pc = Aquarium::Aspects::Pointcut.new :types_and_ancestors => /^Class(Including|DerivedFrom).*Method/,
536
+ :exclude_types_and_descendents => ClassIncludingModuleWithPublicInstanceMethod, :methods => :all, :method_options => :exclude_ancestor_methods
537
+ check_class_descendents pc
538
+ end
539
+ it "should exclude join_points whose types match an excluded descendent types." do
540
+ pc = Aquarium::Aspects::Pointcut.new :join_point => @cimpub_jp, :types_and_ancestors => /^Class(Including|DerivedFrom).*Method/,
541
+ :exclude_types_and_descendents => ClassIncludingModuleWithPublicInstanceMethod, :methods => :all, :method_options => :exclude_ancestor_methods
542
+ check_class_descendents pc
543
+ end
544
+ end
545
+
304
546
  describe Aquarium::Aspects::Pointcut, " (:exclude_objects => objects specified)" do
305
547
  before(:each) do
306
548
  @e11 = ExcludeTestOne.new
@@ -451,7 +693,7 @@ end
451
693
 
452
694
  describe Aquarium::Aspects::Pointcut, " (types or objects specified with public instance methods)" do
453
695
  before(:each) do
454
- before_pointcut_spec
696
+ before_pointcut_class_spec
455
697
  end
456
698
 
457
699
  it "should support MethodFinder's :public and :instance options for the specified types." do
@@ -470,7 +712,7 @@ end
470
712
 
471
713
  describe Aquarium::Aspects::Pointcut, " (types or objects specified with protected instance methods)" do
472
714
  before(:each) do
473
- before_pointcut_spec
715
+ before_pointcut_class_spec
474
716
  end
475
717
 
476
718
  it "should support MethodFinder's :protected and :instance options for the specified types." do
@@ -489,7 +731,7 @@ end
489
731
 
490
732
  describe Aquarium::Aspects::Pointcut, " (types or objects specified with private instance methods)" do
491
733
  before(:each) do
492
- before_pointcut_spec
734
+ before_pointcut_class_spec
493
735
  end
494
736
 
495
737
  it "should support MethodFinder's :private and :instance options for the specified types." do
@@ -508,7 +750,7 @@ end
508
750
 
509
751
  describe Aquarium::Aspects::Pointcut, " (types or objects specified with public class methods)" do
510
752
  before(:each) do
511
- before_pointcut_spec
753
+ before_pointcut_class_spec
512
754
  end
513
755
 
514
756
  it "should support MethodFinder's :public and :class options for the specified types." do
@@ -528,7 +770,7 @@ end
528
770
 
529
771
  describe Aquarium::Aspects::Pointcut, " (types or objects specified with private class methods)" do
530
772
  before(:each) do
531
- before_pointcut_spec
773
+ before_pointcut_class_spec
532
774
  end
533
775
 
534
776
  it "should support MethodFinder's :private and :class options for the specified types." do
@@ -547,7 +789,7 @@ end
547
789
 
548
790
  describe Aquarium::Aspects::Pointcut, " (types or objects specified with method regular expressions)" do
549
791
  before(:each) do
550
- before_pointcut_spec
792
+ before_pointcut_class_spec
551
793
  @jp_rwe = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method_name => :attrRW_ClassWithAttribs=
552
794
  @jp_rw = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method_name => :attrRW_ClassWithAttribs
553
795
  @jp_we = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method_name => :attrW_ClassWithAttribs=
@@ -627,7 +869,7 @@ end
627
869
 
628
870
  describe Aquarium::Aspects::Pointcut, " (types or objects specified with attribute regular expressions)" do
629
871
  before(:each) do
630
- before_pointcut_spec
872
+ before_pointcut_class_spec
631
873
  @jp_rwe = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method_name => :attrRW_ClassWithAttribs=
632
874
  @jp_rw = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method_name => :attrRW_ClassWithAttribs
633
875
  @jp_we = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method_name => :attrW_ClassWithAttribs=
@@ -780,7 +1022,7 @@ end
780
1022
 
781
1023
  describe Aquarium::Aspects::Pointcut, " (join points specified)" do
782
1024
  before(:each) do
783
- before_pointcut_spec
1025
+ before_pointcut_class_spec
784
1026
  @anClassWithPublicInstanceMethod = ClassWithPublicInstanceMethod.new
785
1027
  @expected_matched = [@pub_jp, @pro_jp, @pri_jp, @cpub_jp, @cpri_jp,
786
1028
  Aquarium::Aspects::JoinPoint.new(:object => @anClassWithPublicInstanceMethod, :method => :public_instance_test_method)]
@@ -1057,18 +1299,18 @@ end
1057
1299
 
1058
1300
  describe Aquarium::Aspects::Pointcut, "#candidate_types" do
1059
1301
  before(:each) do
1060
- before_pointcut_spec
1302
+ before_pointcut_class_spec
1061
1303
  end
1062
1304
 
1063
1305
  it "should return only candidate matching types when the input types exist." do
1064
- pc = Aquarium::Aspects::Pointcut.new :types => @example_types
1065
- pc.candidate_types.matched_keys.sort {|x,y| x.to_s <=> y.to_s}.should == @example_types.sort {|x,y| x.to_s <=> y.to_s}
1306
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_classes
1307
+ pc.candidate_types.matched_keys.sort {|x,y| x.to_s <=> y.to_s}.should == @example_classes.sort {|x,y| x.to_s <=> y.to_s}
1066
1308
  pc.candidate_types.not_matched_keys.should == []
1067
1309
  end
1068
1310
 
1069
1311
  it "should return only candidate matching types when the input type names correspond to existing types." do
1070
- pc = Aquarium::Aspects::Pointcut.new :types => @example_types.map {|t| t.to_s}
1071
- pc.candidate_types.matched_keys.sort {|x,y| x.to_s <=> y.to_s}.should == @example_types.sort {|x,y| x.to_s <=> y.to_s}
1312
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_classes.map {|t| t.to_s}
1313
+ pc.candidate_types.matched_keys.sort {|x,y| x.to_s <=> y.to_s}.should == @example_classes.sort {|x,y| x.to_s <=> y.to_s}
1072
1314
  pc.candidate_types.not_matched_keys.should == []
1073
1315
  end
1074
1316
 
@@ -1079,7 +1321,7 @@ describe Aquarium::Aspects::Pointcut, "#candidate_types" do
1079
1321
  end
1080
1322
 
1081
1323
  it "should return no candidate matching or non-matching types when only objects are input." do
1082
- pc = Aquarium::Aspects::Pointcut.new :objects => @example_types.map {|t| t.new}
1324
+ pc = Aquarium::Aspects::Pointcut.new :objects => @example_classes.map {|t| t.new}
1083
1325
  pc.candidate_types.matched_keys.should == []
1084
1326
  pc.candidate_types.not_matched_keys.should == []
1085
1327
  end
@@ -1087,11 +1329,11 @@ end
1087
1329
 
1088
1330
  describe Aquarium::Aspects::Pointcut, "#candidate_objects" do
1089
1331
  before(:each) do
1090
- before_pointcut_spec
1332
+ before_pointcut_class_spec
1091
1333
  end
1092
1334
 
1093
1335
  it "should return only candidate matching objects when the input are objects." do
1094
- example_objs = @example_types.map {|t| t.new}
1336
+ example_objs = @example_classes.map {|t| t.new}
1095
1337
  pc = Aquarium::Aspects::Pointcut.new :objects => example_objs
1096
1338
  example_objs.each do |obj|
1097
1339
  pc.candidate_objects.matched[obj].should_not be(nil?)
@@ -1102,7 +1344,7 @@ end
1102
1344
 
1103
1345
  describe Aquarium::Aspects::Pointcut, "#candidate_join_points" do
1104
1346
  before(:each) do
1105
- before_pointcut_spec
1347
+ before_pointcut_class_spec
1106
1348
  end
1107
1349
 
1108
1350
  it "should return only candidate non-matching join points for the input join points that do not exist." do
@@ -1131,13 +1373,18 @@ end
1131
1373
 
1132
1374
  describe Aquarium::Aspects::Pointcut, "#specification" do
1133
1375
  before(:each) do
1134
- before_pointcut_spec
1376
+ before_pointcut_class_spec
1135
1377
  @empty_set = Set.new
1136
1378
  @default_specification = {
1137
1379
  :types => @empty_set, :objects => @empty_set, :join_points => @empty_set,
1380
+ :types_and_ancestors => @empty_set,
1381
+ :types_and_descendents => @empty_set,
1138
1382
  :methods => @empty_set, :method_options => @empty_set,
1139
1383
  :attributes => @empty_set, :attribute_options => @empty_set,
1140
1384
  :exclude_types => @empty_set,
1385
+ :exclude_types_calculated => @empty_set,
1386
+ :exclude_types_and_ancestors => @empty_set,
1387
+ :exclude_types_and_descendents => @empty_set,
1141
1388
  :exclude_objects => @empty_set,
1142
1389
  :exclude_join_points => @empty_set,
1143
1390
  :exclude_pointcuts => @empty_set,
@@ -1152,38 +1399,38 @@ describe Aquarium::Aspects::Pointcut, "#specification" do
1152
1399
  end
1153
1400
 
1154
1401
  it "should return the input :types and :type arguments combined into an array keyed by :types." do
1155
- pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :type => String
1156
- pc.specification.should == { :types => Set.new(@example_types + [String]) } | @default_specification_all_methods
1402
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_classes, :type => String
1403
+ pc.specification.should == { :types => Set.new(@example_classes + [String]) } | @default_specification_all_methods
1157
1404
  end
1158
1405
 
1159
1406
  it "should return the input :objects and :object arguments combined into an array keyed by :objects." do
1160
- example_objs = @example_types.map {|t| t.new}
1407
+ example_objs = @example_classes.map {|t| t.new}
1161
1408
  s1234 = "1234"
1162
1409
  pc = Aquarium::Aspects::Pointcut.new :objects => example_objs, :object => s1234
1163
1410
  pc.specification.should == { :objects => Set.new(example_objs + [s1234]) } | @default_specification_all_methods
1164
1411
  end
1165
1412
 
1166
1413
  it "should return the input :methods and :method arguments combined into an array keyed by :methods." do
1167
- pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :methods => /^get/, :method => "dup"
1168
- pc.specification.should == { :types => Set.new(@example_types), :methods => Set.new([/^get/, "dup"]) } | @default_specification
1414
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_classes, :methods => /^get/, :method => "dup"
1415
+ pc.specification.should == { :types => Set.new(@example_classes), :methods => Set.new([/^get/, "dup"]) } | @default_specification
1169
1416
  end
1170
1417
 
1171
1418
  it "should return the input :method_options verbatim." do
1172
- pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :methods => /^get/, :method => "dup", :method_options => [:instance, :public]
1173
- pc.specification.should == { :types => Set.new(@example_types), :methods => Set.new([/^get/, "dup"]),
1419
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_classes, :methods => /^get/, :method => "dup", :method_options => [:instance, :public]
1420
+ pc.specification.should == { :types => Set.new(@example_classes), :methods => Set.new([/^get/, "dup"]),
1174
1421
  :method_options => Set.new([:instance, :public]), :default_objects => @empty_set } | @default_specification
1175
1422
  end
1176
1423
 
1177
1424
  it "should return the input :methods and :method arguments combined into an array keyed by :methods." do
1178
- pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :attributes => /^state/, :attribute => "name"
1179
- pc.specification.should == { :types => Set.new(@example_types), :objects => @empty_set, :join_points => @empty_set,
1425
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_classes, :attributes => /^state/, :attribute => "name"
1426
+ pc.specification.should == { :types => Set.new(@example_classes), :objects => @empty_set, :join_points => @empty_set,
1180
1427
  :methods => @empty_set, :method_options => Set.new([]), :default_objects => @empty_set,
1181
1428
  :attributes => Set.new([/^state/, "name"]), :attribute_options => @empty_set } | @default_specification
1182
1429
  end
1183
1430
 
1184
1431
  it "should return the input :attributes, :attribute and :attribute_options arguments, verbatim." do
1185
- pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :attributes => /^state/, :attribute => "name", :attribute_options => :reader
1186
- pc.specification.should == { :types => Set.new(@example_types), :attributes => Set.new([/^state/, "name"]),
1432
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_classes, :attributes => /^state/, :attribute => "name", :attribute_options => :reader
1433
+ pc.specification.should == { :types => Set.new(@example_classes), :attributes => Set.new([/^state/, "name"]),
1187
1434
  :attribute_options => Set.new([:reader]) } | @default_specification
1188
1435
  end
1189
1436
  end