aquarium 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. data/Aquarium.ipr +253 -0
  2. data/Aquarium.iws +629 -0
  3. data/CHANGES +43 -0
  4. data/UPGRADE +13 -7
  5. data/examples/method_tracing_example_spec.rb +4 -1
  6. data/lib/aquarium/aspects/aspect.rb +28 -11
  7. data/lib/aquarium/aspects/exclusion_handler.rb +1 -1
  8. data/lib/aquarium/aspects/join_point.rb +58 -14
  9. data/lib/aquarium/aspects/pointcut.rb +5 -6
  10. data/lib/aquarium/extras/design_by_contract.rb +1 -1
  11. data/lib/aquarium/finders/method_finder.rb +1 -4
  12. data/lib/aquarium/finders/type_finder.rb +8 -1
  13. data/lib/aquarium/utils.rb +1 -0
  14. data/lib/aquarium/utils/default_logger.rb +20 -0
  15. data/lib/aquarium/utils/options_utils.rb +74 -12
  16. data/lib/aquarium/utils/type_utils.rb +1 -7
  17. data/lib/aquarium/version.rb +1 -1
  18. data/spec/aquarium/aspects/advice_chain_node_spec.rb +1 -1
  19. data/spec/aquarium/aspects/advice_spec.rb +1 -1
  20. data/spec/aquarium/aspects/aspect_invocation_spec.rb +1531 -1465
  21. data/spec/aquarium/aspects/aspect_spec.rb +22 -27
  22. data/spec/aquarium/aspects/aspect_with_nested_types_spec.rb +1 -1
  23. data/spec/aquarium/aspects/aspect_with_subtypes_spec.rb +1 -1
  24. data/spec/aquarium/aspects/concurrent_aspects_spec.rb +1 -1
  25. data/spec/aquarium/aspects/concurrent_aspects_with_objects_and_types_spec.rb +1 -1
  26. data/spec/aquarium/aspects/dsl/aspect_dsl_spec.rb +434 -424
  27. data/spec/aquarium/aspects/join_point_spec.rb +27 -4
  28. data/spec/aquarium/aspects/pointcut_and_composition_spec.rb +98 -102
  29. data/spec/aquarium/aspects/pointcut_or_composition_spec.rb +95 -107
  30. data/spec/aquarium/aspects/pointcut_spec.rb +1365 -1382
  31. data/spec/aquarium/extensions/hash_spec.rb +1 -1
  32. data/spec/aquarium/extensions/set_spec.rb +1 -1
  33. data/spec/aquarium/finders/finder_result_spec.rb +1 -1
  34. data/spec/aquarium/finders/method_finder_spec.rb +1 -1
  35. data/spec/aquarium/finders/type_finder_with_descendents_and_ancestors_spec.rb +63 -145
  36. data/spec/aquarium/{spec_example_classes.rb → spec_example_types.rb} +35 -0
  37. data/spec/aquarium/utils/default_logger_spec.rb +28 -0
  38. data/spec/aquarium/utils/hash_utils_spec.rb +1 -1
  39. data/spec/aquarium/utils/logic_error_spec.rb +1 -1
  40. data/spec/aquarium/utils/name_utils_spec.rb +1 -1
  41. data/spec/aquarium/utils/nil_object_spec.rb +1 -1
  42. data/spec/aquarium/utils/options_utils_spec.rb +122 -0
  43. data/spec/aquarium/utils/set_utils_spec.rb +1 -1
  44. metadata +9 -4
@@ -1,5 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
- require File.dirname(__FILE__) + '/../spec_example_classes'
2
+ require File.dirname(__FILE__) + '/../spec_example_types'
3
3
 
4
4
  require 'aquarium/extensions/hash'
5
5
  require 'aquarium/aspects/join_point'
@@ -22,18 +22,41 @@ end
22
22
 
23
23
  describe Aquarium::Aspects::JoinPoint, "#initialize with invalid parameters" do
24
24
 
25
- it "should require either a :type or an :object parameter when creating." do
25
+ it "should require either a :type or an :object parameter, but not both." do
26
26
  lambda { Aquarium::Aspects::JoinPoint.new :method_name => :count }.should raise_error(Aquarium::Utils::InvalidOptions)
27
27
  lambda { Aquarium::Aspects::JoinPoint.new :type => String, :object => "", :method_name => :count }.should raise_error(Aquarium::Utils::InvalidOptions)
28
28
  end
29
29
 
30
- it "should require a :method_name parameter when creating." do
30
+ it "should require a :method_name." do
31
31
  lambda { Aquarium::Aspects::JoinPoint.new :type => String }.should raise_error(Aquarium::Utils::InvalidOptions)
32
32
  end
33
33
 
