cascading_classes 0.3.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,230 @@
1
+ begin
2
+ require_relative '../helper_spec'
3
+ rescue NameError
4
+ require File.expand_path('../helper_spec', __FILE__)
5
+ end
6
+
7
+ describe "basics" do
8
+ before do
9
+ A = Class.new{extend CC}
10
+ B = Class.new(A)
11
+ C = Class.new(B)
12
+ end
13
+
14
+ after do
15
+ Object.send :remove_const, :A
16
+ Object.send :remove_const, :B
17
+ Object.send :remove_const, :C
18
+ end
19
+
20
+ describe "properties with no type" do
21
+ before do
22
+ @props = A.cascade do
23
+ wings
24
+ features
25
+ blind
26
+ end
27
+ end
28
+
29
+ it "has unknown type of :Object" do
30
+ @props[:wings][:type].must_equal :undefined_type
31
+ @props[:features][:type].must_equal :undefined_type
32
+ @props[:blind][:type].must_equal :undefined_type
33
+ end
34
+ end
35
+
36
+ describe "whole slew of properties" do
37
+ before do
38
+ @props = A.cascade do
39
+ color :default => "red"
40
+ score :default => 45.9
41
+ rank :default => 18
42
+ style :default => :spotted
43
+ available :default => true
44
+ locations :default => [:south, :north]
45
+ name :default => {:first => 'jon', :last => 'smith'}
46
+ classified :default => Proc.new{|me| me.score > 40 }
47
+ end
48
+ end
49
+
50
+ describe "parent class" do
51
+ it "has set with the default value" do
52
+ A.color.must_equal "red"
53
+ A.score.must_equal 45.9
54
+ A.rank.must_equal 18
55
+ A.style.must_equal :spotted
56
+ A.available.must_equal true
57
+ A.locations.must_equal [:south, :north]
58
+ A.name.must_equal({:first => 'jon', :last => 'smith'})
59
+ A.classified.must_equal true
60
+ end
61
+ end
62
+
63
+ describe "descendents" do
64
+ it "has access to the 'default' value" do
65
+ A.color(:default).must_equal "red"
66
+ A.color = "blue"
67
+ A.color(:default).must_equal "blue"
68
+
69
+ B.color = "white"
70
+ B.color.must_equal "white"
71
+ B.color(:default).must_equal "red"
72
+ C.color(:default).must_equal "red"
73
+ end
74
+
75
+ describe "non-container-type properties" do
76
+ it "inherits non-blank values from first non-blank ancestor" do
77
+ @props[:color][:inherit].must_equal true
78
+ @props[:score][:inherit].must_equal true
79
+ @props[:rank][:inherit].must_equal true
80
+ @props[:style][:inherit].must_equal true
81
+ @props[:available][:inherit].must_equal true
82
+
83
+ B.color.must_equal "red"
84
+ B.score.must_equal 45.9
85
+ B.rank.must_equal 18
86
+ B.style.must_equal :spotted
87
+ B.available.must_equal true
88
+
89
+ C.color.must_equal "red"
90
+ C.score.must_equal 45.9
91
+ C.rank.must_equal 18
92
+ C.style.must_equal :spotted
93
+ C.available.must_equal true
94
+
95
+ B.score = 48.2
96
+ B.style = :rugged
97
+ B.available = false
98
+
99
+ B.score.must_equal 48.2
100
+ C.score.must_equal 48.2
101
+
102
+ B.style.must_equal :rugged
103
+ C.style.must_equal :rugged
104
+
105
+ B.available.must_equal false
106
+ C.available.must_equal false
107
+ end
108
+ end
109
+
110
+ describe "container-type properties" do
111
+ it "does not inherit ancestor properties" do
112
+ @props[:locations][:inherit].must_equal false
113
+ @props[:name][:inherit].must_equal false
114
+
115
+ B.locations.must_equal Array.new
116
+ C.locations.must_equal Array.new
117
+ B.name.must_equal Hash.new
118
+ C.name.must_equal Hash.new
119
+
120
+ B.locations = [:east, :west]
121
+ B.name = {:first => 'adam', :last => 'phillips'}
122
+
123
+ B.locations.must_equal [:east, :west]
124
+ C.locations.must_equal Array.new
125
+ B.name.must_equal({:first => 'adam', :last => 'phillips'})
126
+ C.name.must_equal Hash.new
127
+ end
128
+ end
129
+
130
+ describe "proc properties" do
131
+ it "inherits by default" do
132
+ @props[:classified][:inherit].must_equal true
133
+ end
134
+
135
+ it "evaluates the proc in context of each descendent" do
136
+ A.score = 54.2
137
+ B.score = 30.1
138
+ C.score = 45.2
139
+
140
+ A.classified.must_equal true
141
+ B.classified.must_equal false
142
+ C.classified.must_equal true
143
+ end
144
+ end
145
+ end
146
+
147
+ describe "property block parameter" do
148
+ before do
149
+ B.color = "blue"
150
+ C.color = "purple"
151
+ end
152
+
153
+ it "expects two parameters: property_name, ancestors" do
154
+ A.color{|color_a, parents|
155
+ color_a.must_equal "red"
156
+ parents.must_equal []
157
+ }
158
+
159
+ B.color{|color_b, parents|
160
+ color_b.must_equal "blue"
161
+ parents.must_equal [A]
162
+ }
163
+
164
+ C.color{|color_c, parents|
165
+ color_c.must_equal "purple"
166
+ parents.must_equal [B, A]
167
+ }
168
+ end
169
+
170
+ it "returns last expression of block" do
171
+ A.color{|my_color| my_color.reverse}.must_equal "der"
172
+ B.color{|my_color| my_color.capitalize}.must_equal "Blue"
173
+ C.color{|my_color| my_color * 2}.must_equal "purplepurple"
174
+ end
175
+ end
176
+
177
+ describe "descendents" do
178
+ describe "properties not of type :Proc but whose descendents set it to one" do
179
+ before do
180
+ B.color = Proc.new{|me, parents| parents.first.color.capitalize}
181
+ B.rank = Proc.new{ Time.now.sec }
182
+ end
183
+
184
+ it "descendents whose property is blank, inherit (invoke) the proc" do
185
+ B.color.must_equal "Red"
186
+
187
+ sec = Time.now.sec
188
+ B.rank.must_equal sec
189
+ C.rank.must_equal sec
190
+
191
+ sleep(2)
192
+
193
+ sec = Time.now.sec
194
+ B.rank.must_equal sec
195
+ C.rank.must_equal sec
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
201
+
202
+ describe "to_hash" do
203
+ before do
204
+ A = Class.new{extend CC}
205
+ B = Class.new(A)
206
+ C = Class.new(B)
207
+
208
+ A.cascade do
209
+ color :default => "red"
210
+ name :default => {:first => 'jon', :last => 'mackey'}
211
+ end
212
+ end
213
+
214
+ after do
215
+ Object.send :remove_const, :A
216
+ Object.send :remove_const, :B
217
+ Object.send :remove_const, :C
218
+ end
219
+
220
+ it "returns hash of property name/values" do
221
+ A.to_hash.must_equal({:color => "red",
222
+ :name => {:first => 'jon',
223
+ :last => 'mackey'}
224
+ })
225
+ end
226
+
227
+ it "applies default getter logic: non-container-types inherit, container-types don't" do
228
+ B.to_hash.must_equal({:color => "red", :name => {}})
229
+ end
230
+ end
@@ -0,0 +1,52 @@
1
+ begin
2
+ require_relative '../helper_spec'
3
+ rescue NameError
4
+ require File.expand_path('../helper_spec', __FILE__)
5
+ end
6
+
7
+ describe "block given" do
8
+ before do
9
+ A = Class.new{include CC}
10
+ B = Class.new(A)
11
+ C = Class.new(B)
12
+
13
+ A.cascade do
14
+ color :default => "red"
15
+ score :default => 34.5
16
+ end
17
+ end
18
+
19
+ after do
20
+ Object.send :remove_const, :A
21
+ Object.send :remove_const, :B
22
+ Object.send :remove_const, :C
23
+ end
24
+
25
+ it "takes two params: value of self, parent classes" do
26
+ A.score{|my_score, parents| my_score}.must_equal A.score
27
+
28
+ B.score = 28.2
29
+ B.score{|my_score, parents| my_score}.must_equal B.score
30
+
31
+ A.new.score{|my_score| my_score}.must_equal A.new.score
32
+ B.new.score{|my_score| my_score}.must_equal B.new.score
33
+
34
+ A.score{|my_score, parents| parents}.must_equal []
35
+ B.score{|my_score, parents| parents}.must_equal [A]
36
+
37
+ A.new.score{|my_score, parents| parents}.must_equal [A]
38
+ B.new.score{|my_score, parents| parents}.must_equal [B, A]
39
+
40
+ =begin
41
+ what_score, which_parents = nil, nil
42
+
43
+ B.score{|my_score, parents|
44
+ what_score = my_score
45
+ which_parents = parents
46
+ }
47
+
48
+ what_score.must_equal(B.score)
49
+ which_parents.must_equal([A])
50
+ =end
51
+ end
52
+ end
@@ -0,0 +1,201 @@
1
+ begin
2
+ require_relative '../helper_spec'
3
+ rescue NameError
4
+ require File.expand_path('../helper_spec', __FILE__)
5
+ end
6
+
7
+ describe "container types: typical" do
8
+ before do
9
+ A = Class.new{extend CC}
10
+ B = Class.new(A)
11
+ C = Class.new(B)
12
+
13
+ @props = A.cascade do
14
+ urls :default => ["www.google.com"]
15
+ name :default => {:first => 'jon', :last => 'smith'}
16
+ end
17
+ end
18
+
19
+ after do
20
+ Object.send :remove_const, :A
21
+ Object.send :remove_const, :B
22
+ Object.send :remove_const, :C
23
+ end
24
+
25
+ it "does not inherit by default" do
26
+ @props[:urls][:inherit].must_equal false
27
+ @props[:name][:inherit].must_equal false
28
+
29
+ A.urls.must_equal ["www.google.com"]
30
+ B.urls.must_equal Array.new
31
+ C.urls.must_equal Array.new
32
+
33
+ A.name.must_equal({:first => 'jon', :last => 'smith'})
34
+ B.name.must_equal Hash.new
35
+ C.name.must_equal Hash.new
36
+ end
37
+
38
+ describe "descendents can update their own container properties" do
39
+ before do
40
+ B.urls << "www.bing.com" << "www.example.com"
41
+
42
+ C.urls = ["c.homepage.org"]
43
+ C.urls << "example.org"
44
+
45
+ B.name[:first] = 'charlie'
46
+ C.name = {:first => 'tim', :last => 'emerson'}
47
+ end
48
+
49
+ it "works" do
50
+ B.urls.must_equal ["www.bing.com", "www.example.com"]
51
+ C.urls.must_equal ["c.homepage.org", "example.org"]
52
+
53
+ B.name.must_equal({:first => 'charlie'})
54
+ C.name.must_equal({:first => 'tim', :last => 'emerson'})
55
+ end
56
+ end
57
+
58
+ describe "manual override: allowing inheritance" do
59
+ it "accepts ':inherit' syntax" do
60
+ B.urls(:inherit).must_equal ["www.google.com"]
61
+ C.urls(:inherit).must_equal ["www.google.com"]
62
+
63
+ B.name(:inherit).must_equal({:first => 'jon', :last => 'smith'})
64
+ C.name(:inherit).must_equal({:first => 'jon', :last => 'smith'})
65
+ end
66
+
67
+ it "accepts ':inherit => <val>' syntax" do
68
+ B.urls(:inherit => 0).must_equal []
69
+ B.urls(:inherit => false).must_equal []
70
+ B.urls(:inherit => nil).must_equal []
71
+ B.urls(:inherit => 1).must_equal ["www.google.com"]
72
+ B.urls(:inherit => true).must_equal ["www.google.com"]
73
+ B.urls(:inherit => -1).must_equal ["www.google.com"]
74
+
75
+ C.urls(:inherit => 0).must_equal []
76
+ C.urls(:inherit => false).must_equal []
77
+ C.urls(:inherit => nil).must_equal []
78
+ C.urls(:inherit => 1).must_equal []
79
+ C.urls(:inherit => 2).must_equal ["www.google.com"]
80
+ C.urls(:inherit => -1).must_equal ["www.google.com"]
81
+ C.urls(:inherit => true).must_equal ["www.google.com"]
82
+ end
83
+
84
+ it "accepts ':inherit, <val>' syntax" do
85
+ B.name(:inherit, 0).must_equal Hash.new
86
+ B.name(:inherit, false).must_equal Hash.new
87
+ B.name(:inherit, nil).must_equal Hash.new
88
+ B.name(:inherit, 1).must_equal({:first => 'jon', :last => 'smith'})
89
+ B.name(:inherit, true).must_equal({:first => 'jon', :last => 'smith'})
90
+ B.name(:inherit, -1).must_equal({:first => 'jon', :last => 'smith'})
91
+
92
+ C.name(:inherit, 0).must_equal Hash.new
93
+ C.name(:inherit, false).must_equal Hash.new
94
+ C.name(:inherit, nil).must_equal Hash.new
95
+ C.name(:inherit, 1).must_equal Hash.new
96
+ C.name(:inherit, 2).must_equal({:first => 'jon', :last => 'smith'})
97
+ C.name(:inherit, true).must_equal({:first => 'jon', :last => 'smith'})
98
+ C.name(:inherit, -1).must_equal({:first => 'jon', :last => 'smith'})
99
+ end
100
+
101
+ describe "manual override has no effect on non-blank container properties" do
102
+ it "works" do
103
+ C.urls << "www.yahoo.com"
104
+
105
+ A.urls_is_blank?.must_equal false
106
+ B.urls_is_blank?.must_equal true
107
+ C.urls_is_blank?.must_equal false
108
+
109
+ A.urls.must_equal ["www.google.com"]
110
+ A.urls(:inherit).must_equal ["www.google.com"]
111
+ A.urls(:inherit => false).must_equal ["www.google.com"]
112
+ A.urls(:inherit => nil).must_equal ["www.google.com"]
113
+ A.urls(:inherit => 0).must_equal ["www.google.com"]
114
+ A.urls(:inherit => 1).must_equal ["www.google.com"]
115
+ A.urls(:inherit => 2).must_equal ["www.google.com"]
116
+ A.urls(:inherit => -1).must_equal ["www.google.com"]
117
+ A.urls(:inherit => true).must_equal ["www.google.com"]
118
+
119
+ C.urls.must_equal ["www.yahoo.com"]
120
+ C.urls(:inherit).must_equal ["www.yahoo.com"]
121
+ C.urls(:inherit, false).must_equal ["www.yahoo.com"]
122
+ C.urls(:inherit, nil).must_equal ["www.yahoo.com"]
123
+ C.urls(:inherit, 0).must_equal ["www.yahoo.com"]
124
+ C.urls(:inherit, 1).must_equal ["www.yahoo.com"]
125
+ C.urls(:inherit, 2).must_equal ["www.yahoo.com"]
126
+ C.urls(:inherit, -1).must_equal ["www.yahoo.com"]
127
+ C.urls(:inherit, true).must_equal ["www.yahoo.com"]
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ describe "container types: property-wide inheritance" do
134
+ before do
135
+ A = Class.new{extend CC}
136
+ B = Class.new(A)
137
+ C = Class.new(B)
138
+
139
+ @props = A.cascade do
140
+ urls :default => ["www.google.com"], :inherit => true
141
+ name :default => {:first => 'jon', :last => 'smith'}, :inherit => true
142
+ end
143
+ end
144
+
145
+ after do
146
+ Object.send :remove_const, :A
147
+ Object.send :remove_const, :B
148
+ Object.send :remove_const, :C
149
+ end
150
+
151
+ it "inherits by default" do
152
+ @props[:urls][:inherit].must_equal true
153
+ @props[:name][:inherit].must_equal true
154
+
155
+ B.urls.must_equal ["www.google.com"]
156
+ C.urls.must_equal ["www.google.com"]
157
+
158
+ B.name.must_equal({:first => 'jon', :last => 'smith'})
159
+ C.name.must_equal({:first => 'jon', :last => 'smith'})
160
+ end
161
+
162
+ describe "a descendent updates a container property" do
163
+ before do
164
+ B.urls = "www.bing.com"
165
+ end
166
+
167
+ it "cascades down its descendents" do
168
+ C.urls.must_equal ["www.bing.com"]
169
+ end
170
+ end
171
+
172
+ describe "overriding the inheritance effect" do
173
+ it "accepts ':inherit => <val>' syntax" do
174
+ B.urls.must_equal ["www.google.com"]
175
+ C.urls.must_equal ["www.google.com"]
176
+
177
+ B.urls(:inherit => false).must_equal []
178
+ C.urls(:inherit => false).must_equal []
179
+
180
+ B.urls(:inherit => 0).must_equal []
181
+ C.urls(:inherit => 0).must_equal []
182
+
183
+ B.urls(:inherit => 1).must_equal ["www.google.com"]
184
+ C.urls(:inherit => 1).must_equal []
185
+ end
186
+
187
+ it "accepts ':inherit, <val>' syntax" do
188
+ B.urls.must_equal ["www.google.com"]
189
+ C.urls.must_equal ["www.google.com"]
190
+
191
+ B.urls(:inherit, false).must_equal []
192
+ C.urls(:inherit, false).must_equal []
193
+
194
+ B.urls(:inherit, 0).must_equal []
195
+ C.urls(:inherit, 0).must_equal []
196
+
197
+ B.urls(:inherit, 1).must_equal ["www.google.com"]
198
+ C.urls(:inherit, 1).must_equal []
199
+ end
200
+ end
201
+ end