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,36 @@
1
+ begin
2
+ require_relative '../helper_spec'
3
+ rescue NameError
4
+ require File.expand_path('../helper_spec', __FILE__)
5
+ end
6
+
7
+ describe "parents_for()" do
8
+ before do
9
+ A = Class.new{extend CC}
10
+ B = Class.new(A)
11
+ C = Class.new(B)
12
+
13
+ A.cascade do
14
+ color :default => "red"
15
+ end
16
+
17
+ B.cascade do
18
+ score :default => 45.32
19
+ end
20
+ end
21
+
22
+ after do
23
+ Object.send :remove_const, :A
24
+ Object.send :remove_const, :B
25
+ Object.send :remove_const, :C
26
+ end
27
+
28
+ it "lists ancestors for given property" do
29
+ A.parents_for(:color).must_equal []
30
+ B.parents_for(:color).must_equal [A]
31
+ C.parents_for(:color).must_equal [B, A]
32
+
33
+ B.parents_for(:score).must_equal []
34
+ C.parents_for(:score).must_equal [B]
35
+ end
36
+ end
@@ -0,0 +1,144 @@
1
+ begin
2
+ require_relative '../helper_spec'
3
+ rescue NameError
4
+ require File.expand_path('../helper_spec', __FILE__)
5
+ end
6
+
7
+ describe "custom hash-like class" do
8
+ before do
9
+ class MyCustom < Hash
10
+ def initialize(*arr)
11
+ return super unless arr.size > 0
12
+ [*arr].flatten.each_slice(2){|k,v| self[k] = v}
13
+ end
14
+ end
15
+
16
+ Parent = Class.new{include CC}
17
+ class Child < Parent; end
18
+ class GrandChild < Child; end
19
+
20
+ @props = Parent.cascade do
21
+ beta :default => MyCustom.new([:rank, 4], [:color, "red"]),
22
+ :new => proc{ MyCustom.new },
23
+ :blank => proc{|v| v.empty?}
24
+ end
25
+ end
26
+
27
+ after do
28
+ Object.send :remove_const, :MyCustom
29
+ Object.send :remove_const, :Parent
30
+ Object.send :remove_const, :Child
31
+ Object.send :remove_const, :GrandChild
32
+ end
33
+
34
+ describe "by default" do
35
+ it "is set to not inherit by default" do
36
+ @props[:beta][:inherit].must_equal false
37
+ end
38
+
39
+ it "descendents (including instances) do not inherit" do
40
+ Parent.new.beta.must_equal MyCustom.new
41
+ Child.beta.must_equal MyCustom.new
42
+ Child.new.beta.must_equal MyCustom.new
43
+ GrandChild.beta.must_equal MyCustom.new
44
+ GrandChild.new.beta.must_equal MyCustom.new
45
+ end
46
+
47
+ it "'Parent' has 'default' value" do
48
+ Parent.beta.must_equal MyCustom.new(:rank, 4, :color, "red")
49
+ end
50
+
51
+ it "has type ':MyCustom'" do
52
+ @props[:beta][:type].must_equal :MyCustom
53
+ end
54
+
55
+ it "has blank value of empty 'MyCustom' object" do
56
+ mc = MyCustom.new
57
+ mc.empty?.must_equal true
58
+
59
+ @props[:beta][:blank].call(mc).must_equal true
60
+ end
61
+
62
+ it "has new value of empty 'MyCustom' object" do
63
+ @props[:beta][:new].call.must_equal MyCustom.new
64
+ end
65
+
66
+ it "nonblank values never inherit" do
67
+ # ???
68
+ end
69
+ end
70
+
71
+ describe "property in instance of 'Parent' is blank" do
72
+ before do
73
+ @parent = Parent.new
74
+ end
75
+
76
+ it "can inherit one level up to 'Parent'" do
77
+ mc = MyCustom.new(:rank, 4); mc[:color] = "red"
78
+ blank_inherit_helper(@parent, :beta, 1, mc, MyCustom.new)
79
+ end
80
+ end
81
+
82
+ describe "'Child'" do
83
+ describe "property on 'Child' is blank" do
84
+ it "can inherit one level up to 'Parent'" do
85
+ mc = MyCustom.new([[:rank, 4], [:color, "red"]])
86
+ blank_inherit_helper(Child, :beta, 1, mc, MyCustom.new)
87
+ end
88
+
89
+ describe "property on instance of 'Child' is blank" do
90
+ before do
91
+ @child = Child.new
92
+ end
93
+
94
+ it "can inherit two levels up to 'Parent'" do
95
+ mc = MyCustom.new(:rank, 4, :color, "red")
96
+ blank_inherit_helper(@child, :beta, 2, mc, MyCustom.new)
97
+ end
98
+ end
99
+
100
+ describe "property on 'GrandChild' is blank" do
101
+ it "can inherit two levels up to 'Parent'" do
102
+ blank_inherit_helper(GrandChild, :beta, 2,
103
+ MyCustom.new(:rank, 4, :color, "red"),
104
+ MyCustom.new)
105
+ end
106
+ end
107
+ end
108
+
109
+ describe "property on 'Child' is nonblank" do
110
+ before do
111
+ Child.beta[:colors] = [:red, :yellow, :blue]
112
+ end
113
+
114
+ describe "property on instance of 'Child' is blank" do
115
+ before do
116
+ @child = Child.new
117
+ end
118
+
119
+ it "can inherit one level up to 'Child'" do
120
+ mc = MyCustom.new; mc[:colors] = [:red, :yellow, :blue]
121
+ blank_inherit_helper(@child, :beta, 1, mc, MyCustom.new)
122
+ end
123
+ end
124
+
125
+ describe "property on 'GrandChild' is blank" do
126
+ it "can inherit one level up to 'Child'" do
127
+ mc = MyCustom.new; mc[:colors] = [:red, :yellow, :blue]
128
+ blank_inherit_helper(GrandChild, :beta, 1, mc, MyCustom.new)
129
+ end
130
+
131
+ describe "property on instance of 'GrandChild' is blank" do
132
+ before do
133
+ @grandchild = GrandChild.new
134
+ end
135
+
136
+ it "can inherit two levels up to 'Child'" do
137
+ mc = MyCustom.new; mc[:colors] = [:red, :yellow, :blue]
138
+ blank_inherit_helper(@grandchild, :beta, 2, mc, MyCustom.new)
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
data/spec/helper_spec.rb CHANGED
@@ -2,6 +2,38 @@ $:.unshift File.expand_path('../../lib', __FILE__)
2
2
  require 'cascading_classes'