34
- it "should except :method as a synonym for the :method_name parameter." do
34
+ it "should except :method as a synonym for :method_name." do
35
35
  lambda { Aquarium::Aspects::JoinPoint.new :type => String, :method => :split }.should_not raise_error(Aquarium::Utils::InvalidOptions)
36
36
  end
37
+
38
+ it "should require a valid type name if a name is specified." do
39
+ lambda { Aquarium::Aspects::JoinPoint.new :type => "String", :method => :split }.should_not raise_error(Aquarium::Utils::InvalidOptions)
40
+ lambda { Aquarium::Aspects::JoinPoint.new :type => "Stringgy", :method => :split }.should raise_error(Aquarium::Utils::InvalidOptions)
41
+ end
42
+
43
+ it "should require a valid type name symbol if a name is specified." do
44
+ lambda { Aquarium::Aspects::JoinPoint.new :type => :String, :method => :split }.should_not raise_error(Aquarium::Utils::InvalidOptions)
45
+ lambda { Aquarium::Aspects::JoinPoint.new :type => :Stringgy, :method => :split }.should raise_error(Aquarium::Utils::InvalidOptions)
46
+ end
47
+
48
+ it "should require a valid type name regular expression if one is specified." do
49
+ lambda { Aquarium::Aspects::JoinPoint.new :type => /^String$/, :method => :split }.should_not raise_error(Aquarium::Utils::InvalidOptions)
50
+ lambda { Aquarium::Aspects::JoinPoint.new :type => /^Stringgy$/, :method => :split }.should raise_error(Aquarium::Utils::InvalidOptions)
51
+ end
52
+
53
+ it "should reject a regular expression that matches no types." do
54
+ lambda { Aquarium::Aspects::JoinPoint.new :type => /^Stringgy$/, :method => :split }.should raise_error(Aquarium::Utils::InvalidOptions)
55
+ end
56
+
57
+ it "should reject a regular expression that matches more than one type." do
58
+ lambda { Aquarium::Aspects::JoinPoint.new :type => /^M/, :method => :split }.should raise_error(Aquarium::Utils::InvalidOptions)
59
+ end
37
60
  end
38
61
 
39
62
  describe Aquarium::Aspects::JoinPoint, "#initialize with parameters that specify class vs. instance methods" do
@@ -1,14 +1,39 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
- require File.dirname(__FILE__) + '/../spec_example_classes'
2
+ require File.dirname(__FILE__) + '/../spec_example_types'
3
3
  require 'aquarium/utils'
4
4
  require 'aquarium/extensions'
5
5
  require 'aquarium/aspects/pointcut'
6
6
  require 'aquarium/aspects/pointcut_composition'
7
7
 
8
- describe "Intersection of Pointcuts", :shared => true do
9
- include Aquarium::Utils::HashUtils
10
- # include Aquarium::Utils::HtmlEscaper
8
+ include Aquarium::Utils::HashUtils
9
+ include Aquarium::Aspects
10
+
11
+ describe Pointcut, "#and" do
12
+ it "should return a new Pointcut." do
13
+ pc1 = Pointcut.new
14
+ pc2 = Pointcut.new :types => ClassWithPublicInstanceMethod, :method_options => :exclude_ancestor_methods
15
+ pc12 = (pc1.and(pc2))
16
+ pc12.should_not equal(pc1)
17
+ pc12.should_not equal(pc2)
18
+ end
19
+ end
20
+
21
+ describe Pointcut, "#and (when one pointcut is empty)" do
22
+ before :all do
23
+ @pc1 = Pointcut.new
24
+ @pc2 = Pointcut.new :types => ClassWithPublicInstanceMethod, :method_options => :exclude_ancestor_methods
25
+ end
11
26
 
27
+ it "should return a new empty Pointcut if the left-hand Pointcut is empty, independent of the right-hand Pointcut." do
28
+ (@pc1.and(@pc2)).should == @pc1
29
+ end
30
+
31
+ it "should return a new empty Pointcut if the right-hand Pointcut is empty, independent of the left-hand Pointcut." do
32
+ (@pc2.and(@pc1)).should == @pc1
33
+ end
34
+ end
35
+
36
+ describe Pointcut, "#and (when both pointcuts are not empty)" do
12
37
  before(:each) do
13
38
  @example_types = {}
