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