3
3
  require 'minitest/autorun'
4
4
 
5
- class << MiniTest::Spec
6
- alias_method :all, :it
5
+ ## class << MiniTest::Spec
6
+ ## alias_method :all, :it
7
+ ## end
8
+
9
+ def blank_inherit_helper(obj, property, expected_depth, expected_val, empty)
10
+ obj.send("#{property}_is_blank?").must_equal true
11
+
12
+ dont_inherit = (expected_depth < 0) ? [0] : (0...expected_depth).to_a
13
+ dont_inherit << false << nil
14
+ dont_inherit.each do |i|
15
+ obj.send(property, i).must_equal empty
16
+ obj.send(property, :inherit => i).must_equal empty
17
+ obj.send(property, :inherit, i).must_equal empty
18
+ end
19
+
20
+ do_inherit = (expected_depth < 0) ? [] : (expected_depth..(expected_depth+1)).to_a
21
+ do_inherit << true << -1
22
+ do_inherit.each do |i|
23
+ obj.send(property, i).must_equal(expected_val)
24
+ obj.send(property, :inherit => i).must_equal(expected_val)
25
+ obj.send(property, :inherit, i).must_equal(expected_val)
26
+ end
27
+ end
28
+
29
+ def nonblank_helper(obj, property, expected)
30
+ obj.send("#{property}_is_blank?").must_equal false
31
+
32
+ vals = [0, 1, 2, 3, -1, false, true, nil]
33
+ vals.each do |i|
34
+ obj.send(property, i).must_equal expected
35
+ obj.send(property, :inherit => i).must_equal expected
36
+ obj.send(property, :inherit, i).must_equal expected
37
+ end
7
38
  end
