cascading_classes 0.3.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+