aquarium 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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