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,800 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/../spec_example_classes'
3
+ require 'aquarium/extensions/hash'
4
+ require 'aquarium/aspects/pointcut'
5
+ require 'aquarium/utils'
6
+
7
+ def common_setup
8
+ @example_types_without_public_instance_method =
9
+ [ClassWithProtectedInstanceMethod, ClassWithPrivateInstanceMethod, ClassWithPublicClassMethod, ClassWithPrivateClassMethod]
10
+ @example_types = ([ClassWithPublicInstanceMethod] + @example_types_without_public_instance_method)
11
+ @pub_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithPublicInstanceMethod, :method_name => :public_instance_test_method
12
+ @pro_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithProtectedInstanceMethod, :method_name => :protected_instance_test_method
13
+ @pri_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithPrivateInstanceMethod, :method_name => :private_instance_test_method
14
+ @cpub_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithPublicClassMethod, :method_name => :public_class_test_method, :is_class_method => true
15
+ @cpri_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithPrivateClassMethod, :method_name => :private_class_test_method, :is_class_method => true
16
+ @apro_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithProtectedInstanceMethod, :method_name => :all
17
+ @apri_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithPrivateInstanceMethod, :method_name => :all
18
+ @acpub_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithPublicClassMethod, :method_name => :all
19
+ @acpri_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithPrivateClassMethod, :method_name => :all
20
+ @expected_matched_jps = Set.new [@pub_jp]
21
+ @expected_not_matched_jps = Set.new [@apro_jp, @apri_jp, @acpub_jp, @acpri_jp]
22
+ end
23
+
24
+ describe Aquarium::Aspects::Pointcut, " (empty)" do
25
+ it "should match no join points by default." do
26
+ pc = Aquarium::Aspects::Pointcut.new
27
+ pc.should be_empty
28
+ end
29
+
30
+ it "should match no join points if nil is the only argument specified." do
31
+ pc = Aquarium::Aspects::Pointcut.new nil
32
+ pc.should be_empty
33
+ end
34
+
35
+ it "should match no join points if types = [] specified." do
36
+ pc = Aquarium::Aspects::Pointcut.new :types => []
37
+ pc.should be_empty
38
+ end
39
+
40
+ it "should match no join points if types = nil specified." do
41
+ pc = Aquarium::Aspects::Pointcut.new :types => nil
42
+ pc.should be_empty
43
+ end
44
+
45
+ it "should match no join points if objects = [] specified." do
46
+ pc = Aquarium::Aspects::Pointcut.new :objects => []
47
+ pc.should be_empty
48
+ end
49
+
50
+ it "should match no join points if objects = nil specified." do
51
+ pc = Aquarium::Aspects::Pointcut.new :objects => nil
52
+ pc.should be_empty
53
+ end
54
+ end
55
+
56
+ describe Aquarium::Aspects::Pointcut, "#empty?" do
57
+ it "should be true if there are no matched and no unmatched join points." do
58
+ pc = Aquarium::Aspects::Pointcut.new
59
+ pc.join_points_matched.size.should == 0
60
+ pc.join_points_not_matched.size.should == 0
61
+ pc.should be_empty
62
+ end
63
+
64
+ it "should be false if there are matched join points." do
65
+ pc = Aquarium::Aspects::Pointcut.new :types => [ClassWithAttribs], :methods => [/^attr/]
66
+ pc.join_points_matched.size.should > 0
67
+ pc.join_points_not_matched.size.should == 0
68
+ pc.should_not be_empty
69
+ end
70
+
71
+ it "should be false if there are unmatched join points." do
72
+ pc = Aquarium::Aspects::Pointcut.new :types => [String], :methods => [/^attr/]
73
+ pc.join_points_matched.size.should == 0
74
+ pc.join_points_not_matched.size.should > 0
75
+ pc.should_not be_empty
76
+ end
77
+ end
78
+
79
+ describe Aquarium::Aspects::Pointcut, " (types specified using regular expressions)" do
80
+ setup do
81
+ common_setup
82
+ end
83
+
84
+ it "should match multiple classes using regular expressions." do
85
+ pc = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :method_options => :suppress_ancestor_methods
86
+ pc.join_points_matched.should == @expected_matched_jps
87
+ pc.join_points_not_matched.should == @expected_not_matched_jps
88
+ end
89
+ end
90
+
91
+ describe Aquarium::Aspects::Pointcut, " (types specified using names)" do
92
+ setup do
93
+ common_setup
94
+ end
95
+
96
+ it "should match multiple classes using names." do
97
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_types.map {|t| t.to_s}, :method_options => :suppress_ancestor_methods
98
+ pc.join_points_matched.should == @expected_matched_jps
99
+ pc.join_points_not_matched.should == @expected_not_matched_jps
100
+ end
101
+
102
+ it "should match multiple classes using types themselves." do
103
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :method_options => :suppress_ancestor_methods
104
+ pc.join_points_matched.should == @expected_matched_jps
105
+ pc.join_points_not_matched.should == @expected_not_matched_jps
106
+ end
107
+
108
+ it "should match :all public instance methods for types by default." do
109
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :method_options => :suppress_ancestor_methods
110
+ pc.join_points_matched.should == @expected_matched_jps
111
+ pc.join_points_not_matched.should == @expected_not_matched_jps
112
+ end
113
+
114
+ it "should support MethodFinder's :suppress_ancestor_methods option when using types." do
115
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :method_options => :suppress_ancestor_methods
116
+ pc.join_points_matched.should == @expected_matched_jps
117
+ pc.join_points_not_matched.should == @expected_not_matched_jps
118
+ end
119
+ end
120
+
121
+ describe Aquarium::Aspects::Pointcut, " (objects specified)" do
122
+ setup do
123
+ common_setup
124
+ end
125
+
126
+ it "should match :all public instance methods for objects by default." do
127
+ pub, pro = ClassWithPublicInstanceMethod.new, ClassWithProtectedInstanceMethod.new
128
+ pc = Aquarium::Aspects::Pointcut.new :objects => [pub, pro], :method_options => :suppress_ancestor_methods
129
+ pc.join_points_matched.should == Set.new([Aquarium::Aspects::JoinPoint.new(:object => pub, :method_name => :public_instance_test_method)])
130
+ pc.join_points_not_matched.should == Set.new([Aquarium::Aspects::JoinPoint.new(:object => pro, :method_name => :all)])
131
+ end
132
+
133
+ it "should support MethodFinder's :suppress_ancestor_methods option when using objects." do
134
+ pub, pro = ClassWithPublicInstanceMethod.new, ClassWithProtectedInstanceMethod.new
135
+ pc = Aquarium::Aspects::Pointcut.new :objects => [pub, pro], :method_options => :suppress_ancestor_methods
136
+ pc.join_points_matched.should == Set.new([Aquarium::Aspects::JoinPoint.new(:object => pub, :method_name => :public_instance_test_method)])
137
+ pc.join_points_not_matched.should == Set.new([Aquarium::Aspects::JoinPoint.new(:object => pro, :method_name => :all)])
138
+ end
139
+
140
+ it "should match all possible methods on the specified objects." do
141
+ pub, pro = ClassWithPublicInstanceMethod.new, ClassWithProtectedInstanceMethod.new
142
+ pc = Aquarium::Aspects::Pointcut.new :objects => [pub, pro], :methods => :all, :method_options => [:public, :protected, :suppress_ancestor_methods]
143
+ pc.join_points_matched.size.should == 2
144
+ pc.join_points_not_matched.size.should == 0
145
+ pc.join_points_matched.should == Set.new([
146
+ Aquarium::Aspects::JoinPoint.new(:object => pro, :method_name => :protected_instance_test_method),
147
+ Aquarium::Aspects::JoinPoint.new(:object => pub, :method_name => :public_instance_test_method)])
148
+ end
149
+ end
150
+
151
+ describe Aquarium::Aspects::Pointcut, " (types or objects specified with public instance methods)" do
152
+ setup do
153
+ common_setup
154
+ end
155
+
156
+ it "should support MethodFinder's :public and :instance options for the specified types." do
157
+ pc = Aquarium::Aspects::Pointcut.new :types => ClassWithPublicInstanceMethod, :method_options => [:public, :instance, :suppress_ancestor_methods]
158
+ pc.join_points_matched.should eql(Set.new([@pub_jp]))
159
+ pc.join_points_not_matched.size.should == 0
160
+ end
161
+
162
+ it "should support MethodFinder's :public and :instance options for the specified objects." do
163
+ pub = ClassWithPublicInstanceMethod.new
164
+ pc = Aquarium::Aspects::Pointcut.new :objects => pub, :method_options => [:public, :instance, :suppress_ancestor_methods]
165
+ pc.join_points_matched.should eql(Set.new([Aquarium::Aspects::JoinPoint.new(:object => pub, :method_name => :public_instance_test_method)]))
166
+ pc.join_points_not_matched.size.should == 0
167
+ end
168
+ end
169
+
170
+ describe Aquarium::Aspects::Pointcut, " (types or objects specified with protected instance methods)" do
171
+ setup do
172
+ common_setup
173
+ end
174
+
175
+ it "should support MethodFinder's :protected and :instance options for the specified types." do
176
+ pc = Aquarium::Aspects::Pointcut.new :types => ClassWithProtectedInstanceMethod, :method_options => [:protected, :instance, :suppress_ancestor_methods]
177
+ pc.join_points_matched.should eql(Set.new([@pro_jp]))
178
+ pc.join_points_not_matched.size.should == 0
179
+ end
180
+
181
+ it "should support MethodFinder's :protected and :instance options for the specified objects." do
182
+ pro = ClassWithProtectedInstanceMethod.new
183
+ pc = Aquarium::Aspects::Pointcut.new :objects => pro, :method_options => [:protected, :instance, :suppress_ancestor_methods]
184
+ pc.join_points_matched.should eql(Set.new([Aquarium::Aspects::JoinPoint.new(:object => pro, :method_name => :protected_instance_test_method)]))
185
+ pc.join_points_not_matched.size.should == 0
186
+ end
187
+ end
188
+
189
+ describe Aquarium::Aspects::Pointcut, " (types or objects specified with private instance methods)" do
190
+ setup do
191
+ common_setup
192
+ end
193
+
194
+ it "should support MethodFinder's :private and :instance options for the specified types." do
195
+ pc = Aquarium::Aspects::Pointcut.new :types => ClassWithPrivateInstanceMethod, :method_options => [:private, :instance, :suppress_ancestor_methods]
196
+ pc.join_points_matched.should eql(Set.new([@pri_jp]))
197
+ pc.join_points_not_matched.size.should == 0
198
+ end
199
+
200
+ it "should support MethodFinder's :private and :instance options for the specified objects." do
201
+ pro = ClassWithPrivateInstanceMethod.new
202
+ pc = Aquarium::Aspects::Pointcut.new :objects => pro, :method_options => [:private, :instance, :suppress_ancestor_methods]
203
+ pc.join_points_matched.should eql(Set.new([Aquarium::Aspects::JoinPoint.new(:object => pro, :method_name => :private_instance_test_method)]))
204
+ pc.join_points_not_matched.size.should == 0
205
+ end
206
+ end
207
+
208
+ describe Aquarium::Aspects::Pointcut, " (types or objects specified with public class methods)" do
209
+ setup do
210
+ common_setup
211
+ end
212
+
213
+ it "should support MethodFinder's :public and :class options for the specified types." do
214
+ pc = Aquarium::Aspects::Pointcut.new :types => ClassWithPublicClassMethod, :method_options => [:public, :class, :suppress_ancestor_methods]
215
+ pc.join_points_matched.should eql(Set.new([@cpub_jp]))
216
+ pc.join_points_not_matched.size.should == 0
217
+ end
218
+
219
+ it "should support MethodFinder's :public and :class options for the specified objects, which will return no methods." do
220
+ pub = ClassWithPublicInstanceMethod.new
221
+ pc = Aquarium::Aspects::Pointcut.new :objects => pub, :method_options => [:public, :class, :suppress_ancestor_methods]
222
+ pc.join_points_matched.size.should == 0
223
+ pc.join_points_not_matched.size.should == 1
224
+ pc.join_points_not_matched.should eql(Set.new([Aquarium::Aspects::JoinPoint.new(:object => pub, :method_name => :all, :is_class_method => true)]))
225
+ end
226
+ end
227
+
228
+ describe Aquarium::Aspects::Pointcut, " (types or objects specified with private class methods)" do
229
+ setup do
230
+ common_setup
231
+ end
232
+
233
+ it "should support MethodFinder's :private and :class options for the specified types." do
234
+ pc = Aquarium::Aspects::Pointcut.new :types => ClassWithPrivateClassMethod, :method_options => [:private, :class, :suppress_ancestor_methods]
235
+ pc.join_points_matched.should eql(Set.new([@cpri_jp]))
236
+ pc.join_points_not_matched.size.should == 0
237
+ end
238
+
239
+ it "should support MethodFinder's :private and :class options for the specified objects, which will return no methods." do
240
+ pri = ClassWithPrivateInstanceMethod.new
241
+ pc = Aquarium::Aspects::Pointcut.new :objects => pri, :method_options => [:private, :class, :suppress_ancestor_methods]
242
+ pc.join_points_not_matched.should eql(Set.new([Aquarium::Aspects::JoinPoint.new(:object => pri, :method_name => :all, :is_class_method => true)]))
243
+ pc.join_points_not_matched.size.should == 1
244
+ end
245
+ end
246
+
247
+ describe Aquarium::Aspects::Pointcut, " (types or objects specified with method regular expressions)" do
248
+ setup do
249
+ common_setup
250
+ @jp_rwe = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method_name => :attrRW_ClassWithAttribs=
251
+ @jp_rw = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method_name => :attrRW_ClassWithAttribs
252
+ @jp_we = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method_name => :attrW_ClassWithAttribs=
253
+ @jp_r = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method_name => :attrR_ClassWithAttribs
254
+ @expected_for_types = Set.new([@jp_rw, @jp_rwe, @jp_r, @jp_we])
255
+ @object_of_ClassWithAttribs = ClassWithAttribs.new
256
+ @jp_rwe_o = Aquarium::Aspects::JoinPoint.new :object => @object_of_ClassWithAttribs, :method_name => :attrRW_ClassWithAttribs=
257
+ @jp_rw_o = Aquarium::Aspects::JoinPoint.new :object => @object_of_ClassWithAttribs, :method_name => :attrRW_ClassWithAttribs
258
+ @jp_we_o = Aquarium::Aspects::JoinPoint.new :object => @object_of_ClassWithAttribs, :method_name => :attrW_ClassWithAttribs=
259
+ @jp_r_o = Aquarium::Aspects::JoinPoint.new :object => @object_of_ClassWithAttribs, :method_name => :attrR_ClassWithAttribs
260
+ @expected_for_objects = Set.new([@jp_rw_o, @jp_rwe_o, @jp_r_o, @jp_we_o])
261
+ end
262
+
263
+ it "should match on public method readers and writers for type names by default." do
264
+ pc = Aquarium::Aspects::Pointcut.new :types => "ClassWithAttribs", :methods => [/^attr/]
265
+ pc.join_points_matched.should == @expected_for_types
266
+ end
267
+
268
+ it "should match on public method readers and writers for types by default." do
269
+ pc = Aquarium::Aspects::Pointcut.new :types => ClassWithAttribs, :methods => [/^attr/]
270
+ pc.join_points_matched.should == @expected_for_types
271
+ end
272
+
273
+ it "should match on public method readers and writers for objects by default." do
274
+ pc = Aquarium::Aspects::Pointcut.new :object => @object_of_ClassWithAttribs, :methods => [/^attr/]
275
+ pc.join_points_matched.should == @expected_for_objects
276
+ end
277
+ end
278
+
279
+ describe Aquarium::Aspects::Pointcut, " (types or objects specified with attribute regular expressions)" do
280
+ setup do
281
+ common_setup
282
+ @jp_rwe = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method_name => :attrRW_ClassWithAttribs=
283
+ @jp_rw = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method_name => :attrRW_ClassWithAttribs
284
+ @jp_we = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method_name => :attrW_ClassWithAttribs=
285
+ @jp_r = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method_name => :attrR_ClassWithAttribs
286
+ @expected_for_types = Set.new([@jp_rw, @jp_rwe, @jp_r, @jp_we])
287
+ @object_of_ClassWithAttribs = ClassWithAttribs.new
288
+ @jp_rwe_o = Aquarium::Aspects::JoinPoint.new :object => @object_of_ClassWithAttribs, :method_name => :attrRW_ClassWithAttribs=
289
+ @jp_rw_o = Aquarium::Aspects::JoinPoint.new :object => @object_of_ClassWithAttribs, :method_name => :attrRW_ClassWithAttribs
290
+ @jp_we_o = Aquarium::Aspects::JoinPoint.new :object => @object_of_ClassWithAttribs, :method_name => :attrW_ClassWithAttribs=
291
+ @jp_r_o = Aquarium::Aspects::JoinPoint.new :object => @object_of_ClassWithAttribs, :method_name => :attrR_ClassWithAttribs
292
+ @expected_for_objects = Set.new([@jp_rw_o, @jp_rwe_o, @jp_r_o, @jp_we_o])
293
+ end
294
+
295
+ it "should match on public attribute readers and writers for type names by default." do
296
+ pc = Aquarium::Aspects::Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/]
297
+ pc.join_points_matched.should == @expected_for_types
298
+ end
299
+
300
+ it "should match on public attribute readers and writers for types by default." do
301
+ pc = Aquarium::Aspects::Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/]
302
+ pc.join_points_matched.should == @expected_for_types
303
+ end
304
+
305
+ it "should match on public attribute readers and writers for objects by default." do
306
+ pc = Aquarium::Aspects::Pointcut.new :object => @object_of_ClassWithAttribs, :attributes => [/^attr/]
307
+ pc.join_points_matched.should == @expected_for_objects
308
+ end
309
+
310
+ it "should match attribute specifications for types that are prefixed with @." do
311
+ pc = Aquarium::Aspects::Pointcut.new :types => "ClassWithAttribs", :attributes => [/^@attr/]
312
+ pc.join_points_matched.should == @expected_for_types
313
+ end
314
+
315
+ it "should match attribute specifications for objects that are prefixed with @." do
316
+ pc = Aquarium::Aspects::Pointcut.new :object => @object_of_ClassWithAttribs, :attributes => [/^@attr/]
317
+ pc.join_points_matched.should == @expected_for_objects
318
+ end
319
+
320
+ it "should match attribute specifications that are regular expressions of symbols." do
321
+ pc = Aquarium::Aspects::Pointcut.new :types => "ClassWithAttribs", :attributes => [/^:attr/]
322
+ pc.join_points_matched.should == @expected_for_types
323
+ end
324
+
325
+ it "should match attribute specifications for objects that are regular expressions of symbols." do
326
+ object = ClassWithAttribs.new
327
+ pc = Aquarium::Aspects::Pointcut.new :object => object, :attributes => [/^:attr/]
328
+ pc.join_points_matched.should == Set.new([
329
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrRW_ClassWithAttribs),
330
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrRW_ClassWithAttribs=),
331
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrR_ClassWithAttribs),
332
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrW_ClassWithAttribs=)])
333
+ end
334
+
335
+ it "should match public attribute readers and writers for types when both the :readers and :writers options are specified." do
336
+ pc = Aquarium::Aspects::Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:readers, :writers]
337
+ pc.join_points_matched.should == @expected_for_types
338
+ end
339
+
340
+ it "should match public attribute readers and writers for objects when both the :readers and :writers options are specified." do
341
+ object = ClassWithAttribs.new
342
+ pc = Aquarium::Aspects::Pointcut.new :object => object, :attributes => [/^:attr/], :attribute_options => [:readers, :writers]
343
+ pc.join_points_matched.should == Set.new([
344
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrRW_ClassWithAttribs),
345
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrRW_ClassWithAttribs=),
346
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrR_ClassWithAttribs),
347
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrW_ClassWithAttribs=)])
348
+ end
349
+
350
+ it "should match public attribute readers for types only when the :readers option is specified." do
351
+ pc = Aquarium::Aspects::Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:readers]
352
+ pc.join_points_matched.should == Set.new([
353
+ Aquarium::Aspects::JoinPoint.new(:type => "ClassWithAttribs", :method_name => :attrRW_ClassWithAttribs),
354
+ Aquarium::Aspects::JoinPoint.new(:type => "ClassWithAttribs", :method_name => :attrR_ClassWithAttribs)])
355
+ end
356
+
357
+ it "should match public attribute readers for objects only when the :readers option is specified." do
358
+ object = ClassWithAttribs.new
359
+ pc = Aquarium::Aspects::Pointcut.new :object => object, :attributes => [/^:attr/], :attribute_options => [:readers]
360
+ pc.join_points_matched.should == Set.new([
361
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrRW_ClassWithAttribs),
362
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrR_ClassWithAttribs)])
363
+ end
364
+
365
+ it "should match public attribute writers for types only when the :writers option is specified." do
366
+ pc = Aquarium::Aspects::Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:writers]
367
+ pc.join_points_matched.should == Set.new([
368
+ Aquarium::Aspects::JoinPoint.new(:type => "ClassWithAttribs", :method_name => :attrRW_ClassWithAttribs=),
369
+ Aquarium::Aspects::JoinPoint.new(:type => "ClassWithAttribs", :method_name => :attrW_ClassWithAttribs=)])
370
+ end
371
+
372
+ it "should match public attribute writers for objects only when the :writers option is specified." do
373
+ object = ClassWithAttribs.new
374
+ pc = Aquarium::Aspects::Pointcut.new :object => object, :attributes => [/^:attr/], :attribute_options => [:writers]
375
+ pc.join_points_matched.should == Set.new([
376
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrRW_ClassWithAttribs=),
377
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrW_ClassWithAttribs=)])
378
+ end
379
+
380
+ it "should match attribute writers for types whether or not the attributes specification ends with an equal sign." do
381
+ pc = Aquarium::Aspects::Pointcut.new :types => "ClassWithAttribs",
382
+ :attributes => [/^attr[RW]+_ClassWithAttribs=/], :attribute_options => [:writers]
383
+ pc.join_points_matched.should == Set.new([
384
+ Aquarium::Aspects::JoinPoint.new(:type => "ClassWithAttribs", :method_name => :attrRW_ClassWithAttribs=),
385
+ Aquarium::Aspects::JoinPoint.new(:type => "ClassWithAttribs", :method_name => :attrW_ClassWithAttribs=)])
386
+ pc2 = Aquarium::Aspects::Pointcut.new :types => "ClassWithAttribs",
387
+ :attributes => [/^attr[RW]+_ClassWithAttribs/], :attribute_options => [:writers]
388
+ pc2.join_points_matched.should == Set.new([
389
+ Aquarium::Aspects::JoinPoint.new(:type => "ClassWithAttribs", :method_name => :attrRW_ClassWithAttribs=),
390
+ Aquarium::Aspects::JoinPoint.new(:type => "ClassWithAttribs", :method_name => :attrW_ClassWithAttribs=)])
391
+ end
392
+
393
+ it "should match attribute writers for objects whether or not the attributes specification ends with an equal sign." do
394
+ object = ClassWithAttribs.new
395
+ pc = Aquarium::Aspects::Pointcut.new :object => object, :attributes => [/^attr[RW]+_ClassWithAttribs=/], :attribute_options => [:writers]
396
+ pc.join_points_matched.should == Set.new([
397
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrRW_ClassWithAttribs=),
398
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrW_ClassWithAttribs=)])
399
+ pc2 = Aquarium::Aspects::Pointcut.new :object => object, :attributes => [/^attr[RW]+_ClassWithAttribs/], :attribute_options => [:writers]
400
+ pc2.join_points_matched.should == Set.new([
401
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrRW_ClassWithAttribs=),
402
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrW_ClassWithAttribs=)])
403
+ end
404
+
405
+ it "should match attribute readers for types when the :readers option is specified even if the attributes specification ends with an equal sign!" do
406
+ pc = Aquarium::Aspects::Pointcut.new :types => "ClassWithAttribs",
407
+ :attributes => [/^attr[RW]+_ClassWithAttribs=/], :attribute_options => [:readers]
408
+ pc.join_points_matched.should == Set.new([
409
+ Aquarium::Aspects::JoinPoint.new(:type => "ClassWithAttribs", :method_name => :attrRW_ClassWithAttribs),
410
+ Aquarium::Aspects::JoinPoint.new(:type => "ClassWithAttribs", :method_name => :attrR_ClassWithAttribs)])
411
+ pc2 = Aquarium::Aspects::Pointcut.new :types => "ClassWithAttribs",
412
+ :attributes => [/^attr[RW]+_ClassWithAttribs=/], :attribute_options => [:readers]
413
+ pc2.join_points_matched.should == Set.new([
414
+ Aquarium::Aspects::JoinPoint.new(:type => "ClassWithAttribs", :method_name => :attrRW_ClassWithAttribs),
415
+ Aquarium::Aspects::JoinPoint.new(:type => "ClassWithAttribs", :method_name => :attrR_ClassWithAttribs)])
416
+ end
417
+
418
+ it "should match attribute readers for objects when the :readers option is specified even if the attributes specification ends with an equal sign!" do
419
+ object = ClassWithAttribs.new
420
+ pc = Aquarium::Aspects::Pointcut.new :object => object, :attributes => [/^attr[RW]+_ClassWithAttribs=/], :attribute_options => [:readers]
421
+ pc.join_points_matched.should == Set.new([
422
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrRW_ClassWithAttribs),
423
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrR_ClassWithAttribs)])
424
+ pc2 = Aquarium::Aspects::Pointcut.new :object => object, :attributes => [/^attr[RW]+_ClassWithAttribs/], :attribute_options => [:readers]
425
+ pc2.join_points_matched.should == Set.new([
426
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrRW_ClassWithAttribs),
427
+ Aquarium::Aspects::JoinPoint.new(:object => object, :method_name => :attrR_ClassWithAttribs)])
428
+ end
429
+ end
430
+
431
+ describe Aquarium::Aspects::Pointcut, " (methods that end in non-alphanumeric characters)" do
432
+ class ClassWithFunkyMethodNames
433
+ def huh?; true; end
434
+ def yes!; true; end
435
+ def x= other; false; end
436
+ def == other; false; end
437
+ def =~ other; false; end
438
+ end
439
+
440
+ before(:each) do
441
+ @funky = ClassWithFunkyMethodNames.new
442
+ end
443
+
444
+ {'?' => :huh?, '!' => :yes!, '=' => :x=}.each do |char, method|
445
+ it "should match instance methods for types when searching for names that end with a '#{char}' character." do
446
+ pc = Aquarium::Aspects::Pointcut.new :types => ClassWithFunkyMethodNames, :method => method, :method_options => [:suppress_ancestor_methods]
447
+ expected_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithFunkyMethodNames, :method_name => method
448
+ pc.join_points_matched.should == Set.new([expected_jp])
449
+ end
450
+
451
+ it "should match instance methods for objects when searching for names that end with a '#{char}' character." do
452
+ pc = Aquarium::Aspects::Pointcut.new :object => @funky, :method => method, :method_options => [:suppress_ancestor_methods]
453
+ expected_jp = Aquarium::Aspects::JoinPoint.new :object => @funky, :method_name => method
454
+ pc.join_points_matched.should == Set.new([expected_jp])
455
+ end
456
+
457
+ it "should match instance methods for types when searching for names that end with a '#{char}' character, using a regular expressions." do
458
+ pc = Aquarium::Aspects::Pointcut.new :types => ClassWithFunkyMethodNames, :methods => /#{Regexp.escape(char)}$/, :method_options => [:suppress_ancestor_methods]
459
+ expected_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithFunkyMethodNames, :method_name => method
460
+ pc.join_points_matched.should == Set.new([expected_jp])
461
+ end
462
+
463
+ it "should match instance methods for object when searching for names that end with a '#{char}' character, using a regular expressions." do
464
+ pc = Aquarium::Aspects::Pointcut.new :object => @funky, :methods => /#{Regexp.escape(char)}$/, :method_options => [:suppress_ancestor_methods]
465
+ expected_jp = Aquarium::Aspects::JoinPoint.new :object => @funky, :method_name => method
466
+ pc.join_points_matched.should == Set.new([expected_jp])
467
+ end
468
+ end
469
+
470
+ {'=' => :==, '~' => :=~}.each do |char, method|
471
+ it "should match the #{method} instance method for types, if you don't suppress ancestor methods, even if the method is defined in the class!" do
472
+ pc = Aquarium::Aspects::Pointcut.new :types => ClassWithFunkyMethodNames, :method => method, :method_options => [:instance]
473
+ expected_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithFunkyMethodNames, :method_name => method
474
+ pc.join_points_matched.should == Set.new([expected_jp])
475
+ end
476
+
477
+ it "should match the #{method} instance method for objects, if you don't suppress ancestor methods, even if the method is defined in the class!" do
478
+ pc = Aquarium::Aspects::Pointcut.new :object => @funky, :method => method, :method_options => [:instance]
479
+ expected_jp = Aquarium::Aspects::JoinPoint.new :object => @funky, :method_name => method
480
+ pc.join_points_matched.should == Set.new([expected_jp])
481
+ end
482
+
483
+ it "should match the #{method} instance method for types when using a regular expressions, if you don't suppress ancestor methods, even if the method is defined in the class!" do
484
+ pc = Aquarium::Aspects::Pointcut.new :types => ClassWithFunkyMethodNames, :methods => /#{Regexp.escape(char)}$/, :method_options => [:instance]
485
+ pc.join_points_matched.any? {|jp| jp.method_name == method}.should be_true
486
+ end
487
+
488
+ it "should match the #{method} instance method for objects when using a regular expressions, if you don't suppress ancestor methods, even if the method is defined in the class!" do
489
+ pc = Aquarium::Aspects::Pointcut.new :object => @funky, :methods => /#{Regexp.escape(char)}$/, :method_options => [:instance]
490
+ pc.join_points_matched.any? {|jp| jp.method_name == method}.should be_true
491
+ end
492
+ end
493
+ end
494
+
495
+ describe Aquarium::Aspects::Pointcut, " (:attributes => :all option not yet supported)" do
496
+
497
+ it "should raise if :all is used for attributes for types (not yet supported)." do
498
+ lambda { Aquarium::Aspects::Pointcut.new :types => "ClassWithAttribs", :attributes => :all }.should raise_error(Aquarium::Utils::InvalidOptions)
499
+ end
500
+
501
+ it "should raise if :all is used for attributes for objects (not yet supported)." do
502
+ lambda { Aquarium::Aspects::Pointcut.new :object => ClassWithAttribs.new, :attributes => :all }.should raise_error(Aquarium::Utils::InvalidOptions)
503
+ end
504
+ end
505
+
506
+ describe "Aquarium::Aspects::Pointcut" do
507
+
508
+ setup do
509
+ class Empty; end
510
+
511
+ @objectWithSingletonMethod = Empty.new
512
+ class << @objectWithSingletonMethod
513
+ def a_singleton_method
514
+ end
515
+ end
516
+
517
+ class NotQuiteEmpty
518
+ end
519
+ class << NotQuiteEmpty
520
+ def a_class_singleton_method
521
+ end
522
+ end
523
+ @notQuiteEmpty = NotQuiteEmpty.new
524
+ end
525
+
526
+ it "should find instance-level singleton method joinpoints for objects when :singleton is specified." do
527
+ pc = Aquarium::Aspects::Pointcut.new :objects => [@notQuiteEmpty, @objectWithSingletonMethod], :methods => :all, :method_options => [:singleton]
528
+ pc.join_points_matched.should == Set.new([Aquarium::Aspects::JoinPoint.new(:object => @objectWithSingletonMethod, :method_name => :a_singleton_method)])
529
+ pc.join_points_not_matched.should == Set.new([Aquarium::Aspects::JoinPoint.new(:object => @notQuiteEmpty, :method_name => :all)])
530
+ end
531
+
532
+ it "should find type-level singleton methods for types when :singleton is specified." do
533
+ pc = Aquarium::Aspects::Pointcut.new :types => [NotQuiteEmpty, Empty], :methods => :all, :method_options => [:singleton, :suppress_ancestor_methods]
534
+ pc.join_points_matched.should == Set.new([Aquarium::Aspects::JoinPoint.new(:type => NotQuiteEmpty, :method_name => :a_class_singleton_method)])
535
+ pc.join_points_not_matched.should == Set.new([Aquarium::Aspects::JoinPoint.new(:type => Empty, :method_name => :all)])
536
+ end
537
+
538
+ it "should raise when specifying method options :singleton with :class, :public, :protected, or :private." do
539
+ lambda { Aquarium::Aspects::Pointcut.new :types => [NotQuiteEmpty, Empty], :methods => :all, :method_options => [:singleton, :class]}.should raise_error(Aquarium::Utils::InvalidOptions)
540
+ lambda { Aquarium::Aspects::Pointcut.new :types => [NotQuiteEmpty, Empty], :methods => :all, :method_options => [:singleton, :public]}.should raise_error(Aquarium::Utils::InvalidOptions)
541
+ lambda { Aquarium::Aspects::Pointcut.new :types => [NotQuiteEmpty, Empty], :methods => :all, :method_options => [:singleton, :protected]}.should raise_error(Aquarium::Utils::InvalidOptions)
542
+ lambda { Aquarium::Aspects::Pointcut.new :types => [NotQuiteEmpty, Empty], :methods => :all, :method_options => [:singleton, :private]}.should raise_error(Aquarium::Utils::InvalidOptions)
543
+ end
544
+ end
545
+
546
+
547
+ describe Aquarium::Aspects::Pointcut, "#eql?" do
548
+ it "should return true for the same Aquarium::Aspects::Pointcut object." do
549
+ pc = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :methods => /_test_method$/
550
+ pc.should eql(pc)
551
+ pc1 = Aquarium::Aspects::Pointcut.new :object => ClassWithPublicClassMethod.new, :methods => /_test_method$/
552
+ pc1.should eql(pc1)
553
+ end
554
+
555
+ it "should return true for Aquarium::Aspects::Pointcuts that specify the same types and methods." do
556
+ pc1 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :methods => /_test_method$/
557
+ pc2 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :methods => /_test_method$/
558
+ pc1.should eql(pc2)
559
+ end
560
+
561
+ it "should return false for Aquarium::Aspects::Pointcuts that specify different types." do
562
+ pc1 = Aquarium::Aspects::Pointcut.new :types => /ClassWithPublicMethod/
563
+ pc2 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/
564
+ pc1.should_not eql(pc2)
565
+ end
566
+
567
+ it "should return false for Aquarium::Aspects::Pointcuts that specify different types, even if no methods match." do
568
+ pc1 = Aquarium::Aspects::Pointcut.new :types => /ClassWithPublicMethod/, :methods => /foobar/
569
+ pc2 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/ , :methods => /foobar/
570
+ pc1.should_not eql(pc2)
571
+ end
572
+
573
+ it "should return false for Aquarium::Aspects::Pointcuts that specify different methods." do
574
+ pc1 = Aquarium::Aspects::Pointcut.new :types => /ClassWithPublicMethod/, :methods =>/^private/
575
+ pc2 = Aquarium::Aspects::Pointcut.new :types => /ClassWithPublicMethod/, :methods =>/^public/
576
+ pc1.should_not eql(pc2)
577
+ end
578
+
579
+ it "should return false for Aquarium::Aspects::Pointcuts that specify equivalent objects that are not the same object." do
580
+ pc1 = Aquarium::Aspects::Pointcut.new :object => ClassWithPublicClassMethod.new, :methods => /_test_method$/
581
+ pc2 = Aquarium::Aspects::Pointcut.new :object => ClassWithPublicClassMethod.new, :methods => /_test_method$/
582
+ pc1.should_not eql(pc2)
583
+ end
584
+
585
+ it "should return false for Aquarium::Aspects::Pointcuts that specify equivalent objects that are not the same object, even if no methods match." do
586
+ pc1 = Aquarium::Aspects::Pointcut.new :object => ClassWithPublicClassMethod.new, :methods => /foobar/
587
+ pc2 = Aquarium::Aspects::Pointcut.new :object => ClassWithPublicClassMethod.new, :methods => /foobar/
588
+ pc1.should_not eql(pc2)
589
+ end
590
+
591
+ it "should return false if the matched types are different." do
592
+ pc1 = Aquarium::Aspects::Pointcut.new :types => /ClassWithPublicMethod/
593
+ pc2 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/
594
+ pc1.should_not eql(pc2)
595
+ end
596
+
597
+ it "should return false if the matched objects are different." do
598
+ pc1 = Aquarium::Aspects::Pointcut.new :object => ClassWithPublicClassMethod.new, :methods => /_test_method$/
599
+ pc2 = Aquarium::Aspects::Pointcut.new :object => ClassWithPrivateClassMethod.new, :methods => /_test_method$/
600
+ pc1.should_not eql(pc2)
601
+ end
602
+
603
+ it "should return false if the not_matched types are different." do
604
+ pc1 = Aquarium::Aspects::Pointcut.new :types => /Foo/
605
+ pc2 = Aquarium::Aspects::Pointcut.new :types => /Bar/
606
+ pc1.should_not eql(pc2)
607
+ end
608
+
609
+ it "should return false if the matched methods for the same types are different." do
610
+ pc1 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :methods => /public.*_test_method$/
611
+ pc2 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :methods => /_test_method$/
612
+ pc1.should_not == pc2
613
+ end
614
+
615
+ it "should return false if the matched methods for the same objects are different." do
616
+ pub = ClassWithPublicInstanceMethod.new
617
+ pri = ClassWithPrivateInstanceMethod.new
618
+ pc1 = Aquarium::Aspects::Pointcut.new :objects => [pub, pri], :methods => /public.*_test_method$/
619
+ pc2 = Aquarium::Aspects::Pointcut.new :objects => [pub, pri], :methods => /_test_method$/
620
+ pc1.should_not == pc2
621
+ end
622
+
623
+ it "should return false if the not_matched methods for the same types are different." do
624
+ pc1 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :methods => /foo/
625
+ pc2 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :methods => /bar/
626
+ pc1.should_not == pc2
627
+ end
628
+
629
+ it "should return false if the not_matched methods for the same objects are different." do
630
+ pub = ClassWithPublicInstanceMethod.new
631
+ pri = ClassWithPrivateInstanceMethod.new
632
+ pc1 = Aquarium::Aspects::Pointcut.new :objects => [pub, pri], :methods => /foo/
633
+ pc2 = Aquarium::Aspects::Pointcut.new :objects => [pub, pri], :methods => /bar/
634
+ pc1.should_not == pc2
635
+ end
636
+
637
+ it "should return false if the matched attributes for the same types are different." do
638
+ pc1 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :attributes => /attrRW/
639
+ pc2 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :attributes => /attrR/
640
+ pc1.should_not == pc2
641
+ end
642
+
643
+ it "should return false if the matched attributes for the same objects are different." do
644
+ pub = ClassWithPublicInstanceMethod.new
645
+ pri = ClassWithPrivateInstanceMethod.new
646
+ pc1 = Aquarium::Aspects::Pointcut.new :objects => [pub, pri], :attributes => /attrRW/
647
+ pc2 = Aquarium::Aspects::Pointcut.new :objects => [pub, pri], :attributes => /attrR/
648
+ pc1.should_not == pc2
649
+ end
650
+
651
+ it "should return false if the not_matched attributes for the same types are different." do
652
+ pc1 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :attributes => /foo/
653
+ pc2 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :attributes => /bar/
654
+ pc1.should_not == pc2
655
+ end
656
+
657
+ it "should return false if the not_matched attributes for the same objects are different." do
658
+ pub = ClassWithPublicInstanceMethod.new
659
+ pri = ClassWithPrivateInstanceMethod.new
660
+ pc1 = Aquarium::Aspects::Pointcut.new :objects => [pub, pri], :attributes => /foo/
661
+ pc2 = Aquarium::Aspects::Pointcut.new :objects => [pub, pri], :attributes => /bar/
662
+ pc1.should_not == pc2
663
+ end
664
+ end
665
+
666
+ describe "Aquarium::Aspects::Pointcut#eql?" do
667
+ it "should be an alias for #==" do
668
+ pc1 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :methods => /_test_method$/
669
+ pc2 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/, :methods => /_test_method$/
670
+ pc3 = Aquarium::Aspects::Pointcut.new :objects => [ClassWithPublicInstanceMethod.new, ClassWithPublicInstanceMethod.new]
671
+ pc1.should eql(pc1)
672
+ pc1.should eql(pc2)
673
+ pc1.should_not eql(pc3)
674
+ pc2.should_not eql(pc3)
675
+ end
676
+ end
677
+
678
+ describe "Aquarium::Aspects::Pointcut#candidate_types" do
679
+ setup do
680
+ common_setup
681
+ end
682
+
683
+ it "should return only candidate matching types when the input types exist." do
684
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_types
685
+ 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}
686
+ pc.candidate_types.not_matched_keys.should == []
687
+ end
688
+
689
+ it "should return only candidate matching types when the input type names correspond to existing types." do
690
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_types.map {|t| t.to_s}
691
+ 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}
692
+ pc.candidate_types.not_matched_keys.should == []
693
+ end
694
+
695
+ it "should return only candidate non-matching types when the input types do not exist." do
696
+ pc = Aquarium::Aspects::Pointcut.new :types => 'NonExistentClass'
697
+ pc.candidate_types.matched_keys.should == []
698
+ pc.candidate_types.not_matched_keys.should == ['NonExistentClass']
699
+ end
700
+
701
+ it "should return no candidate matching or non-matching types when only objects are input." do
702
+ pc = Aquarium::Aspects::Pointcut.new :objects => @example_types.map {|t| t.new}
703
+ pc.candidate_types.matched_keys.should == []
704
+ pc.candidate_types.not_matched_keys.should == []
705
+ end
706
+ end
707
+
708
+ describe "Aquarium::Aspects::Pointcut#candidate_objects" do
709
+ setup do
710
+ common_setup
711
+ end
712
+
713
+ it "should return only candidate matching objects when the input are objects." do
714
+ example_objs = @example_types.map {|t| t.new}
715
+ pc = Aquarium::Aspects::Pointcut.new :objects => example_objs
716
+ example_objs.each do |obj|
717
+ pc.candidate_objects.matched[obj].should_not be(nil?)
718
+ end
719
+ pc.candidate_objects.not_matched_keys.should == []
720
+ end
721
+ end
722
+
723
+ describe "Aquarium::Aspects::Pointcut#specification" do
724
+ setup do
725
+ common_setup
726
+ @expected_specification_subset = {
727
+ :methods => [:all], :method_options => [:suppress_ancestor_methods],
728
+ :attributes => [], :attribute_options => []}
729
+ @empty_set = Set.new
730
+ end
731
+
732
+ it "should return ':attribute_options => []', by default, if no arguments are given." do
733
+ pc = Aquarium::Aspects::Pointcut.new
734
+ pc.specification.should == { :types => @empty_set, :objects => @empty_set, :default_object => @empty_set,
735
+ :methods => Set.new([:all]), :method_options => Set.new([]),
736
+ :attributes => @empty_set, :attribute_options => @empty_set }
737
+ end
738
+
739
+ it "should return the input :types and :type arguments combined into an array keyed by :types." do
740
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :type => String
741
+ pc.specification.should == { :types => Set.new(@example_types + [String]), :objects => @empty_set, :default_object => @empty_set,
742
+ :methods => Set.new([:all]), :method_options => Set.new([]),
743
+ :attributes => @empty_set, :attribute_options => @empty_set }
744
+ end
745
+
746
+ it "should return the input :objects and :object arguments combined into an array keyed by :objects." do
747
+ example_objs = @example_types.map {|t| t.new}
748
+ s1234 = "1234"
749
+ pc = Aquarium::Aspects::Pointcut.new :objects => example_objs, :object => s1234
750
+ pc.specification.should == { :types => @empty_set, :objects => Set.new(example_objs + [s1234]), :default_object => @empty_set,
751
+ :methods => Set.new([:all]), :method_options => Set.new([]),
752
+ :attributes => @empty_set, :attribute_options => @empty_set }
753
+ end
754
+
755
+ it "should return the input :methods and :method arguments combined into an array keyed by :methods." do
756
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :methods => /^get/, :method => "dup"
757
+ pc.specification.should == { :types => Set.new(@example_types), :objects => @empty_set, :default_object => @empty_set,
758
+ :methods => Set.new([/^get/, "dup"]), :method_options => Set.new([]),
759
+ :attributes => @empty_set, :attribute_options => @empty_set }
760
+ end
761
+
762
+ it "should return the input :method_options verbatim." do
763
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :methods => /^get/, :method => "dup", :method_options => [:instance, :public]
764
+ pc.specification.should == { :types => Set.new(@example_types), :objects => @empty_set, :default_object => @empty_set,
765
+ :methods => Set.new([/^get/, "dup"]), :method_options => Set.new([:instance, :public]),
766
+ :attributes => @empty_set, :attribute_options => @empty_set }
767
+ end
768
+
769
+ it "should return the input :methods and :method arguments combined into an array keyed by :methods." do
770
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :attributes => /^state/, :attribute => "name"
771
+ pc.specification.should == { :types => Set.new(@example_types), :objects => @empty_set, :default_object => @empty_set,
772
+ :methods => @empty_set, :method_options => Set.new([]),
773
+ :attributes => Set.new([/^state/, "name"]), :attribute_options => @empty_set }
774
+ end
775
+
776
+ it "should return the input :attributes, :attribute and :attribute_options arguments, verbatim." do
777
+ pc = Aquarium::Aspects::Pointcut.new :types => @example_types, :attributes => /^state/, :attribute => "name", :attribute_options => :reader
778
+ pc.specification.should == { :types => Set.new(@example_types), :objects => @empty_set, :default_object => @empty_set,
779
+ :methods => @empty_set, :method_options => Set.new([]),
780
+ :attributes => Set.new([/^state/, "name"]), :attribute_options => Set.new([:reader]) }
781
+ end
782
+ end
783
+
784
+ describe "Aquarium::Aspects::Pointcut.make_attribute_method_names" do
785
+ before do
786
+ @expected_attribs = Set.new(%w[a a= b b= c c= d d=])
787
+ end
788
+
789
+ it "should generate attribute reader and writer method names when the attribute name is prefixed with @." do
790
+ Aquarium::Aspects::Pointcut.make_attribute_method_names(%w[@a @b @c @d]).should == @expected_attribs
791
+ end
792
+
793
+ it "should generate attribute reader and writer method names when the attribute name is not prefixed with @." do
794
+ Aquarium::Aspects::Pointcut.make_attribute_method_names(%w[a b c d]).should == @expected_attribs
795
+ end
796
+
797
+ it "should generate attribute reader and writer method names when the attribute name is a symbol." do
798
+ Aquarium::Aspects::Pointcut.make_attribute_method_names([:a, :b, :c, :d]).should == @expected_attribs
799
+ end
800
+ end