doodle 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +24 -0
- data/Manifest.txt +26 -1
- data/README.txt +9 -8
- data/lib/doodle.rb +43 -1496
- data/lib/doodle/app.rb +6 -0
- data/lib/doodle/attribute.rb +165 -0
- data/lib/doodle/base.rb +180 -0
- data/lib/doodle/collector-1.9.rb +72 -0
- data/lib/doodle/collector.rb +191 -0
- data/lib/doodle/comparable.rb +8 -0
- data/lib/doodle/conversion.rb +80 -0
- data/lib/doodle/core.rb +42 -0
- data/lib/doodle/datatype-holder.rb +39 -0
- data/lib/doodle/debug.rb +20 -0
- data/lib/doodle/deferred.rb +13 -0
- data/lib/doodle/equality.rb +21 -0
- data/lib/doodle/exceptions.rb +29 -0
- data/lib/doodle/factory.rb +91 -0
- data/lib/doodle/getter-setter.rb +154 -0
- data/lib/doodle/info.rb +298 -0
- data/lib/doodle/inherit.rb +40 -0
- data/lib/doodle/json.rb +38 -0
- data/lib/doodle/marshal.rb +16 -0
- data/lib/doodle/normalized_array.rb +512 -0
- data/lib/doodle/normalized_hash.rb +356 -0
- data/lib/doodle/ordered-hash.rb +8 -0
- data/lib/doodle/singleton.rb +23 -0
- data/lib/doodle/smoke-and-mirrors.rb +23 -0
- data/lib/doodle/to_hash.rb +17 -0
- data/lib/doodle/utils.rb +173 -11
- data/lib/doodle/validation.rb +122 -0
- data/lib/doodle/version.rb +1 -1
- data/lib/molic_orderedhash.rb +24 -10
- data/spec/assigned_spec.rb +45 -0
- data/spec/attributes_spec.rb +7 -7
- data/spec/collector_spec.rb +100 -13
- data/spec/doodle_context_spec.rb +5 -5
- data/spec/from_spec.rb +43 -3
- data/spec/json_spec.rb +232 -0
- data/spec/member_init_spec.rb +11 -11
- data/spec/modules_spec.rb +4 -4
- data/spec/multi_collector_spec.rb +91 -0
- data/spec/must_spec.rb +32 -0
- data/spec/spec_helper.rb +14 -4
- data/spec/specialized_attribute_class_spec.rb +2 -2
- data/spec/typed_collector_spec.rb +57 -0
- data/spec/xml_spec.rb +8 -8
- metadata +33 -3
data/spec/doodle_context_spec.rb
CHANGED
@@ -11,15 +11,15 @@ describe Doodle, "doodle_context" do
|
|
11
11
|
# - a proc/lamba is treated as a literal argument, i.e. the
|
12
12
|
# - value is set to a Proc
|
13
13
|
# - a block argument, on the other hand, is instance
|
14
|
-
#
|
14
|
+
# evaluated during initialization
|
15
15
|
# - consequences
|
16
16
|
# - can only be done in init block
|
17
17
|
# - somewhat subtle difference (from programmer's point of
|
18
|
-
#
|
18
|
+
# view) between a proc and a block
|
19
19
|
# Also note re: Doodle.parent - its value is only valid
|
20
20
|
# during initialization - this is a way to capture that
|
21
|
-
# value for
|
22
|
-
|
21
|
+
# value for use later
|
22
|
+
|
23
23
|
init { doodle.parent }
|
24
24
|
end
|
25
25
|
end
|
@@ -29,7 +29,7 @@ describe Doodle, "doodle_context" do
|
|
29
29
|
end
|
30
30
|
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
it 'should provide a means to find out the current parent of an item in initialization block' do
|
34
34
|
dad = Parent 'Conn' do
|
35
35
|
child 'Sean'
|
data/spec/from_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
2
|
|
3
|
-
describe 'Doodle', '
|
3
|
+
describe 'Doodle', 'from' do
|
4
4
|
temporary_constant :Foo, :Name do
|
5
5
|
before :each do
|
6
6
|
class Name < String
|
@@ -25,7 +25,7 @@ describe 'Doodle', 'applying Doodle type conversions' do
|
|
25
25
|
it 'should convert a value based on conversions in doodle class' do
|
26
26
|
proc { foo = Foo 'Arthur' }.should_not raise_error
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
it 'should convert a value based on conversions in doodle class to the correct class' do
|
30
30
|
foo = Foo 'Arthur'
|
31
31
|
foo.name.class.should_be Name
|
@@ -38,6 +38,46 @@ describe 'Doodle', 'applying Doodle type conversions' do
|
|
38
38
|
it 'should apply validations from doodle type' do
|
39
39
|
proc { Foo 'Art' }.should raise_error(Doodle::ConversionError)
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'Doodle', 'from' do
|
46
|
+
temporary_constant :Answer do
|
47
|
+
before :each do
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should allow specifying from in has params' do
|
51
|
+
class Answer < Doodle
|
52
|
+
has :value, :from => { Integer => proc {|i| i.to_s }}
|
53
|
+
end
|
54
|
+
name = Answer.new(42)
|
55
|
+
name.value.should_be "42"
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should allow specifying from in has params with kind specified' do
|
59
|
+
class Answer < Doodle
|
60
|
+
has :value, :kind => String, :from => { Integer => proc {|i| i.to_s }}
|
61
|
+
end
|
62
|
+
name = Answer.new(42)
|
63
|
+
name.value.should_be "42"
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should override from clause in has params with one defined in block' do
|
67
|
+
class Answer < Doodle
|
68
|
+
has :value, :kind => String, :from => { Integer => proc {|i| i.to_s }} do
|
69
|
+
# this should override :from clause in has params
|
70
|
+
from Float do |i|
|
71
|
+
(Integer(i + 20)).to_s
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
name = Answer.new(22.0)
|
77
|
+
name.value.should_be "42"
|
78
|
+
|
79
|
+
name = Answer.new(42)
|
80
|
+
name.value.should_be "42"
|
81
|
+
end
|
42
82
|
end
|
43
83
|
end
|
data/spec/json_spec.rb
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
require 'doodle/json'
|
3
|
+
|
4
|
+
def compare_json(data, json)
|
5
|
+
JSON.parse(data.to_json, :create_additions => false).should_be JSON.parse(json, :create_additions => false)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe Doodle, 'JSON serialization within a module' do
|
9
|
+
temporary_constants :Container, :Base, :Slideshow, :Layout do
|
10
|
+
before(:each) do
|
11
|
+
@json_source = <<EOT
|
12
|
+
{
|
13
|
+
"json_class":"Container::Slideshow",
|
14
|
+
"data":{
|
15
|
+
"name":"test",
|
16
|
+
"layout":{
|
17
|
+
"json_class":"Container::Layout",
|
18
|
+
"data":{
|
19
|
+
"template":"generic"
|
20
|
+
}
|
21
|
+
},
|
22
|
+
"id":1
|
23
|
+
}
|
24
|
+
}
|
25
|
+
EOT
|
26
|
+
@json_data = JSON.parse(@json_source, :create_additions => false)
|
27
|
+
|
28
|
+
module ::Container
|
29
|
+
class Base < Doodle
|
30
|
+
include Doodle::JSON
|
31
|
+
end
|
32
|
+
class Layout < Base
|
33
|
+
has :template
|
34
|
+
end
|
35
|
+
class Slideshow < Base
|
36
|
+
has :id, :kind => Integer do
|
37
|
+
from String do |s|
|
38
|
+
s.to_i
|
39
|
+
end
|
40
|
+
end
|
41
|
+
has :name, :kind => String
|
42
|
+
has Layout
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
it 'should serialize to json' do
|
47
|
+
slideshow = Container::Slideshow.new do
|
48
|
+
id 1
|
49
|
+
name "test"
|
50
|
+
layout "generic"
|
51
|
+
end
|
52
|
+
compare_json(slideshow, @json_source)
|
53
|
+
end
|
54
|
+
it 'should serialize from json' do
|
55
|
+
slideshow = Container::Slideshow.new do
|
56
|
+
id 1
|
57
|
+
name "test"
|
58
|
+
layout "generic"
|
59
|
+
end
|
60
|
+
ss2 = Doodle.from_json(@json_source)
|
61
|
+
ss2.should_be slideshow
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe Doodle, 'JSON serialization at top level' do
|
67
|
+
temporary_constants :Base, :Slideshow, :Layout do
|
68
|
+
before(:each) do
|
69
|
+
@json_source = <<EOT
|
70
|
+
{
|
71
|
+
"json_class":"Slideshow",
|
72
|
+
"data":{
|
73
|
+
"name":"test",
|
74
|
+
"layout":{
|
75
|
+
"json_class":"Layout",
|
76
|
+
"data":{
|
77
|
+
"template":"generic"
|
78
|
+
}
|
79
|
+
},
|
80
|
+
"id":1
|
81
|
+
}
|
82
|
+
}
|
83
|
+
EOT
|
84
|
+
class ::Base < Doodle
|
85
|
+
include Doodle::JSON
|
86
|
+
end
|
87
|
+
class ::Layout < Base
|
88
|
+
has :template
|
89
|
+
end
|
90
|
+
class ::Slideshow < Base
|
91
|
+
has :id, :kind => Integer do
|
92
|
+
from String do |s|
|
93
|
+
s.to_i
|
94
|
+
end
|
95
|
+
end
|
96
|
+
has :name, :kind => String
|
97
|
+
has Layout
|
98
|
+
end
|
99
|
+
end
|
100
|
+
it 'should serialize to json' do
|
101
|
+
slideshow = ::Slideshow.new do
|
102
|
+
id 1
|
103
|
+
name "test"
|
104
|
+
layout "generic"
|
105
|
+
end
|
106
|
+
compare_json(slideshow, @json_source)
|
107
|
+
end
|
108
|
+
it 'should serialize from json' do
|
109
|
+
slideshow = ::Slideshow.new do
|
110
|
+
id 1
|
111
|
+
name "test"
|
112
|
+
layout "generic"
|
113
|
+
end
|
114
|
+
ss2 = Doodle.from_json(@json_source)
|
115
|
+
ss2.should_be slideshow
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe Doodle, 'JSON' do
|
121
|
+
temporary_constant :Address do
|
122
|
+
before :each do
|
123
|
+
class ::Address < Doodle
|
124
|
+
include Doodle::JSON
|
125
|
+
has :where, :default => "home"
|
126
|
+
has :city
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should not raise an error when supplying attribute values' do
|
131
|
+
proc {
|
132
|
+
Address do
|
133
|
+
city "London"
|
134
|
+
end
|
135
|
+
}.should_not raise_error
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should accept attributes defined in block' do
|
139
|
+
a = Address do
|
140
|
+
city "London"
|
141
|
+
end
|
142
|
+
a.city.should_be "London"
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'should output non-doodle attributes as JSON attributes' do
|
146
|
+
a = Address do
|
147
|
+
city "London"
|
148
|
+
end
|
149
|
+
compare_json(a, <<EOT)
|
150
|
+
{
|
151
|
+
"json_class":"Address",
|
152
|
+
"data":{
|
153
|
+
"city":"London"
|
154
|
+
}
|
155
|
+
}
|
156
|
+
EOT
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe Doodle, 'JSON' do
|
162
|
+
temporary_constant :Base, :City, :Address do
|
163
|
+
before :each do
|
164
|
+
class ::Base < Doodle
|
165
|
+
include Doodle::JSON
|
166
|
+
end
|
167
|
+
class ::City < Base
|
168
|
+
has :_text_
|
169
|
+
has :country, :default => "UK"
|
170
|
+
end
|
171
|
+
class ::Address < Base
|
172
|
+
has :where, :default => "home"
|
173
|
+
has City
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'should output required tags in JSON' do
|
178
|
+
a = Address do
|
179
|
+
city "London"
|
180
|
+
end
|
181
|
+
compare_json(a, <<EOT)
|
182
|
+
{
|
183
|
+
"json_class":"Address",
|
184
|
+
"data":{
|
185
|
+
"city":{
|
186
|
+
"json_class":"City",
|
187
|
+
"data":{"_text_":"London"}
|
188
|
+
}
|
189
|
+
}
|
190
|
+
}
|
191
|
+
EOT
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'should output specified optional attributes as json attributes if kind not a doodle class' do
|
195
|
+
a = Address :where => 'home' do
|
196
|
+
city "London"
|
197
|
+
end
|
198
|
+
compare_json(a, <<EOT)
|
199
|
+
{
|
200
|
+
"json_class":"Address",
|
201
|
+
"data":{
|
202
|
+
"city":{
|
203
|
+
"json_class":"City",
|
204
|
+
"data":{"_text_":"London"}
|
205
|
+
},
|
206
|
+
"where":"home"
|
207
|
+
}
|
208
|
+
}
|
209
|
+
EOT
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'should output specified optional attributes' do
|
213
|
+
a = Address :where => 'home' do
|
214
|
+
city "London", :country => "England" do
|
215
|
+
country "UK"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
compare_json(a, <<EOT)
|
219
|
+
{
|
220
|
+
"json_class":"Address",
|
221
|
+
"data":{
|
222
|
+
"city":{"json_class":"City", "data":{"_text_":"London", "country":"UK"}},
|
223
|
+
"where":"home"
|
224
|
+
}
|
225
|
+
}
|
226
|
+
EOT
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
|
data/spec/member_init_spec.rb
CHANGED
@@ -13,16 +13,16 @@ describe 'Doodle', 'initialization of scalar attributes from hash' do
|
|
13
13
|
has :v2, :kind => String, :default => "bar"
|
14
14
|
end
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
it 'should initialize an attribute from a hash' do
|
18
18
|
foo = Foo do
|
19
|
-
bar :name => "hello", :count => 1
|
19
|
+
bar :name => "hello", :count => 1
|
20
20
|
end
|
21
21
|
foo.bar.name.should_be "hello"
|
22
22
|
foo.bar.count.should_be 1
|
23
23
|
end
|
24
24
|
it 'should fail trying to initialize with incorrect keyword values' do
|
25
|
-
proc {
|
25
|
+
proc {
|
26
26
|
foo = Foo do
|
27
27
|
bar :name => 1, :count => "hello"
|
28
28
|
end
|
@@ -30,7 +30,7 @@ describe 'Doodle', 'initialization of scalar attributes from hash' do
|
|
30
30
|
end
|
31
31
|
it 'should work with positional args' do
|
32
32
|
foo = nil
|
33
|
-
proc {
|
33
|
+
proc {
|
34
34
|
foo = Foo do
|
35
35
|
bar "hello", 1
|
36
36
|
end
|
@@ -40,7 +40,7 @@ describe 'Doodle', 'initialization of scalar attributes from hash' do
|
|
40
40
|
end
|
41
41
|
it 'should work with block initialization' do
|
42
42
|
foo = nil
|
43
|
-
proc {
|
43
|
+
proc {
|
44
44
|
foo = Foo do
|
45
45
|
bar do
|
46
46
|
name "hello"
|
@@ -53,7 +53,7 @@ describe 'Doodle', 'initialization of scalar attributes from hash' do
|
|
53
53
|
end
|
54
54
|
it 'should work with arg and block initialization' do
|
55
55
|
foo = nil
|
56
|
-
proc {
|
56
|
+
proc {
|
57
57
|
foo = Foo do
|
58
58
|
bar "hello" do
|
59
59
|
count 1
|
@@ -65,7 +65,7 @@ describe 'Doodle', 'initialization of scalar attributes from hash' do
|
|
65
65
|
end
|
66
66
|
it 'should work with keyword and block initialization' do
|
67
67
|
foo = nil
|
68
|
-
proc {
|
68
|
+
proc {
|
69
69
|
foo = Foo do
|
70
70
|
bar :name => "hello" do
|
71
71
|
count 1
|
@@ -77,7 +77,7 @@ describe 'Doodle', 'initialization of scalar attributes from hash' do
|
|
77
77
|
end
|
78
78
|
it 'should raise error with invalid keyword and block initialization' do
|
79
79
|
foo = nil
|
80
|
-
proc {
|
80
|
+
proc {
|
81
81
|
foo = Foo do
|
82
82
|
bar :name => 1 do
|
83
83
|
count "hello"
|
@@ -87,7 +87,7 @@ describe 'Doodle', 'initialization of scalar attributes from hash' do
|
|
87
87
|
end
|
88
88
|
it 'should raise error with keyword and invalid block initialization' do
|
89
89
|
foo = nil
|
90
|
-
proc {
|
90
|
+
proc {
|
91
91
|
foo = Foo do
|
92
92
|
bar :name => "hello" do
|
93
93
|
count "hello"
|
@@ -97,7 +97,7 @@ describe 'Doodle', 'initialization of scalar attributes from hash' do
|
|
97
97
|
end
|
98
98
|
it 'should initialize non-Doodle or Proc with simple value' do
|
99
99
|
foo = nil
|
100
|
-
proc {
|
100
|
+
proc {
|
101
101
|
foo = Foo do
|
102
102
|
bar :name => "hello", :count => 1
|
103
103
|
v2 "Hello"
|
@@ -108,7 +108,7 @@ describe 'Doodle', 'initialization of scalar attributes from hash' do
|
|
108
108
|
foo.v2.should_be "Hello"
|
109
109
|
end
|
110
110
|
it 'should fail trying to initialize an inappropriate attribute (not a Doodle or Proc) from a block' do
|
111
|
-
proc {
|
111
|
+
proc {
|
112
112
|
foo = Foo do
|
113
113
|
bar :name => "hello", :count => 1
|
114
114
|
v2 do
|
data/spec/modules_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
2
|
|
3
|
-
describe Doodle, "
|
3
|
+
describe Doodle, "definitions within rspec" do
|
4
4
|
temporary_constant :Foo1 do
|
5
5
|
before :each do
|
6
6
|
class Foo1 < Doodle
|
@@ -13,7 +13,7 @@ describe Doodle, "Definitions within rspec" do
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
describe Doodle, "
|
16
|
+
describe Doodle, "definitions at top level" do
|
17
17
|
temporary_constant :Foo2 do
|
18
18
|
before :each do
|
19
19
|
class ::Object
|
@@ -28,7 +28,7 @@ describe Doodle, "Definitions at top level" do
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
describe Doodle, "
|
31
|
+
describe Doodle, "definitions in modules" do
|
32
32
|
temporary_constant :Foo3, :Bar3 do
|
33
33
|
before :each do
|
34
34
|
module ::Bar3
|
@@ -43,7 +43,7 @@ describe Doodle, "Definitions in modules" do
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
describe Doodle, "
|
46
|
+
describe Doodle, "definitions in module_eval" do
|
47
47
|
temporary_constant :Foo4, :Bar4 do
|
48
48
|
before :each do
|
49
49
|
module Bar4
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe Doodle, 'multiple collector' do
|
4
|
+
temporary_constants :Text, :Item, :List do
|
5
|
+
before :each do
|
6
|
+
#: definition
|
7
|
+
class ::Item < Doodle
|
8
|
+
has :name, :kind => String
|
9
|
+
end
|
10
|
+
class ::Text < Doodle
|
11
|
+
has :body, :kind => String
|
12
|
+
end
|
13
|
+
class ::List < Doodle
|
14
|
+
has :items, :collect => [Item, Text]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should accept convertible values in collector' do
|
19
|
+
list = nil
|
20
|
+
no_error {
|
21
|
+
list = List do
|
22
|
+
item "Hello"
|
23
|
+
text "World"
|
24
|
+
end
|
25
|
+
}
|
26
|
+
list.items.size.should_be 2
|
27
|
+
list.items[0].should_be Item("Hello")
|
28
|
+
list.items[1].should_be Text("World")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe Doodle, 'multiple collector' do
|
34
|
+
temporary_constants :Text, :Item, :List do
|
35
|
+
before :each do
|
36
|
+
#: definition
|
37
|
+
class ::Item < Doodle
|
38
|
+
has :name, :kind => String
|
39
|
+
end
|
40
|
+
class ::Text < Doodle
|
41
|
+
has :body, :kind => String
|
42
|
+
end
|
43
|
+
class ::List < Doodle
|
44
|
+
has :items, :collect => [ { :foo => Item }, { :bar => Text } ]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should accept convertible values in collector using specified collector methods' do
|
49
|
+
list = nil
|
50
|
+
no_error {
|
51
|
+
list = List do
|
52
|
+
foo "Hello"
|
53
|
+
bar "World"
|
54
|
+
end
|
55
|
+
}
|
56
|
+
list.items.size.should_be 2
|
57
|
+
list.items[0].should_be Item("Hello")
|
58
|
+
list.items[1].should_be Text("World")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe Doodle, 'multiple collector' do
|
64
|
+
temporary_constants :Text, :Item, :List do
|
65
|
+
before :each do
|
66
|
+
#: definition
|
67
|
+
class ::Item < Doodle
|
68
|
+
has :name, :kind => String
|
69
|
+
end
|
70
|
+
class ::Text < Doodle
|
71
|
+
has :body, :kind => String
|
72
|
+
end
|
73
|
+
class ::List < Doodle
|
74
|
+
has :items, :collect => { :foo => Item, :bar => Text }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should accept convertible values in collector using specified collector methods' do
|
79
|
+
list = nil
|
80
|
+
no_error {
|
81
|
+
list = List do
|
82
|
+
foo "Hello"
|
83
|
+
bar "World"
|
84
|
+
end
|
85
|
+
}
|
86
|
+
list.items.size.should_be 2
|
87
|
+
list.items[0].should_be Item("Hello")
|
88
|
+
list.items[1].should_be Text("World")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|