14
39
  [ClassWithPublicInstanceMethod, ClassWithProtectedInstanceMethod, ClassWithPrivateInstanceMethod,
@@ -16,145 +41,116 @@ describe "Intersection of Pointcuts", :shared => true do
16
41
  @empty_set = Set.new
17
42
  end
18
43
 
19
- it "should return an empty Aquarium::Aspects::Pointcut if the left-hand Aquarium::Aspects::Pointcut is empty, independent of the right-hand Aquarium::Aspects::Pointcut." do
20
- pc1 = Aquarium::Aspects::Pointcut.new
21
- pc2 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/
22
- (pc1.and(pc2)).should == pc1
23
- pc3 = Aquarium::Aspects::Pointcut.new :object => ClassWithPublicInstanceMethod.new
24
- (pc1.and(pc3)).should == pc1
25
- end
26
-
27
- it "should return an empty Aquarium::Aspects::Pointcut if the second pointcut has no join points." do
28
- pc1 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/
29
- pc2 = Aquarium::Aspects::Pointcut.new
30
- (pc1.and(pc2)).should == pc2
31
- pc3 = Aquarium::Aspects::Pointcut.new :object => ClassWithPublicInstanceMethod.new
32
- (pc3.and(pc2)).should == pc2
33
- end
34
-
35
- it "should return a new Aquarium::Aspects::Pointcut whose join points are the intersection of the left- and right-hand side Aquarium::Aspects::Pointcuts, each with multiple types." do
36
- pc1 = Aquarium::Aspects::Pointcut.new :types => [ClassWithAttribs, ClassWithPublicInstanceMethod, ClassWithPrivateInstanceMethod], :attributes => [/^attr/], :attribute_options => [:readers]
37
- pc2 = Aquarium::Aspects::Pointcut.new :types => [ClassWithAttribs, ClassWithPublicInstanceMethod, ClassWithProtectedInstanceMethod], :attributes => :attrRW_ClassWithAttribs
44
+ it "should return a new Pointcut whose join points are the intersection of the left- and right-hand side Pointcuts, each with multiple types." do
45
+ pc1 = Pointcut.new :types => [ClassWithAttribs, ClassWithPublicInstanceMethod, ClassWithPrivateInstanceMethod], :attributes => [/^attr/], :attribute_options => [:readers]
46
+ pc2 = Pointcut.new :types => [ClassWithAttribs, ClassWithPublicInstanceMethod, ClassWithProtectedInstanceMethod], :attributes => :attrRW_ClassWithAttribs, :attribute_options => [:exclude_ancestor_methods]
38
47
  pc = pc1.and pc2
39
- expected_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method => :attrRW_ClassWithAttribs
48
+ expected_jp = JoinPoint.new :type => ClassWithAttribs, :method => :attrRW_ClassWithAttribs
40
49
  pc.join_points_matched.should == Set.new([expected_jp])
41
50
  pc.join_points_not_matched.should == @empty_set
42
51
  end
43
52
 
44
- it "should return a new Aquarium::Aspects::Pointcut whose join points are the intersection of the left- and right-hand side Aquarium::Aspects::Pointcuts, each with multiple objects." do
53
+ it "should return a new Pointcut whose join points are the intersection of the left- and right-hand side Pointcuts, each with multiple objects." do
45
54
  cwa = ClassWithAttribs.new
46
55
  pub = ClassWithPublicInstanceMethod.new
47
56
  pri = ClassWithPrivateInstanceMethod.new
48
57
  pro = ClassWithProtectedInstanceMethod.new
49
- pc1 = Aquarium::Aspects::Pointcut.new :objects => [cwa, pub, pri], :attributes => [/^attr/], :attribute_options => [:readers]
50
- pc2 = Aquarium::Aspects::Pointcut.new :objects => [cwa, pub, pro], :attributes => :attrRW_ClassWithAttribs
58
+ pc1 = Pointcut.new :objects => [cwa, pub, pri], :attributes => [/^attr/], :attribute_options => [:readers, :exclude_ancestor_methods]
59
+ pc2 = Pointcut.new :objects => [cwa, pub, pro], :attributes => :attrRW_ClassWithAttribs
51
60
  pc = pc1.and pc2
52
- expected_jp = Aquarium::Aspects::JoinPoint.new :object => cwa, :method => :attrRW_ClassWithAttribs
61
+ expected_jp = JoinPoint.new :object => cwa, :method => :attrRW_ClassWithAttribs
53
62
  pc.join_points_matched.should == Set.new([expected_jp])
54
63
  pc.join_points_not_matched.should == @empty_set
55
64
  end
56
65
 
57
- it "should return a new Aquarium::Aspects::Pointcut whose join points are the intersection of the left- and right-hand side Aquarium::Aspects::Pointcuts, each with a single type." do
58
- pc1 = Aquarium::Aspects::Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:readers]
59
- pc2 = Aquarium::Aspects::Pointcut.new :types => "ClassWithAttribs", :attributes => :attrRW_ClassWithAttribs
66
+ it "should return a new Pointcut whose join points are the intersection of the left- and right-hand side Pointcuts, each with a single type." do
67
+ pc1 = Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:readers]
68
+ pc2 = Pointcut.new :types => "ClassWithAttribs", :attributes => :attrRW_ClassWithAttribs
60
69
  pc = pc1.and pc2