39
+
@@ -0,0 +1,239 @@
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
+ # defaults: hash of defaults
10
+ def getters(obj, defaults)
11
+ defaults.each do |key, val|
12
+ obj.send(key).must_equal val
13
+ end
14
+ end
15
+
16
+ def container_getters(obj, depth)
17
+ obj.urls(false).must_equal Array.new
18
+ obj.urls(nil).must_equal Array.new
19
+ 0.upto(depth-1).each do |i|
20
+ obj.urls(i).must_equal Array.new
21
+ end
22
+ depth.upto(depth+1).each do |i|
23
+ obj.urls(i).must_equal ["www.google.com"]
24
+ end
25
+ obj.urls(-1).must_equal ["www.google.com"]
26
+ obj.urls(true).must_equal ["www.google.com"]
27
+
28
+ obj.name(false).must_equal Hash.new
29
+ obj.name(nil).must_equal Hash.new
30
+ 0.upto(depth-1).each do |i|
31
+ obj.name(i).must_equal Hash.new
32
+ end
33
+ depth.upto(depth+1).each do |i|
34
+ obj.name(i).must_equal({:first => 'jon', :last => 'smith'})
35
+ end
36
+ obj.name(true).must_equal({:first => 'jon', :last => 'smith'})
37
+ obj.name(-1).must_equal({:first => 'jon', :last => 'smith'})
38
+ end
39
+
40
+ def setters(obj)
41
+ obj.color = "blue"
42
+ obj.color.must_equal "blue"
43
+
44
+ obj.setting = :rural
45
+ obj.setting.must_equal :rural
46
+
47
+ obj.score = 28.1
48
+ obj.score.must_equal 28.1
49
+
50
+ obj.num = 15
51
+ obj.num.must_equal 15
52
+
53
+ obj.available = false
54
+ obj.available.must_equal false
55
+
56
+ obj.urls << "www.yahoo.com" << "www.bing.com"
57
+ obj.urls.must_equal ["www.yahoo.com", "www.bing.com"]
58
+
59
+ obj.urls = ["www.nytimes.com"]
60
+ obj.urls.must_equal ["www.nytimes.com"]
61
+
62
+ obj.verify.must_equal false # doesn't inherit name
63
+ obj.verify2.must_equal true # inherits name
64
+
65
+ obj.name[:first] = 'thomas'
66
+ obj.name[:last] = 'smith'
67
+ obj.name.must_equal({:first => 'thomas', :last => 'smith'})
68
+
69
+ obj.verify.must_equal true
70
+ obj.verify2.must_equal true
71
+
72
+ obj.verify = Proc.new{|me| me.name[:first] !~ /mas/}
73
+ obj.verify2 = Proc.new{|me| me.name(true)[:first] !~ /mas/}
74
+
75
+ obj.verify.must_equal false
76
+ obj.verify2.must_equal false
77
+ end
78
+
79
+ describe "instances: via 'extend'" do
80
+ before do
81
+ A = Class.new{extend CC}
82
+ B = Class.new(A)
83
+ C = Class.new(B)
84
+ end
85
+
86
+ after do
87
+ Object.send :remove_const, :A
88
+ Object.send :remove_const, :B
89
+ Object.send :remove_const, :C
90
+ end
91
+
92
+ describe "by default" do
93
+ before do
94
+ @props = A.cascade do
95
+ color :default => "red"
96
+ setting :default => :urban
97
+ score :default => 34.1
98
+ num :default => 3
99
+ available :default => true
100
+ urls :default => ["www.google.com"]
101
+ name :default => {:first => 'jon', :last => 'smith'}
102
+ verify :default => Proc.new{|me| me.name[:last] == 'smith'}
103
+ end
104
+ end
105
+
106
+ it "does not create properties for instances" do
107
+ a = A.new
108
+ [:color, :setting, :score, :num, :available,
109
+ :urls, :name, :verify].each do |t|
110
+ @props[t][:instances_too].must_equal false
111
+ a.respond_to?(:t).must_equal false
112
+ end
113
+ end
114
+ end
115
+
116
+ describe "extend: override default" do
117
+ before do
118
+ @props = A.cascade do
119
+ color :default => "red", :instances => true
120
+ setting :default => :urban, :instances => true
121
+ score :default => 34.1, :instances => true
122
+ num :default => 3, :instances => true
123
+ available :default => true, :instance => true
124
+ urls :default => ["www.google.com"], :instance => true
125
+ name :default => {:first => 'jon', :last => 'smith'}, :instance => true
126
+ verify :default => Proc.new{|me| me.name[:last] == 'smith'}, :instance => true
127
+ verify2 :default => Proc.new{|me| me.name(true)[:last] == 'smith'}, :instance => true
128
+ end
129
+ end
130
+
131
+ it "adds properties to instances" do
132
+ a = A.new
133
+ [:color, :setting, :score, :num, :available,
134
+ :urls, :name, :verify, :verify2].each do |t|
135
+ @props[t][:instances_too].must_equal true
136
+ a.respond_to?(t).must_equal true
137
+ end
138
+ end
139
+
140
+ it "inherits all non-container properties" do
141
+ [:color, :setting, :score, :num, :available, :verify, :verify2].each do |t|
142
+ @props[t][:inherit].must_equal true
143
+ end
144
+ @props[:urls][:inherit].must_equal false
145
+ @props[:name][:inherit].must_equal false
146
+
147
+ defaults = A.to_hash # assumes 'to_hash' works; ie: likely testing it too
148
+ [:urls, :name, :verify, :verify2].each{|j| defaults.delete j}
149
+
150
+ getters(A.new, defaults)
151
+ getters(B.new, defaults)
152
+ getters(C.new, defaults)
153
+ end
154
+
155
+ it "inherits container properties only when explicitly told to do so" do
156
+ container_getters(A.new, 1)
157
+ container_getters(B.new, 2)
158
+ container_getters(C.new, 3)
159
+ end
160
+
161
+ it "has instance setters" do
162
+ setters(A.new)
163
+ end
164
+
165
+ it "has subclass instance setters" do
166
+ setters(B.new)
167
+ setters(C.new)
168
+ end
169
+ end
170
+ end
171
+
172
+ describe "instances: via 'include'" do
173
+ before do
174
+ A = Class.new{include CC}
175
+ B = Class.new(A)
176
+ C = Class.new(B)
177
+ end
178
+
179
+ after do
180
+ Object.send :remove_const, :A
181
+ Object.send :remove_const, :B
182
+ Object.send :remove_const, :C
183
+ end
184
+
185
+ describe "defaults" do
186
+ before do
187
+ @props = A.cascade do
188
+ color :default => "red"
189
+ setting :default => :urban
190
+ score :default => 34.1
191
+ num :default => 3
192
+ available :default => true
193
+ urls :default => ["www.google.com"]
194
+ name :default => {:first => 'jon', :last => 'smith'}
195
+ verify :default => Proc.new{|me| me.name[:last] == 'smith'}
196
+ verify2 :default => Proc.new{|me| me.name(true)[:last] == 'smith'}
197
+ end
198
+ end
199
+
200
+ it "adds properties to instances" do
201
+ a = A.new
202
+ [:color, :setting, :score, :num, :available,
203
+ :urls, :name, :verify, :verify2].each do |t|
204
+ @props[t][:instances_too].must_equal true
205
+ a.respond_to?(t).must_equal true
206
+ end
207
+ end
208
+
209
+ it "inherits all non-container properties" do
210
+ [:color, :setting, :score, :num, :available, :verify, :verify2].each do |t|
211
+ @props[t][:inherit].must_equal true
212
+ end
213
+ @props[:urls][:inherit].must_equal false
214
+ @props[:name][:inherit].must_equal false
215
+
216
+ defaults = A.to_hash # assumes 'to_hash' works; ie: likely testing it too
217
+ [:urls, :name, :verify, :verify2].each{|j| defaults.delete j}
218
+
219
+ getters(A.new, defaults)
220
+ getters(B.new, defaults)
221
+ getters(C.new, defaults)
222
+ end
223
+
224
+ it "inherits container properties only when explicitly told to do so" do
225
+ container_getters(A.new, 1)
226
+ container_getters(B.new, 2)
227
+ container_getters(C.new, 3)
228
+ end
229
+
230
+ it "has instance setters" do
231
+ setters(A.new)
232
+ end
233
+
234
+ it "has subclass instance setters" do
235
+ setters(B.new)
236
+ setters(C.new)
237
+ end
238
+ end
239
+ end