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,339 @@
1
+ begin
2
+ require_relative '../helper_spec'
3
+ rescue NameError
4
+ require File.expand_path('../helper_spec', __FILE__)
5
+ end
6
+
7
+ # todo: update --> when you do :inherit => false this means NO INHERITANCE
8
+
9
+ describe "inherit" do
10
+ before do
11
+ A = Class.new{extend CC}
12
+ B = Class.new(A)
13
+ C = Class.new(B)
14
+ end
15
+
16
+ after do
17
+ Object.send :remove_const, :A
18
+ Object.send :remove_const, :B
19
+ Object.send :remove_const, :C
20
+ end
21
+
22
+ describe "defaults" do
23
+ before do
24
+ @props = A.cascade do
25
+ location :default => "south side"
26
+ score :default => 32.18
27
+ num :default => 12
28
+ weather :default => :sunny
29
+ available :default => false
30
+ mood :default => Proc.new{|me| me.weather == :sunny ? "content" : "depressed"}
31
+ color :default => Proc.new{|me| me.mood == "content" ? "rosy" : "blue"}
32
+ name :default => {:first => 'jon', :last => 'smith'}
33
+ groceries :default => [:ice, :lemons, :splenda]
34
+ ingredients :default => Set.new([:sugar, :butter, :flour, :eggs])
35
+ end
36
+ end
37
+
38
+ describe "descendents" do
39
+ it "inherits symbols strings, fixnums, floats, and bools (by default)" do
40
+ @props[:location][:inherit].must_equal true
41
+ @props[:weather][:inherit].must_equal true
42
+ @props[:num][:inherit].must_equal true
43
+ @props[:score][:inherit].must_equal true
44
+ @props[:available][:inherit].must_equal true
45
+
46
+ B.location.must_equal "south side"
47
+ C.location.must_equal "south side"
48
+
49
+ B.weather.must_equal :sunny
50
+ C.weather.must_equal :sunny
51
+
52
+ B.num.must_equal 12
53
+ C.num.must_equal 12
54
+
55
+ B.score.must_equal 32.18
56
+ C.score.must_equal 32.18
57
+
58
+ B.available.must_equal false
59
+ C.available.must_equal false
60
+ end
61
+
62
+ it "doesn't inherit containers like hashes, arrays, and sets (by default)" do
63
+ @props[:name][:inherit].must_equal false
64
+ @props[:groceries][:inherit].must_equal false
65
+
66
+ B.name.must_equal Hash.new
67
+ C.name.must_equal Hash.new
68
+
69
+ B.groceries.must_equal Array.new
70
+ C.groceries.must_equal Array.new
71
+
72
+ B.ingredients.must_equal Set.new
73
+ C.ingredients.must_equal Set.new
74
+ end
75
+
76
+ it "inherits properties of type ':Proc'" do
77
+ @props[:mood][:inherit].must_equal true
78
+
79
+ A.weather = :sunny
80
+ B.weather = :rainy
81
+
82
+ C.weather.must_equal :rainy
83
+
84
+ A.mood.must_equal "content"
85
+ B.mood.must_equal "depressed"
86
+ C.mood.must_equal "depressed"
87
+
88
+ C.weather = :sunny
89
+ C.mood.must_equal "content"
90
+ end
91
+ end
92
+ end
93
+
94
+ describe "syntax" do
95
+ describe "overriding the default 'inherit' age" do
96
+ describe "manual override" do
97
+ before do
98
+ A.cascade do
99
+ location :default => "south side"
100
+ score :default => 32.18
101
+ num :default => 12
102
+ weather :default => :sunny
103
+ available :default => false
104
+ mood :default => Proc.new{|me| me.weather == :sunny ? "content" : "depressed"}
105
+ color :default => Proc.new{|me| me.mood == "content" ? "rosy" : "blue"}
106
+ name :default => {:first => 'jon', :last => 'smith'}
107
+ groceries :default => [:ice, :lemons, :splenda]
108
+ ingredients :default => Set.new([:sugar, :butter, :flour, :eggs])
109
+ end
110
+
111
+ B.color = Proc.new{|me| me.mood == "content" ? "#{me}: rosy" : "#{me}: blue"}
112
+ end
113
+
114
+ it "allows 'false', 'nil' and '0' to force no inheritance" do
115
+ B.location(false).must_equal ""
116
+ C.location(false).must_equal ""
117
+
118
+ B.score(nil).must_equal nil
119
+ C.score(nil).must_equal nil
120
+
121
+ B.weather(0).must_equal nil
122
+ C.weather(0).must_equal nil
123
+ end
124
+
125
+ it "allows 'true', '-1' to force full, inifinte max inheritance" do
126
+ B.num(true).must_equal 12
127
+ C.num(true).must_equal 12
128
+
129
+ B.groceries(-1).must_equal [:ice, :lemons, :splenda]
130
+ C.groceries(-1).must_equal [:ice, :lemons, :splenda]
131
+ end
132
+
133
+ it "allows '<fixnum>' value to indicate max inheritance age" do
134
+ B.score(0).must_equal nil
135
+ B.score(1).must_equal 32.18
136
+ B.score(2).must_equal 32.18
137
+ C.score(1).must_equal nil
138
+ C.score(2).must_equal 32.18
139
+
140
+ B.name(0).must_equal Hash.new
141
+ B.name(1).must_equal({:first => 'jon', :last => 'smith'})
142
+ C.name(0).must_equal Hash.new
143
+ C.name(1).must_equal Hash.new
144
+ C.name(2).must_equal({:first => 'jon', :last => 'smith'})
145
+ end
146
+
147
+ it "allows ':inherit => false' and ':inherit => nil' syntax" do
148
+ B.location(:inherit => false).must_equal ""
149
+ c_location = C.location :inherit => false
150
+ c_location.must_equal ""
151
+
152
+ B.weather(:inherit => nil).must_equal nil
153
+ c_weather = C.weather :inherit => nil
154
+ c_weather.must_equal nil
155
+ end
156
+
157
+ it "allows ':inhert, false' and ':inherit, nil' syntax" do
158
+ B.num(:inherit, false).must_equal nil
159
+ c_num = C.num :inherit, false
160
+ c_num.must_equal nil
161
+
162
+ B.score(:inherit, nil).must_equal nil
163
+ c_score = C.score :inherit, nil
164
+ c_score.must_equal nil
165
+ end
166
+
167
+ it "allows ':inherit => true' and ':inherit => -1' syntax" do
168
+ B.name(:inherit => true).must_equal({:first => 'jon', :last => 'smith'})
169
+ c_name = C.name :inherit => true
170
+ c_name.must_equal({:first => 'jon', :last => 'smith'})
171
+
172
+ B.groceries(:inherit => -1).must_equal [:ice, :lemons, :splenda]
173
+ c_groceries = C.groceries :inherit => -1
174
+ c_groceries.must_equal [:ice, :lemons, :splenda]
175
+ end
176
+
177
+ it "allows ':inherit, true' and ':inherit, -1' syntax" do
178
+ B.ingredients(:inherit, true).must_equal Set.new([:sugar, :butter, :flour, :eggs])
179
+ c_ingredients = C.ingredients :inherit, true
180
+ c_ingredients.must_equal Set.new([:sugar, :butter, :flour, :eggs])
181
+
182
+ B.name(:inherit, -1).must_equal({:first => 'jon', :last => 'smith'})
183
+ c_name = C.name :inherit, -1
184
+ c_name.must_equal({:first => 'jon', :last => 'smith'})
185
+ end
186
+
187
+ it "allows ':inherit => <n>' (n: fixnum) syntax" do
188
+ B.location(:inherit => 0).must_equal ''
189
+ B.location(:inherit => 1).must_equal "south side"
190
+
191
+ c_loc_0 = C.location :inherit => 0
192
+ c_loc_1 = C.location :inherit => 1
193
+ c_loc_2 = C.location :inherit => 2
194
+
195
+ c_loc_0.must_equal ''
196
+ c_loc_1.must_equal ''
197
+ c_loc_2.must_equal "south side"
198
+
199
+ B.groceries(:inherit => 0).must_equal []
200
+ B.groceries(:inherit => 1).must_equal [:ice, :lemons, :splenda]
201
+
202
+ c_groc_0 = C.groceries :inherit => 0
203
+ c_groc_1 = C.groceries :inherit => 1
204
+ c_groc_2 = C.groceries :inherit => 2
205
+
206
+ c_groc_0.must_equal []
207
+ c_groc_1.must_equal []
208
+ c_groc_2.must_equal [:ice, :lemons, :splenda]
209
+ end
210
+
211
+ it "allows ':inherit, <n>' (n: fixnum) syntax" do
212
+ B.score(:inherit, 0).must_equal nil
213
+ B.score(:inherit, 1).must_equal 32.18
214
+
215
+ c_score_0 = C.score :inherit, 0
216
+ c_score_1 = C.score :inherit, 1
217
+ c_score_2 = C.score :inherit, 2
218
+
219
+ c_score_0.must_equal nil
220
+ c_score_1.must_equal nil
221
+ c_score_2.must_equal 32.18
222
+
223
+ B.ingredients(:inherit, 0).must_equal Set.new([])
224
+ B.ingredients(:inherit, 1).must_equal Set.new([:sugar, :butter, :flour, :eggs])
225
+
226
+ c_ingr_0 = C.ingredients :inherit, 0
227
+ c_ingr_1 = C.ingredients :inherit, 1
228
+ c_ingr_2 = C.ingredients :inherit, 2
229
+
230
+ c_ingr_0.must_equal Set.new([])
231
+ c_ingr_1.must_equal Set.new([])
232
+ c_ingr_2.must_equal Set.new([:sugar, :butter, :flour, :eggs])
233
+ end
234
+ end
235
+
236
+ describe "property-wide inherit age override" do
237
+ before do
238
+ @props = A.cascade do
239
+ location :default => "south side", :inherit => false
240
+ score :default => 32.18, :inherit => false
241
+ num :default => 12, :inherit => false
242
+ weather :default => :sunny, :inherit => false
243
+ available :default => false, :inherit => false
244
+ mood :default => Proc.new{|me| me.weather == :sunny ? "content" : "depressed"}, :inherit => false
245
+ color :default => Proc.new{|me| me.mood == "content" ? "rosy" : "blue"}, :inherit => false
246
+ name :default => {:first => 'jon', :last => 'smith'}, :inherit => false
247
+ groceries :default => [:ice, :lemons, :splenda], :inherit => false
248
+ ingredients :default => Set.new([:sugar, :butter, :flour, :eggs]), :inherit => false
249
+ end
250
+
251
+ B.color = Proc.new{|me| me.mood == "content" ? "#{me}: rosy" : "#{me}: blue"}
252
+ end
253
+
254
+ it "all should not inherit" do
255
+ @props[:location][:inherit].must_equal false
256
+ @props[:score][:inherit].must_equal false
257
+ @props[:num][:inherit].must_equal false
258
+ @props[:weather][:inherit].must_equal false
259
+ @props[:available][:inherit].must_equal false
260
+ @props[:mood][:inherit].must_equal false
261
+ @props[:color][:inherit].must_equal false
262
+ @props[:groceries][:inherit].must_equal false
263
+ @props[:ingredients][:inherit].must_equal false
264
+
265
+ A.location.must_equal "south side"
266
+ B.location.must_equal ''
267
+ C.location.must_equal ''
268
+
269
+ A.score.must_equal 32.18
270
+ B.score.must_equal nil
271
+ C.score.must_equal nil
272
+
273
+ A.num.must_equal 12
274
+ B.num.must_equal nil
275
+ C.num.must_equal nil
276
+
277
+ A.weather.must_equal :sunny
278
+ B.weather.must_equal nil
279
+ C.weather.must_equal nil
280
+
281
+ A.available.must_equal false
282
+ B.available.must_equal nil
283
+ C.available.must_equal nil
284
+
285
+ A.mood.must_equal "content"
286
+ B.mood.must_equal "depressed"
287
+ C.mood.must_equal "depressed"
288
+
289
+ A.color.must_equal "rosy"
290
+ B.color.must_equal "B: blue"
291
+ C.color.must_equal "blue"
292
+
293
+ A.name.must_equal({:first => 'jon', :last => 'smith'})
294
+ B.name.must_equal Hash.new
295
+ C.name.must_equal Hash.new
296
+
297
+ A.groceries.must_equal [:ice, :lemons, :splenda]
298
+ B.groceries.must_equal Array.new
299
+ C.groceries.must_equal Array.new
300
+
301
+ A.ingredients.must_equal Set.new([:sugar, :butter, :flour, :eggs])
302
+ B.ingredients.must_equal Set.new
303
+ C.ingredients.must_equal Set.new
304
+ end
305
+
306
+ describe "manual inheritance age override" do
307
+ it "allows 'true' and '-1' syntax" do
308
+ B.location(true).must_equal "south side"
309
+ C.location(true).must_equal "south side"
310
+
311
+ B.score(-1).must_equal 32.18
312
+ C.score(-1).must_equal 32.18
313
+
314
+ B.ingredients(true).must_equal Set.new([:sugar, :butter, :flour, :eggs])
315
+ C.ingredients(true).must_equal Set.new([:sugar, :butter, :flour, :eggs])
316
+ end
317
+
318
+ it "allows <fixnum> (n > 0) syntax to indicate max inheritance age" do
319
+ B.weather(0).must_equal nil
320
+ B.weather(1).must_equal :sunny
321
+ B.weather(2).must_equal :sunny
322
+ C.weather(0).must_equal nil
323
+ C.weather(1).must_equal nil
324
+ C.weather(2).must_equal :sunny
325
+ C.weather(3).must_equal :sunny
326
+
327
+ B.groceries(0).must_equal Array.new
328
+ B.groceries(1).must_equal [:ice, :lemons, :splenda]
329
+ B.groceries(2).must_equal [:ice, :lemons, :splenda]
330
+ C.groceries(0).must_equal Array.new
331
+ C.groceries(1).must_equal Array.new
332
+ C.groceries(2).must_equal Array.new [:ice, :lemons, :splenda]
333
+ C.groceries(3).must_equal Array.new [:ice, :lemons, :splenda]
334
+ end
335
+ end
336
+ end
337
+ end
338
+ end
339
+ end
@@ -0,0 +1,343 @@
1
+ begin
2
+ require_relative '../helper_spec'
3
+ rescue NameError
4
+ require File.expand_path('../helper_spec', __FILE__)
5
+ end
6
+
7
+ # known error: defining a proc property with do ... end syntax
8
+ # A.cascade do
9
+ # mood :default => Proc.new do |me|
10
+ # me.weather == :sunny ? "content" : "depressed"
11
+ # end
12
+ # end
13
+
14
+
15
+ describe "proc properties" do
16
+ before do
17
+ A = Class.new{include CC}
18
+ B = Class.new(A)
19
+ C = Class.new(B)
20
+
21
+ @props = A.cascade do
22
+ weather :default => :sunny
23
+ mood :default => Proc.new{|me|
24
+ me.weather == :sunny ? "content" : "depressed"
25
+ }
26
+ color :default => Proc.new{|me|
27
+ me.mood == "content" ? "rosy" : "blue"
28
+ }
29
+ end
30
+ end
31
+
32
+ after do
33
+ Object.send :remove_const, :A
34
+ Object.send :remove_const, :B
35
+ Object.send :remove_const, :C
36
+ end
37
+
38
+ it "inherits by default" do
39
+ @props[:weather][:inherit].must_equal true # sanity
40
+ @props[:mood][:inherit].must_equal true
41
+ @props[:color][:inherit].must_equal true
42
+ end
43
+
44
+ describe "a property of type :Proc" do
45
+ it "evaluates the proc on each invocation of the property" do
46
+ A.weather.must_equal :sunny
47
+ A.mood.must_equal "content"
48
+ A.color.must_equal "rosy"
49
+
50
+ A.weather = :rainy
51
+ A.mood.must_equal "depressed"
52
+ A.color.must_equal "blue"
53
+ end
54
+
55
+ it "has second parameter that is a list of parents" do
56
+ A.mood = Proc.new{|me, parents| parents}
57
+
58
+ A.mood.must_equal []
59
+ B.mood.must_equal [A]
60
+ C.mood.must_equal [B, A]
61
+
62
+ A.new.mood.must_equal [A]
63
+ B.new.mood.must_equal [B, A]
64
+ C.new.mood.must_equal [C, B, A]
65
+ end
66
+
67
+ describe "blank descendents" do
68
+ it "inherits from its nearest non-blank ancestor" do
69
+ B.mood_is_blank?.must_equal true
70
+ C.mood_is_blank?.must_equal true
71
+
72
+ A.weather = :sunny
73
+ B.mood.must_equal "content"
74
+ C.mood.must_equal "content"
75
+ B.color.must_equal "rosy"
76
+ C.color.must_equal "rosy"
77
+
78
+ A.weather = :rainy
79
+
80
+ B.mood.must_equal "depressed"
81
+ C.mood.must_equal "depressed"
82
+ B.color.must_equal "blue"
83
+ C.color.must_equal "blue"
84
+ end
85
+
86
+ it "uses its own proc if not blank" do
87
+ B.mood = Proc.new{ "angry" }
88
+
89
+ B.mood.must_equal "angry"
90
+ B.color.must_equal "blue"
91
+ end
92
+
93
+ describe "the parent redefines the proc property" do
94
+ before do
95
+ A.color = Proc.new{|me| me.mood == "content" ? "#{me}: rosy" : "#{me}: blue"}
96
+ end
97
+
98
+ it "cascades down to descendents whose property is blank, just as before" do
99
+ A.weather = :sunny
100
+ B.weather = :rainy
101
+
102
+ A.color.must_equal "A: rosy"
103
+ B.color.must_equal "B: blue"
104
+ C.color.must_equal "C: blue"
105
+ end
106
+ end
107
+
108
+ describe "a descendent changes its proc property" do
109
+ before do
110
+ B.mood = Proc.new{ "angry" }
111
+ B.color = Proc.new{|me, parents| me.mood == "content" ? "#{me}: rosy" : "#{me}: blue"}
112
+ end
113
+
114
+ describe "descendents of the descendent" do
115
+ it "inherits the new proc by default" do
116
+ A.weather = :sunny
117
+
118
+ A.mood.must_equal "content"
119
+ B.mood.must_equal "angry"
120
+ C.mood.must_equal "angry"
121
+
122
+ A.color.must_equal "rosy"
123
+ B.color.must_equal "B: blue"
124
+ C.color.must_equal "C: blue"
125
+ end
126
+
127
+ describe "descendents can any inheritance, using the default instead" do
128
+ it "accepts ':default' syntax" do
129
+ A.weather = :sunny
130
+
131
+ A.mood.must_equal "content"
132
+ B.mood.must_equal "angry"
133
+ C.mood(:default).must_equal "content"
134
+ end
135
+
136
+ it "accepts ':inherit => false' syntax" do
137
+ A.weather = :sunny
138
+
139
+ A.mood.must_equal "content"
140
+ B.mood.must_equal "angry"
141
+ C.mood(:inherit => false).must_equal "content"
142
+
143
+ A.color.must_equal "rosy"
144
+ B.color.must_equal "B: blue"
145
+ C.color(:inherit => false).must_equal "blue" # ***** take note: C.mood = "depressed" *****
146
+ end
147
+
148
+ it "accepts ':inherit, false' syntax" do
149
+ A.weather = :sunny
150
+
151
+ A.mood.must_equal "content"
152
+ B.mood.must_equal "angry"
153
+ C.mood(:inherit, false).must_equal "content"
154
+
155
+ A.color.must_equal "rosy"
156
+ B.color.must_equal "B: blue"
157
+ C.color(:inherit, false).must_equal "blue"
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
164
+
165
+ describe "a property of type :Proc with property-level inheritance override" do
166
+ before do
167
+ @props = A.cascade do
168
+ weather :default => :sunny
169
+ mood :default => Proc.new{|me| me.weather == :sunny ? "content" : "depressed"}, :inherit => false
170
+ color :default => Proc.new{|me| me.mood == "content" ? "#{me}: rosy" : "#{me}: blue"}, :inherit => false
171
+ end
172
+
173
+ B.mood = Proc.new{ "angry" }
174
+ end
175
+
176
+ it "does not inherit" do
177
+ @props[:weather][:inherit].must_equal true # sanity
178
+ @props[:mood][:inherit].must_equal false
179
+ @props[:color][:inherit].must_equal false
180
+ end
181
+
182
+ describe "descendents" do
183
+ it "propogates the initial proc value, but not any descendents' proc" do
184
+ B.color_is_blank?.must_equal true
185
+ C.mood_is_blank?.must_equal true
186
+
187
+ A.weather.must_equal :sunny # sanity
188
+ B.weather.must_equal :sunny # sanity
189
+ C.weather.must_equal :sunny
190
+
191
+ A.mood.must_equal "content" # sanity
192
+ B.mood.must_equal "angry" # sanity
193
+ C.mood.must_equal "content"
194
+
195
+ A.color.must_equal "A: rosy" # sanity
196
+ B.color.must_equal "B: blue" # sanity
197
+ C.color.must_equal "C: rosy"
198
+ end
199
+ end
200
+ end
201
+
202
+ describe "an inherited property not of type :Proc" do
203
+ before do
204
+ @props = A.cascade do
205
+ ingredients :default => Set.new([:sugar, :butter, :flour, :eggs]), :inherit => true
206
+ sweet_tooth :default => false
207
+ end
208
+ end
209
+
210
+ it "inherits the property" do
211
+ @props[:ingredients][:inherit].must_equal true
212
+ @props[:sweet_tooth][:inherit].must_equal true
213
+
214
+ A.ingredients.must_equal Set.new([:sugar, :butter, :flour, :eggs])
215
+ B.ingredients.must_equal Set.new([:sugar, :butter, :flour, :eggs])
216
+ C.ingredients.must_equal Set.new([:sugar, :butter, :flour, :eggs])
217
+
218
+ A.sweet_tooth.must_equal false
219
+ B.sweet_tooth.must_equal false
220
+ C.sweet_tooth.must_equal false
221
+ end
222
+
223
+ describe "a descendent redefines the property with a proc" do
224
+ before do
225
+ class D < C; end
226
+
227
+ B.cascade do
228
+ diabetic :default => false
229
+ end
230
+
231
+ B.ingredients = Proc.new do |me, parents|
232
+ me.diabetic ? parents.first.ingredients.dup.delete(:sugar) << :splenda :
233
+ parents.first.ingredients.dup.delete(:splenda) << :sugar
234
+ end
235
+
236
+ B.sweet_tooth = Proc.new{|me, parents| me.ingredients.include? :sugar}
237
+ end
238
+
239
+ after do
240
+ Object.send :remove_const, :D
241
+ end
242
+
243
+ it "further descendents inherit the proc" do
244
+ C.diabetic = true
245
+ D.diabetic = false
246
+
247
+ B.diabetic.must_equal false
248
+ C.diabetic.must_equal true
249
+ D.diabetic.must_equal false
250
+
251
+ B.ingredients.must_equal Set.new([:sugar, :butter, :flour, :eggs])
252
+ C.ingredients.must_equal Set.new([:splenda, :butter, :flour, :eggs])
253
+ D.ingredients.must_equal Set.new([:sugar, :butter, :flour, :eggs])
254
+
255
+ A.sweet_tooth.must_equal false
256
+ B.sweet_tooth.must_equal true
257
+ C.sweet_tooth.must_equal false
258
+ D.sweet_tooth.must_equal true
259
+ end
260
+
261
+ describe "descendents redefine the property, but not to a proc" do
262
+ before do
263
+ C.ingredients = Set.new([:equal, :butter, :flour, :eggs])
264
+ C.sweet_tooth = false
265
+ end
266
+
267
+ it "descendents reflect the new 'static' settings" do
268
+ C.ingredients.must_equal Set.new([:equal, :butter, :flour, :eggs])
269
+ D.ingredients.must_equal Set.new([:equal, :butter, :flour, :eggs])
270
+
271
+ C.sweet_tooth.must_equal false
272
+ D.sweet_tooth.must_equal false
273
+ end
274
+ end
275
+ end
276
+ end
277
+
278
+ describe "syntax" do
279
+ it "takes two params: self, parent classes" do
280
+ who_am_i, which_parents = nil, nil
281
+
282
+ B.color = Proc.new{|me, parents|
283
+ who_am_i = me
284
+ which_parents = parents
285
+ "green"
286
+ }
287
+
288
+ B.color.must_equal("green")
289
+ who_am_i.must_equal(B)
290
+ which_parents.must_equal([A])
291
+ end
292
+
293
+ it "evaluates to the property value" do
294
+ B.color = Proc.new{ "green" }
295
+ B.color.must_equal "green"
296
+
297
+ C.color = Proc.new{|me, parents|
298
+ "#{me} #{parents.first.color.capitalize}"
299
+ }
300
+ C.color.must_equal "C Green"
301
+ end
302
+ end
303
+ end
304
+
305
+ describe "examples" do
306
+ before do
307
+ class A; extend CC; end
308
+ class B < A; end
309
+ class C < B; end
310
+ end
311
+
312
+ after do
313
+ Object.send :remove_const, :A
314
+ Object.send :remove_const, :B
315
+ Object.send :remove_const, :C
316
+ end
317
+
318
+ describe "merge: hash property" do
319
+ before do
320
+ A.cascade do
321
+ opts :default => {:color => "black", :music => ["Rolling Stones"]}
322
+ merged_opts :proc => true
323
+ end
324
+
325
+ A.merged_opts = Proc.new do |me, parents|
326
+ parents.reverse.inject({}){|r, child|
327
+ r.merge(child.opts)
328
+ }.merge(me.opts)
329
+ end
330
+
331
+ B.opts[:music] = ["Arcade Fire"]
332
+ C.opts[:color] = "blond"
333
+ end
334
+
335
+ it "works" do
336
+ A.merged_opts.must_equal({:color => "black", :music => ["Rolling Stones"]})
337
+ B.merged_opts.must_equal({:color => "black", :music => ["Arcade Fire"]})
338
+ C.merged_opts.must_equal({:color => "blond", :music => ["Arcade Fire"]})
339
+ end
340
+ end
341
+ end
342
+
343
+