61
- expected_jp = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method => :attrRW_ClassWithAttribs
70
+ expected_jp = JoinPoint.new :type => ClassWithAttribs, :method => :attrRW_ClassWithAttribs
62
71
  pc.join_points_matched.should == Set.new([expected_jp])
63
72
  pc.join_points_not_matched.should == @empty_set
64
73
  end
65
74
 
66
- it "should return a new Aquarium::Aspects::Pointcut whose join points are the intersection of the left- and right-hand side Aquarium::Aspects::Pointcuts, each with a single object." do
75
+ it "should return a new Pointcut whose join points are the intersection of the left- and right-hand side Pointcuts, each with a single object." do
67
76
  cwa = ClassWithAttribs.new
68
- pc1 = Aquarium::Aspects::Pointcut.new :object => cwa, :attributes => [/^attr/], :attribute_options => [:readers]
69
- pc2 = Aquarium::Aspects::Pointcut.new :object => cwa, :attributes => :attrRW_ClassWithAttribs
77
+ pc1 = Pointcut.new :object => cwa, :attributes => [/^attr/], :attribute_options => [:readers]
78
+ pc2 = Pointcut.new :object => cwa, :attributes => :attrRW_ClassWithAttribs
70
79
  pc = pc1.and pc2
71
- expected_jp = Aquarium::Aspects::JoinPoint.new :object => cwa, :method => :attrRW_ClassWithAttribs
80
+ expected_jp = JoinPoint.new :object => cwa, :method => :attrRW_ClassWithAttribs
72
81
  pc.join_points_matched.should == Set.new([expected_jp])
73
82
  pc.join_points_not_matched.should == @empty_set
74
83
  end
75
-
76
- it "should be unitary for type-based Aquarium::Aspects::Pointcuts." do
77
- pc1 = Aquarium::Aspects::Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/], :attribute_options => [:writers]
78
- pc2 = Aquarium::Aspects::Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/], :attribute_options => [:writers]
79
- pc = pc1.and pc2
80
- pc.should == pc1
81
- pc.should == pc2
84
+ end
85
+
86
+ describe Pointcut, "#and (algebraic properties for type-based pointcuts)" do
87
+ before :all do
88
+ @pc1 = Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/], :attribute_options => [:writers]
89
+ @pc2 = Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/], :attribute_options => [:writers]
90
+ @pc3 = Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/]
82
91
  end
83
92
 
84
- it "should be unitary for object-based Aquarium::Aspects::Pointcuts." do
85
- cwa = ClassWithAttribs.new
86
- pc1 = Aquarium::Aspects::Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:writers]
87
- pc2 = Aquarium::Aspects::Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:writers]
88
- pc = pc1.and pc2
89
- pc.should == pc1
90
- pc.should == pc2
93
+ it "should be unitary for type-based Pointcuts." do
94
+ pc = @pc1.and @pc2
95
+ pc.should == @pc1
96
+ pc.should == @pc2
91
97
  end
92
-
93
- it "should be commutative for type-based Aquarium::Aspects::Pointcuts." do
94
- pc1 = Aquarium::Aspects::Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/], :attribute_options => [:writers]
95
- pc2 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/
96
- pc12 = pc1.and pc2
97
- pc21 = pc2.and pc1
98
- pc12.should == pc21
98
+
99
+ it "should be commutative for type-based Pointcuts." do
100
+ pc13 = @pc1.and @pc3
101
+ pc31 = @pc3.and @pc1
102
+ pc13.should == pc31
99
103
  end
100
104
 
101
- it "should be commutative for object-based Aquarium::Aspects::Pointcuts." do
105
+ it "should be associativity for type-based Pointcuts." do
106
+ pc123a = (@pc1.and(@pc2)).and(@pc3)
107
+ pc123b = @pc1.and(@pc2.and(@pc3))
108
+ pc123a.should == pc123b
109
+ end
110
+ end
111
+
112
+ describe Pointcut, "#and (algebraic properties for object-based pointcuts)" do
113
+ before :all do
102
114
  cwa = ClassWithAttribs.new
103
- pub = ClassWithPublicInstanceMethod.new
104
- pc1 = Aquarium::Aspects::Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:writers]
105
- pc2 = Aquarium::Aspects::Pointcut.new :objects => pub, :attributes => [/^attr/], :attribute_options => [:writers]
106
- pc12 = pc1.and pc2
107
- pc21 = pc2.and pc1
108
- pc12.should == pc21
115
+ @pc1 = Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:writers]
116
+ @pc2 = Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:writers]
117
+ @pc3 = Pointcut.new :objects => cwa, :attributes => [/^attr/]
118
+ end
119
+
120
+ it "should be unitary for object-based Pointcuts." do
121
+ pc = @pc1.and @pc2
122
+ pc.should == @pc1
123
+ pc.should == @pc2
109
124
  end
