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