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,214 @@
1
+ begin
2
+ require_relative '../helper_spec'
3
+ rescue NameError
4
+ require File.expand_path('../helper_spec', __FILE__)
5
+ end
6
+
7
+ describe "array syntax" do
8
+ before do
9
+ Parent = Class.new{extend CC}
10
+ Child = Class.new(Parent)
11
+ GrandChild = Class.new(Child)
12
+ end
13
+
14
+ after do
15
+ Object.send :remove_const, :Parent
16
+ Object.send :remove_const, :Child
17
+ Object.send :remove_const, :GrandChild
18
+ end
19
+
20
+ describe "equivalent syntax" do
21
+ before do
22
+ Parent.cascade do
23
+ colors_a :default => [:red, :blue, :yellow]
24
+ colors_b :array => true
25
+ colors_c
26
+ end
27
+
28
+ props = Parent.singleton_class.properties
29
+
30
+ props[:colors_a][:type].must_equal :Array
31
+ props[:colors_b][:type].must_equal :Array
32
+ props[:colors_c][:type].must_equal :undefined_type
33
+ Parent.colors_a.must_equal [:red, :blue, :yellow]
34
+ Parent.colors_b.must_equal []
35
+ Parent.colors_c.must_equal nil
36
+
37
+ Parent.colors_b << :red << :blue << :yellow
38
+ Parent.colors_c = [:red, :blue, :yellow]
39
+
40
+ props[:colors_c][:type].must_equal :Array
41
+ Parent.colors_b.must_equal [:red, :blue, :yellow]
42
+ Parent.colors_c.must_equal [:red, :blue, :yellow]
43
+
44
+ Parent.cascade [:colors_d, [:red, :blue, :yellow]], :colors_e
45
+ Parent.cascade [:colors_f, [:red, :blue, :yellow]]
46
+ Parent.cascade :colors_g
47
+
48
+ props[:colors_d][:type].must_equal :Array
49
+ props[:colors_e][:type].must_equal :undefined_type
50
+ props[:colors_f][:type].must_equal :Array
51
+ props[:colors_g][:type].must_equal :undefined_type
52
+ Parent.colors_d.must_equal [:red, :blue, :yellow]
53
+ Parent.colors_e.must_equal nil
54
+ Parent.colors_f.must_equal [:red, :blue, :yellow]
55
+ Parent.colors_g.must_equal nil
56
+
57
+ Parent.colors_e = [:red, :blue, :yellow]
58
+ Parent.colors_g = [:red, :blue, :yellow]
59
+
60
+ props[:colors_e][:type].must_equal :Array
61
+ props[:colors_g][:type].must_equal :Array
62
+ Parent.colors_e.must_equal [:red, :blue, :yellow]
63
+ Parent.colors_g.must_equal [:red, :blue, :yellow]
64
+ end
65
+
66
+ it "is all the same" do
67
+ Parent.colors_a.must_equal [:red, :blue, :yellow]
68
+ Parent.colors_b.must_equal [:red, :blue, :yellow]
69
+ Parent.colors_c.must_equal [:red, :blue, :yellow]
70
+ Parent.colors_d.must_equal [:red, :blue, :yellow]
71
+ Parent.colors_e.must_equal [:red, :blue, :yellow]
72
+ Parent.colors_f.must_equal [:red, :blue, :yellow]
73
+ Parent.colors_g.must_equal [:red, :blue, :yellow]
74
+ end
75
+ end
76
+ end
77
+
78
+ describe "array syntax" do
79
+ before do
80
+ Parent = Class.new{include CC}
81
+ Child = Class.new(Parent)
82
+ GrandChild = Class.new(Child)
83
+
84
+ @props = Parent.cascade do
85
+ fruit :default => [:orange, :apple, :pear]
86
+ end
87
+ end
88
+
89
+ after do
90
+ Object.send :remove_const, :Parent
91
+ Object.send :remove_const, :Child
92
+ Object.send :remove_const, :GrandChild
93
+ end
94
+
95
+ describe "by default" do
96
+ it "is set to not 'inherit' by default" do
97
+ @props[:fruit][:inherit].must_equal(false)
98
+ Child.fruit.must_equal []
99
+ end
100
+
101
+ it "descendents (including instances) do not inherit" do
102
+ Parent.new.fruit.must_equal []
103
+ Child.fruit.must_equal []
104
+ Child.new.fruit.must_equal []
105
+ GrandChild.fruit.must_equal []
106
+ GrandChild.new.fruit.must_equal []
107
+ end
108
+
109
+ it "'Parent' has default value" do
110
+ Parent.fruit.must_equal [:orange, :apple, :pear]
111
+ end
112
+
113
+ it "has type ':Array'" do
114
+ @props[:fruit][:type].must_equal :Array
115
+ end
116
+
117
+ it "has blank value of empty array" do
118
+ @props[:fruit][:blank].call([]).must_equal true
119
+ end
120
+
121
+ it "has new value of empty array" do
122
+ @props[:fruit][:new].call.must_equal []
123
+ end
124
+
125
+ it "nonblank values never inherit" do
126
+ nonblank_helper(Parent, :fruit, [:orange, :apple, :pear])
127
+
128
+ parent = Parent.new
129
+ parent.fruit = [:mango, :pineapple]
130
+ nonblank_helper(parent, :fruit, [:mango, :pineapple])
131
+
132
+ Child.fruit = ["summer", "rain"]
133
+ nonblank_helper(Child, :fruit, ["summer", "rain"])
134
+
135
+ child = Child.new
136
+ child.fruit = [:lemons, :limes]
137
+ nonblank_helper(child, :fruit, [:lemons, :limes])
138
+
139
+ GrandChild.fruit = [:watermelon, :orange]
140
+ nonblank_helper(GrandChild, :fruit, [:watermelon, :orange])
141
+
142
+ grandchild = GrandChild.new
143
+ grandchild.fruit = [{:time => false, :color => "blue"}]
144
+ nonblank_helper(grandchild, :fruit, [{:time => false, :color => "blue"}])
145
+ end
146
+ end
147
+
148
+ describe "property on instance of 'Parent' is blank" do
149
+ before do
150
+ @parent = Parent.new
151
+ end
152
+
153
+ it "can inherit one level up to 'Parent'" do
154
+ blank_inherit_helper(@parent, :fruit, 1, [:orange, :apple, :pear], [])
155
+ end
156
+ end
157
+
158
+ describe "'Child'" do
159
+ describe "property on 'Child' is blank" do
160
+ it "can inherit one level up to 'Parent'" do
161
+ blank_inherit_helper(Child, :fruit, 1, [:orange, :apple, :pear], [])
162
+ end
163
+
164
+ describe "property on instance of 'Child' is blank" do
165
+ before do
166
+ @child = Child.new
167
+ end
168
+
169
+ it "can inherit two levels up to 'Parent'" do
170
+ blank_inherit_helper(@child, :fruit, 2, [:orange, :apple, :pear], [])
171
+ end
172
+ end
173
+
174
+ describe "property on 'GrandChild' is blank" do
175
+ it "can inherit two levels up to 'Parent'" do
176
+ blank_inherit_helper(GrandChild, :fruit, 2, [:orange, :apple, :pear], [])
177
+ end
178
+ end
179
+ end
180
+
181
+ describe "property on 'Child' is nonblank" do
182
+ before do
183
+ Child.fruit = [:mango, :pineapple]
184
+ end
185
+
186
+ describe "property on instance of 'Child' is blank" do
187
+ before do
188
+ @child = Child.new
189
+ end
190
+
191
+ it "can inherit one level up to 'Child'" do
192
+ blank_inherit_helper(@child, :fruit, 1, [:mango, :pineapple], [])
193
+ end
194
+ end
195
+
196
+ describe "property on 'GrandChild' is blank" do
197
+ it "can inherit one level up to 'Child'" do
198
+ blank_inherit_helper(GrandChild, :fruit, 1, [:mango, :pineapple], [])
199
+ end
200
+
201
+ describe "property on instance of 'GrandChild' is blank" do
202
+ before do
203
+ @grandchild = GrandChild.new
204
+ end
205
+
206
+ it "can inherit two levels up to 'Child'" do
207
+ blank_inherit_helper(@grandchild, :fruit, 2, [:mango, :pineapple], [])
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end
214
+
@@ -0,0 +1,210 @@
1
+ begin
2
+ require_relative '../helper_spec'
3
+ rescue NameError
4
+ require File.expand_path('../helper_spec', __FILE__)
5
+ end
6
+
7
+ # todo: subclasses that inherit :Object (undefined types)
8
+
9
+ describe "hash syntax" do
10
+ before do
11
+ Parent = Class.new{extend CC}
12
+ Child = Class.new(Parent)
13
+ GrandChild = Class.new(Child)
14
+ end
15
+
16
+ after do
17
+ Object.send :remove_const, :Parent
18
+ Object.send :remove_const, :Child
19
+ Object.send :remove_const, :GrandChild
20
+ end
21
+
22
+ describe "equivalent syntax" do
23
+ before do
24
+ Parent.cascade do
25
+ person_a :default => {:name => ['williamson', 'charles']}
26
+ person_b :hash => true
27
+ person_c
28
+ end
29
+
30
+ props = Parent.singleton_class.properties
31
+
32
+ props[:person_a][:type].must_equal :Hash
33
+ props[:person_b][:type].must_equal :Hash
34
+ props[:person_c][:type].must_equal :undefined_type
35
+ Parent.person_a.must_equal({:name => ['williamson', 'charles']})
36
+ Parent.person_b.must_equal({})
37
+ Parent.person_c.must_equal nil
38
+
39
+ Parent.person_b[:name] = ['williamson', 'charles']
40
+ Parent.person_c = {:name => ['williamson', 'charles']}
41
+ props[:person_c][:type].must_equal :Hash
42
+ Parent.person_b.must_equal({:name => ['williamson', 'charles']})
43
+ Parent.person_c.must_equal({:name => ['williamson', 'charles']})
44
+
45
+ Parent.cascade [:person_d, {:name => ['williamson', 'charles']}], :person_e
46
+ Parent.cascade [:person_f, {:name => ['williamson', 'charles']}]
47
+ Parent.cascade :person_g
48
+ props[:person_d][:type].must_equal :Hash
49
+ props[:person_e][:type].must_equal :undefined_type
50
+ props[:person_f][:type].must_equal :Hash
51
+ props[:person_g][:type].must_equal :undefined_type
52
+ Parent.person_d.must_equal({:name => ['williamson', 'charles']})
53
+ Parent.person_e.must_equal nil
54
+ Parent.person_f.must_equal({:name => ['williamson', 'charles']})
55
+ Parent.person_g.must_equal nil
56
+
57
+ Parent.person_e = Parent.person_g = {:name => ['williamson', 'charles']}
58
+ props[:person_e][:type].must_equal :Hash
59
+ props[:person_g][:type].must_equal :Hash
60
+ Parent.person_e.must_equal({:name => ['williamson', 'charles']})
61
+ Parent.person_g.must_equal({:name => ['williamson', 'charles']})
62
+ end
63
+
64
+ it 'is all the same' do
65
+ Parent.person_a.must_equal({:name => ['williamson', 'charles']})
66
+ Parent.person_b.must_equal({:name => ['williamson', 'charles']})
67
+ Parent.person_c.must_equal({:name => ['williamson', 'charles']})
68
+ Parent.person_d.must_equal({:name => ['williamson', 'charles']})
69
+ Parent.person_e.must_equal({:name => ['williamson', 'charles']})
70
+ Parent.person_f.must_equal({:name => ['williamson', 'charles']})
71
+ Parent.person_g.must_equal({:name => ['williamson', 'charles']})
72
+ end
73
+ end
74
+ end
75
+
76
+ describe "hash usage" do
77
+ before do
78
+ Parent = Class.new{include CC}
79
+ Child = Class.new(Parent)
80
+ GrandChild = Class.new(Child)
81
+
82
+ @props = Parent.cascade do
83
+ eyes :default => {:color => "red"}
84
+ end
85
+ end
86
+
87
+ after do
88
+ Object.send :remove_const, :Parent
89
+ Object.send :remove_const, :Child
90
+ Object.send :remove_const, :GrandChild
91
+ end
92
+
93
+ describe "by default" do
94
+ it "is set to not 'inherit' by default" do
95
+ @props[:eyes][:inherit].must_equal false
96
+ end
97
+
98
+ it "descendents (including instances) do not inherit" do
99
+ Parent.new.eyes.must_equal({})
100
+ Child.eyes.must_equal({})
101
+ Child.new.eyes.must_equal({})
102
+ GrandChild.eyes.must_equal({})
103
+ GrandChild.new.eyes.must_equal({})
104
+ end
105
+
106
+ it "'Parent' has 'default' value" do
107
+ Parent.eyes.must_equal({:color => "red"})
108
+ end
109
+
110
+ it "has type ':Hash'" do
111
+ @props[:eyes][:type].must_equal :Hash
112
+ end
113
+
114
+ it "has blank value of empty hash" do
115
+ @props[:eyes][:blank].call({}).must_equal true
116
+ end
117
+
118
+ it "has new value of empty hash" do
119
+ @props[:eyes][:new].call.must_equal({})
120
+ end
121
+
122
+ it "nonblank values never inherit" do
123
+ nonblank_helper(Parent, :eyes, {:color => "red"})
124
+
125
+ parent = Parent.new
126
+ parent.eyes[:style] = "western"
127
+ nonblank_helper(parent, :eyes, {:style => "western"})
128
+
129
+ Child.eyes[:orig] = true
130
+ nonblank_helper(Child, :eyes, {:orig => true})
131
+
132
+ child = Child.new
133
+ child.eyes[:temp] = 95
134
+ nonblank_helper(child, :eyes, {:temp => 95})
135
+
136
+ GrandChild.eyes[:layout] = :normal
137
+ nonblank_helper(GrandChild, :eyes, {:layout => :normal})
138
+
139
+ grandchild = GrandChild.new
140
+ grandchild.eyes[:locale] = "en"
141
+ nonblank_helper(grandchild, :eyes, {:locale => "en"})
142
+ end
143
+ end
144
+
145
+ describe "property on instance of 'Parent' is blank" do
146
+ before do
147
+ @parent = Parent.new
148
+ end
149
+
150
+ it "can inherit one level up to 'Parent'" do
151
+ blank_inherit_helper(@parent, :eyes, 1, {:color => "red"}, {})
152
+ end
153
+ end
154
+
155
+ describe "'Child'" do
156
+ describe "property on 'Child' is blank" do
157
+ it "can inherit one level up to 'Parent'" do
158
+ blank_inherit_helper(Child, :eyes, 1, {:color => "red"}, {})
159
+ end
160
+
161
+ describe "property on instance of 'Child' is blank" do
162
+ before do
163
+ @child = Child.new
164
+ end
165
+
166
+ it "can inherit two levels up to 'Parent'" do
167
+ blank_inherit_helper(@child, :eyes, 2, {:color => "red"}, {})
168
+ end
169
+ end
170
+
171
+ describe "property on 'GrandChild' is blank" do
172
+ it "can inherit two levels up to 'Parent'" do
173
+ blank_inherit_helper(GrandChild, :eyes, 2, {:color => "red"}, {})
174
+ end
175
+ end
176
+ end
177
+
178
+ describe "property on 'Child' is nonblank" do
179
+ before do
180
+ Child.eyes[:degrees] = [:bachelors]
181
+ end
182
+
183
+ describe "property on instance of 'Child' is blank" do
184
+ before do
185
+ @child = Child.new
186
+ end
187
+
188
+ it "can inherit one level up to 'Child'" do
189
+ blank_inherit_helper(@child, :eyes, 1, {:degrees => [:bachelors]}, {})
190
+ end
191
+ end
192
+
193
+ describe "property on 'GrandChild' is blank" do
194
+ it "can inherit one level up to 'Child'" do
195
+ blank_inherit_helper(GrandChild, :eyes, 1, {:degrees => [:bachelors]}, {})
196
+ end
197
+
198
+ describe "property on instance of 'GrandChild' is blank" do
199
+ before do
200
+ @grandchild = GrandChild.new
201
+ end
202
+
203
+ it "can inherit two levels up to 'Child'" do
204
+ blank_inherit_helper(@grandchild, :eyes, 2, {:degrees => [:bachelors]}, {})
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,190 @@
1
+ begin
2
+ require_relative '../helper_spec'
3
+ rescue NameError
4
+ require File.expand_path('../helper_spec', __FILE__)
5
+ end
6
+
7
+ describe "string - base" do
8
+ before do
9
+ Parent = Class.new{extend CC}
10
+ Child = Class.new(Parent)
11
+ GrandChild = Class.new(Child)
12
+ end
13
+
14
+ after do
15
+ Object.send :remove_const, :Parent
16
+ Object.send :remove_const, :Child
17
+ Object.send :remove_const, :GrandChild
18
+ end
19
+
20
+ describe "equivalent syntax" do
21
+ before do
22
+ Parent.cascade do
23
+ color_a :default => "white"
24
+ color_b :string => true
25
+ color_c
26
+ end
27
+
28
+ props = Parent.singleton_class.properties
29
+
30
+ props[:color_a][:type].must_equal :String
31
+ props[:color_b][:type].must_equal :String
32
+ props[:color_c][:type].must_equal :Object
33
+ Parent.color_a.must_equal "white"
34
+ Parent.color_b.must_equal ''
35
+ Parent.color_c.must_equal nil
36
+
37
+ Parent.color_b = "white"
38
+ Parent.color_c = "white"
39
+ props[:color_c][:type].must_equal :String
40
+ Parent.color_b.must_equal "white"
41
+ Parent.color_c.must_equal "white"
42
+
43
+ Parent.cascade [:color_d, "white"], :color_e
44
+ Parent.cascade [:color_f, "white"]
45
+ Parent.cascade :color_g
46
+ props[:color_d][:type].must_equal :String
47
+ props[:color_e][:type].must_equal :Object
48
+ props[:color_f][:type].must_equal :String
49
+ props[:color_g][:type].must_equal :Object
50
+ Parent.color_d.must_equal "white"
51
+ Parent.color_e.must_equal nil
52
+ Parent.color_f.must_equal "white"
53
+ Parent.color_g.must_equal nil
54
+
55
+ Parent.color_e = Parent.color_g = "white"
56
+ props[:color_e][:type].must_equal :String
57
+ props[:color_g][:type].must_equal :String
58
+ Parent.color_e.must_equal "white"
59
+ Parent.color_g.must_equal "white"
60
+ end
61
+
62
+ it "is all the same" do
63
+ Parent.color_a.must_equal "white"
64
+ Parent.color_b.must_equal "white"
65
+ Parent.color_c.must_equal "white"
66
+ Parent.color_d.must_equal "white"
67
+ Parent.color_e.must_equal "white"
68
+ Parent.color_f.must_equal "white"
69
+ Parent.color_g.must_equal "white"
70
+ end
71
+ end
72
+ end
73
+
74
+ describe "string" do
75
+ before do
76
+ Parent = Class.new{extend CC}
77
+ Child = Class.new(Parent)
78
+ GrandChild = Class.new(Child)
79
+
80
+ @props = Parent.cascade do
81
+ color :default => "red"
82
+ end
83
+ end
84
+
85
+ after do
86
+ Object.send :remove_const, :Parent
87
+ Object.send :remove_const, :Child
88
+ Object.send :remove_const, :GrandChild
89
+ end
90
+
91
+ describe "by default" do
92
+ it "has type :String" do
93
+ @props[:color][:type].must_equal :String
94
+ end
95
+
96
+ it "inherits by default" do
97
+ @props[:color][:inherit].must_equal true
98
+ end
99
+
100
+ it "has blank value of empty string" do
101
+ @props[:color][:blank].call('').must_equal true
102
+ end
103
+
104
+ it "has new value of empty string" do
105
+ @props[:color][:new].call.must_equal ''
106
+ end
107
+ end
108
+
109
+ describe "'Child' is blank" do
110
+ it "can inherit from 'Parent'" do
111
+ blank_inherit_helper(Child, :color, 1, "red", '')
112
+ end
113
+
114
+ describe "descendents of 'Child'" do
115
+ it "can inherit from 'Parent'" do
116
+ blank_inherit_helper(GrandChild, :color, 2, "red", '')
117
+ end
118
+ end
119
+ end
120
+
121
+ describe "'Child' is not blank" do
122
+ before do
123
+ Child.color = "blue"
124
+ end
125
+
126
+ it "does not inherit" do
127
+ nonblank_helper(Child, :color, "blue")
128
+ end
129
+
130
+ describe "descendents of 'Child'" do
131
+ it "inherits from 'Child'" do
132
+ blank_inherit_helper(GrandChild, :color, 1, "blue", '')
133
+ end
134
+ end
135
+ end
136
+
137
+ describe "change 'blank' proc, leave 'new' proc" do
138
+ before do
139
+ @props = Parent.cascade do
140
+ city :default => "new york", :blank => Proc.new{|v| v.nil?}
141
+ end
142
+ end
143
+
144
+ it "has blank value of nil and new value of empty string" do
145
+ @props[:city][:blank].call('').must_equal false
146
+ @props[:city][:blank].call(nil).must_equal true
147
+
148
+ new_val = @props[:city][:new].call
149
+
150
+ Parent.city.must_equal "new york"
151
+ Parent.city_is_blank?.must_equal false
152
+ Child.city.must_equal new_val
153
+ Child.city_is_blank?.must_equal false
154
+ GrandChild.city.must_equal new_val
155
+ GrandChild.city_is_blank?.must_equal false
156
+
157
+ GrandChild.city = nil
158
+ GrandChild.city_is_blank?.must_equal true
159
+ GrandChild.city.must_equal Child.city
160
+
161
+ Child.city = nil
162
+ Child.city_is_blank?.must_equal true
163
+ Child.city.must_equal Parent.city
164
+
165
+ Parent.city = nil
166
+ Parent.city.must_equal nil
167
+ Parent.city_is_blank?.must_equal true
168
+ end
169
+ end
170
+
171
+ describe "change 'blank' proc and 'new' proc" do
172
+ before do
173
+ @props = Parent.cascade do
174
+ state :default => "NY", :blank => proc{|v| v.nil?}, :new => proc{ nil }
175
+ end
176
+ end
177
+
178
+ it "has blank value of nil and new value of nil" do
179
+ @props[:state][:blank].call('').must_equal false
180
+ @props[:state][:blank].call(nil).must_equal true
181
+ @props[:state][:new].call.must_equal nil
182
+
183
+ Child.state_is_blank?.must_equal true
184
+ GrandChild.state_is_blank?.must_equal true
185
+
186
+ Child.state(false).must_equal nil
187
+ GrandChild.state(false).must_equal nil
188
+ end
189
+ end
190
+ end