110
125
 
111
- it "should be associativity for type-based Aquarium::Aspects::Pointcuts." do
112
- pc1 = Aquarium::Aspects::Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/], :attribute_options => [:writers]
113
- pc2 = Aquarium::Aspects::Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/], :attribute_options => [:readers]
114
- pc3 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/
115
- pc123a = (pc1.and(pc2)).and(pc3)
116
- pc123b = pc1.and(pc2.and(pc3))
117
- pc123a.should == pc123b
126
+ it "should be commutative for object-based Pointcuts." do
127
+ pc13 = @pc1.and @pc3
128
+ pc31 = @pc3.and @pc1
129
+ pc13.should == pc31
118
130
  end
119
-
120
- it "should be associativity for object-based Aquarium::Aspects::Pointcuts." do
121
- cwa = ClassWithAttribs.new
122
- pub = ClassWithPublicInstanceMethod.new
123
- pc1 = Aquarium::Aspects::Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:writers]
124
- pc2 = Aquarium::Aspects::Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:readers]
125
- pc3 = Aquarium::Aspects::Pointcut.new :objects => pub
126
- pc123a = (pc1.and(pc2)).and(pc3)
127
- pc123b = pc1.and(pc2.and(pc3))
131
+
132
+ it "should be associativity for object-based Pointcuts." do
133
+ pc123a = (@pc1.and(@pc2)).and(@pc3)
134
+ pc123b = @pc1.and(@pc2.and(@pc3))
128
135
  pc123a.should == pc123b
129
136
  end
130
137
  end
131
138
 
132
- describe Aquarium::Aspects::Pointcut, "#and" do
133
- it_should_behave_like "Intersection of Pointcuts"
134
- end
135
-
136
- describe Aquarium::Aspects::Pointcut, "#&" do
137
- include Aquarium::Utils::HashUtils
139
+ describe Pointcut, "#&" do
138
140
 
139
- it_should_behave_like "Intersection of Pointcuts"
140
-
141
- it "should be associativity for type-based Aquarium::Aspects::Pointcuts." do
142
- pc1 = Aquarium::Aspects::Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/], :attribute_options => [:writers]
143
- pc2 = Aquarium::Aspects::Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/], :attribute_options => [:readers]
144
- pc3 = Aquarium::Aspects::Pointcut.new :types => /Class.*Method/
141
+ it "should be a synonym for #and." do
142
+ pc1 = Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/], :attribute_options => [:writers]
143
+ pc2 = Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/], :attribute_options => [:writers]
144
+ pc3 = Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/]
145
145
  pc123a = (pc1 & pc2) & pc3
146
146
  pc123b = pc1 & (pc2 & pc3)
147
147
  pc123a.should == pc123b
148
- end
149
-
150
- it "should be associativity for object-based Aquarium::Aspects::Pointcuts." do
151
148
  cwa = ClassWithAttribs.new
152
- pub = ClassWithPublicInstanceMethod.new
153
- pc1 = Aquarium::Aspects::Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:writers]
154
- pc2 = Aquarium::Aspects::Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:readers]
155
- pc3 = Aquarium::Aspects::Pointcut.new :objects => pub
156
- pc123a = (pc1 & pc2) & pc3
157
- pc123b = pc1 & (pc2 & pc3)
158
- pc123a.should == pc123b
149
+ pca = Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:writers]
150
+ pcb = Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:writers]
151
+ pcc = Pointcut.new :objects => cwa, :attributes => [/^attr/]
152
+ pcabc1 = (pca & pcb) & pcc
153
+ pcabc2 = pca & (pcb & pcc)
154
+ pcabc1.should == pcabc2
159
155
  end
160
156
  end
@@ -1,5 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
- require File.dirname(__FILE__) + '/../spec_example_classes'
2
+ require File.dirname(__FILE__) + '/../spec_example_types'
3
3
  require 'aquarium/utils'
4
4
  require 'aquarium/extensions'
5
5
  require 'aquarium/aspects/pointcut'
@@ -8,148 +8,136 @@ require 'aquarium/aspects/pointcut_composition'
8
8
  include Aquarium::Utils::HashUtils
9
9
  include Aquarium::Aspects
10
10
 
11
- describe "Union of Pointcuts", :shared => true do
11
+ describe Pointcut, "#or" do
12
12
 
