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,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