13
- before(:each) do
14
- classes = [
15
- ClassWithProtectedInstanceMethod,
16
- ClassWithPrivateInstanceMethod,
17
- ClassWithPublicClassMethod,
18
- ClassWithPrivateClassMethod,
19
- ClassIncludingModuleWithPrivateClassMethod,
20
- ClassIncludingModuleWithPublicClassMethod,
21
- ClassIncludingModuleWithProtectedInstanceMethod,
22
- ClassIncludingModuleWithPrivateInstanceMethod]
23
- jps_array = classes.map {|c| Aquarium::Aspects::JoinPoint.new :type => c, :method => :all}
24
- @not_matched_jps = Set.new(jps_array)
13
+ before :all do
14
+ @pc1 = Pointcut.new
15
+ @pc2 = Pointcut.new :types => /Class.*Public.*Method/, :method_options => [:exclude_ancestor_methods]
16
+ @pc3 = Pointcut.new :object => ClassWithProtectedInstanceMethod.new, :method_options => [:protected, :exclude_ancestor_methods]
25
17
  end
26
-
27
- it "should return a Pointcut equal to the second, appended, non-empty Pointcut if self is empty (has no join points)." do
28
- pc1 = Pointcut.new
29
- pc2 = Pointcut.new :types => /Class.*Method/
30
- pc1.or(pc2).should eql(pc2)
31
- pc3 = Pointcut.new :object => ClassWithPublicInstanceMethod.new
32
- pc1.or(pc3).should eql(pc3)
18
+
19
+ it "should return a new Pointcut equal to the second, appended, non-empty Pointcut if self is empty (has no join points)." do
20
+ @pc1.or(@pc2).should eql(@pc2)
21
+ @pc1.or(@pc3).should eql(@pc3)
33
22
  end
34
23
 
35
- it "should return a Pointcut equal to self if the second pointcut is empty." do
36
- pc1 = Pointcut.new :types => /Class.*Method/
37
- pc2 = Pointcut.new
38
- pc1.or(pc2).should eql(pc1)
39
- pc3 = Pointcut.new :object => ClassWithPublicInstanceMethod.new
40
- pc3.or(pc2).should eql(pc3)
24
+ it "should return a new Pointcut equal to self if the second pointcut is empty." do
25
+ @pc2.or(@pc1).should eql(@pc2)
26
+ @pc3.or(@pc1).should eql(@pc3)
41
27
  end
28
+ end
42
29
 
30
+ describe Pointcut, "#or (with two non-empty pointcuts)" do
31
+
43
32
  it "should return a new Pointcut whose join points are the union of the left- and right-hand side Pointcuts for type-based Pointcuts." do
44
- pc1 = Pointcut.new :types => ClassWithAttribs, :attributes => [/^attr/], :attribute_options => [:writers, :exclude_ancestor_methods]
45
- # "[^F]" excludes the ClassWithFunkyMethodNames ...
46
- pc2 = Pointcut.new :types => [/ClassWith[^F]+Method/, /ClassDerived/, /ClassIncludingMod/], :method_options => :exclude_ancestor_methods
47
- pc = pc1.or pc2
48
- jp1 = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method => :attrRW_ClassWithAttribs=
49
- jp2 = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttribs, :method => :attrW_ClassWithAttribs=
50
- jp3 = Aquarium::Aspects::JoinPoint.new :type => ClassWithPublicInstanceMethod, :method => :public_instance_test_method
51
- jp4 = Aquarium::Aspects::JoinPoint.new :type => ClassWithPublicInstanceMethod2, :method => :public_instance_test_method2
52
- jp5 = Aquarium::Aspects::JoinPoint.new :type => ClassDerivedFromClassIncludingModuleWithPublicInstanceMethod, :method => :public_instance_class_derived_from_class_including_module_test_method
53
- jp6 = Aquarium::Aspects::JoinPoint.new :type => ClassIncludingModuleWithPublicInstanceMethod, :method => :public_instance_class_including_module_test_method
54
- pc.join_points_matched.should == Set.new([jp1, jp2, jp3, jp4, jp5, jp6])
55
- pc.join_points_not_matched.should == @not_matched_jps
33
+ pc4 = Pointcut.new :type => ClassWithPublicInstanceMethod, :method_options => :exclude_ancestor_methods
34
+ pc5 = Pointcut.new :type => ClassWithAttribs, :methods => /^attr.*=$/, :method_options => :exclude_ancestor_methods
35
+ jp_np1 = JoinPoint.new :type => ClassIncludingModuleWithPublicInstanceMethod, :method => :public_instance_class_including_module_test_method
36
+ jp_np2 = JoinPoint.new :type => ModuleWithPublicInstanceMethod, :method => :public_instance_module_test_method
37
+ pc4.join_points_not_matched << jp_np1
38
+ pc5.join_points_not_matched << jp_np2
39
+ pc = pc4.or pc5
40
+ jp1 = JoinPoint.new :type => ClassWithAttribs, :method => :attrRW_ClassWithAttribs=
41
+ jp2 = JoinPoint.new :type => ClassWithAttribs, :method => :attrW_ClassWithAttribs=
42
+ jp3 = JoinPoint.new :type => ClassWithPublicInstanceMethod, :method => :public_instance_test_method
43
+ pc.join_points_matched.should == Set.new([jp1, jp2, jp3])
44
+ pc.join_points_not_matched.should == Set.new([jp_np1, jp_np2])
56
45
  end
57
46
 
58
47
  it "should return a new Pointcut whose join points are the union of the left- and right-hand side Pointcuts for object-based Pointcuts." do
59
48
  cwa = ClassWithAttribs.new
60
49
  pub = ClassWithPublicInstanceMethod.new
61
- pc1 = Pointcut.new :objects => [cwa], :attributes => [/^attr/], :attribute_options => [:writers, :exclude_ancestor_methods]
62
- pc2 = Pointcut.new :object => pub, :method_options => :exclude_ancestor_methods
63
- pc = pc1.or pc2
64
- jp1 = Aquarium::Aspects::JoinPoint.new :object => cwa, :method => :attrRW_ClassWithAttribs=
65
- jp2 = Aquarium::Aspects::JoinPoint.new :object => cwa, :method => :attrW_ClassWithAttribs=
66
- jp3 = Aquarium::Aspects::JoinPoint.new :object => pub, :method => :public_instance_test_method
50
+ pc4 = Pointcut.new :objects => [cwa], :attributes => [/^attr/], :attribute_options => [:writers, :exclude_ancestor_methods]
51
+ pc5 = Pointcut.new :object => pub, :method_options => :exclude_ancestor_methods
52
+ pc = pc4.or pc5
53
+ jp1 = JoinPoint.new :object => cwa, :method => :attrRW_ClassWithAttribs=
54
+ jp2 = JoinPoint.new :object => cwa, :method => :attrW_ClassWithAttribs=
55
+ jp3 = JoinPoint.new :object => pub, :method => :public_instance_test_method
67
56
  pc.join_points_matched.sort.should == [jp1, jp2, jp3].sort
68
57
  pc.join_points_not_matched.sort.should == []
69
58
  end
70
-
59
+ end
60
+
61
+ describe Pointcut, "#or (algebraic properties for type-based pointcuts)" do
62
+ before :all do
63
+ @pc1 = Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:writers, :exclude_ancestor_methods]
64
+ @pc2 = Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:writers, :exclude_ancestor_methods]
65
+ @pc3 = Pointcut.new :types => /Class.*Public.*Method/, :method_options => [:public, :exclude_ancestor_methods]
66
+ end
67
+
71
68
  it "should be unitary for type-based Pointcuts." do
72
- pc1 = Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:writers]
73
- pc2 = Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:writers]
74
- pc = pc1.or pc2
75
- pc.should eql(pc1)
76
- pc.should eql(pc2)
69
+ pc = @pc1.or @pc2
70
+ pc.should eql(@pc1)
71
+ pc.should eql(@pc2)
77
72
  end
78
73
 
79
- it "should be unitary for object-based Pointcuts." do
80
- cwa = ClassWithAttribs.new
81
- pc1 = Pointcut.new :object => cwa, :attributes => [/^attr/], :attribute_options => [:writers]
82
- pc2 = Pointcut.new :object => cwa, :attributes => [/^attr/], :attribute_options => [:writers]
83
- pc = pc1.or pc2
84
- pc.should eql(pc1)
85
- pc.should eql(pc2)
74
+ it "should be commutative for type-based Pointcuts." do
75
+ pc13 = @pc1.or @pc3
76
+ pc31 = @pc3.or @pc1
77
+ pc13.should eql(pc31)
86
78
  end
87
79
 
88
- it "should be commutative for type-based Pointcuts." do
89
- pc1 = Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:writers]
90
- pc2 = Pointcut.new :types => /Class.*Method/
91
- pc12 = pc1.or pc2
92
- pc21 = pc2.or pc1
93
- pc12.should eql(pc21)
80
+ it "should be associativity for type-based Pointcuts." do
81
+ pc123a = (@pc1.or(@pc2)).or(@pc3)
82
+ pc123b = @pc1.or(@pc2.or(@pc3))
83
+ pc123a.should eql(pc123b)
94
84
  end
85
+ end
95
86
 
96
- it "should be commutative for object-based Pointcuts." do
87
+ describe Pointcut, "#or (algebraic properties for object-based pointcuts)" do
88
+ before :all do
97
89
  cwa = ClassWithAttribs.new
98
90
  pub = ClassWithPublicInstanceMethod.new
99
- pc1 = Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:writers]
100
- pc2 = Pointcut.new :objects => pub, :attributes => [/^attr/], :attribute_options => [:writers]
101
- pc12 = pc1.or pc2
102
- pc21 = pc2.or pc1
103
- pc12.should eql(pc21)
91
+ @pc1 = Pointcut.new :object => cwa, :attributes => [/^attr/], :attribute_options => [:writers, :exclude_ancestor_methods]
92
+ @pc2 = Pointcut.new :object => cwa, :attributes => [/^attr/], :attribute_options => [:writers, :exclude_ancestor_methods]
93
+ @pc3 = Pointcut.new :objects => pub, :attributes => [/^attr/], :attribute_options => [:writers, :exclude_ancestor_methods]
94
+ end
95
+
96
+ it "should be unitary for object-based Pointcuts." do
97
+ pc12 = @pc1.or @pc2
98
+ pc12.should eql(@pc1)
99
+ pc12.should eql(@pc2)
104
100
  end
105
101
 
106
- it "should be associativity for type-based Pointcuts." do
107
- pc1 = Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:writers]
108
- pc2 = Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:readers]
109
- pc3 = Pointcut.new :types => /Class.*Method/
110
- pc123a = (pc1.or(pc2)).or(pc3)
111
- pc123b = pc1.or(pc2.or(pc3))
112
- pc123a.should eql(pc123b)
102
+ it "should be commutative for object-based Pointcuts." do
103
+ pc13 = @pc1.or @pc3
104
+ pc31 = @pc3.or @pc1
105
+ pc13.should eql(pc31)
113
106
  end
114
107
 
115
108
  it "should be associativity for object-based Pointcuts." do
116
- cwa = ClassWithAttribs.new
117
- pub = ClassWithPublicInstanceMethod.new
118
- pc1 = Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:writers]
119
- pc2 = Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:readers]
120
- pc3 = Pointcut.new :objects => pub
121
- pc123a = (pc1.or(pc2)).or(pc3)
122
- pc123b = pc1.or(pc2.or(pc3))
109
+ pc123a = (@pc1.or(@pc2)).or(@pc3)
110
+ pc123b = @pc1.or(@pc2.or(@pc3))
123
111
  pc123a.should eql(pc123b)
124
112
  end
125
-
126
113
  end
127
114
 
128
- describe Pointcut, "#or" do
129
- it_should_behave_like "Union of Pointcuts"
130
- end
131
115
 
132
116
  describe Pointcut, "#|" do
133
-
134
- it_should_behave_like "Union of Pointcuts"
135
-
136
- it "should be associativity for type-based Pointcuts." do
137
- pc1 = Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:writers]
138
- pc2 = Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:readers]
139
- pc3 = Pointcut.new :types => /Class.*Method/
140
- pc123a = (pc1 | pc2) | pc3
141
- pc123b = pc1 | (pc2 | pc3)
142
- pc123a.should eql(pc123b)
143
- end
144
-
145
- it "should be associativity for object-based Pointcuts." do
117
+ it "should be a synonym for #or." do
118
+ pc1 = Pointcut.new
119
+ pc2 = Pointcut.new :types => /Class.*Public.*Method/, :method_options => [:public, :exclude_ancestor_methods]
120
+ pc3 = Pointcut.new :object => ClassWithPublicInstanceMethod.new, :method_options => [:exclude_ancestor_methods]
121
+ pc12 = pc1 | pc2
122
+ pc32 = pc3 | pc2
123
+ pc23 = pc2 | pc3
124
+ pc12.should_not equal(pc1)
125
+ pc12.should_not equal(pc2)
126
+ pc12.should eql(pc2)
127
+ pc32.should eql(pc23)
128
+ pca = Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:writers, :exclude_ancestor_methods]
129
+ pcb = Pointcut.new :types => "ClassWithAttribs", :attributes => [/^attr/], :attribute_options => [:readers, :exclude_ancestor_methods]
130
+ pcc = Pointcut.new :types => /Class.*Method/, :method_options => [:exclude_ancestor_methods]
131
+ pcabc1 = (pca | pcb) | pcc
132
+ pcabc2 = pca | (pcb | pcc)
133
+ pcabc1.should eql(pcabc2)
146
134
  cwa = ClassWithAttribs.new
147
135
  pub = ClassWithPublicInstanceMethod.new
148
- pc1 = Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:writers]
149
- pc2 = Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:readers]
150
- pc3 = Pointcut.new :objects => pub
151
- pc123a = (pc1 | pc2) | pc3
152
- pc123b = pc1 | (pc2 | pc3)
153
- pc123a.should eql(pc123b)
136
+ pcd = Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:writers, :exclude_ancestor_methods]
137
+ pce = Pointcut.new :objects => cwa, :attributes => [/^attr/], :attribute_options => [:readers, :exclude_ancestor_methods]
138
+ pcf = Pointcut.new :objects => pub, :method_options => [:exclude_ancestor_methods]
139
+ pcdef1 = (pcd | pce) | pcf
140
+ pcdef2 = pcd | (pce | pcf)
141
+ pcdef1.should eql(pcdef2)
154
142
  end
155
143
  end