doodle 0.1.3 → 0.1.4
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.
- data/COPYING +18 -0
- data/History.txt +9 -0
- data/Manifest.txt +16 -12
- data/PostInstall.txt +1 -0
- data/lib/doodle.rb +166 -86
- data/lib/doodle/datatypes.rb +19 -6
- data/lib/doodle/rfc822.rb +22 -15
- data/lib/doodle/version.rb +1 -1
- data/spec/arg_order_spec.rb +11 -11
- data/spec/attributes_spec.rb +8 -8
- data/spec/bugs_spec.rb +12 -12
- data/spec/class_spec.rb +21 -21
- data/spec/collector_spec.rb +87 -11
- data/spec/defaults_spec.rb +21 -21
- data/spec/doodle_context_spec.rb +2 -2
- data/spec/doodle_spec.rb +86 -70
- data/spec/factory_spec.rb +8 -8
- data/spec/inheritance_spec.rb +74 -0
- data/spec/new_doodle_spec.rb +3 -3
- data/spec/singleton_spec.rb +16 -16
- data/spec/spec_helper.rb +10 -0
- data/spec/specialized_attribute_class_spec.rb +111 -0
- data/spec/superclass_spec.rb +4 -4
- data/spec/validation_spec.rb +8 -8
- data/tasks/deployment.rake +5 -5
- metadata +21 -14
- data/tasks/website.rake +0 -17
data/lib/doodle/datatypes.rb
CHANGED
@@ -57,6 +57,24 @@ class Doodle
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
+
def boolean(name, params = { }, &block)
|
61
|
+
define name, params, block, { } do
|
62
|
+
must "be true or false" do |v|
|
63
|
+
[true, false].include?(v)
|
64
|
+
end
|
65
|
+
from String, Symbol do |v|
|
66
|
+
case v.to_s
|
67
|
+
when /^(yes|true|on)$/
|
68
|
+
true
|
69
|
+
when /^(no|false|off)$/
|
70
|
+
false
|
71
|
+
else
|
72
|
+
v
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
60
78
|
def symbol(name, params = { }, &block)
|
61
79
|
define name, params, block, { :kind => Symbol } do
|
62
80
|
from String do |s|
|
@@ -112,12 +130,7 @@ class Doodle
|
|
112
130
|
# 384 = 128+1+255
|
113
131
|
string(name, { :max => 384 }.merge(params), &block).instance_eval do
|
114
132
|
must "be valid email address" do |s|
|
115
|
-
|
116
|
-
# the regex fails in 1.9 with illegal utf byte sequence error
|
117
|
-
s =~ /\A.*@.*\z/
|
118
|
-
else
|
119
|
-
s =~ RFC822::EmailAddress
|
120
|
-
end
|
133
|
+
s =~ RFC822::EmailAddress
|
121
134
|
end
|
122
135
|
end
|
123
136
|
end
|
data/lib/doodle/rfc822.rb
CHANGED
@@ -12,20 +12,27 @@
|
|
12
12
|
# http://creativecommons.org/licenses/by-sa/2.5/
|
13
13
|
#
|
14
14
|
module RFC822
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
15
|
+
# TODO: fix the illegal multibyte sequence in 1.9
|
16
|
+
# the regex fails in 1.9 with illegal utf byte sequence error
|
17
|
+
if RUBY_VERSION < '1.9.0'
|
18
|
+
EmailAddress = begin
|
19
|
+
qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]'
|
20
|
+
dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]'
|
21
|
+
atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-' +
|
22
|
+
'\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+'
|
23
|
+
quoted_pair = '\\x5c[\\x00-\\x7f]'
|
24
|
+
domain_literal = "\\x5b(?:#{dtext}|#{quoted_pair})*\\x5d"
|
25
|
+
quoted_string = "\\x22(?:#{qtext}|#{quoted_pair})*\\x22"
|
26
|
+
domain_ref = atom
|
27
|
+
sub_domain = "(?:#{domain_ref}|#{domain_literal})"
|
28
|
+
word = "(?:#{atom}|#{quoted_string})"
|
29
|
+
domain = "#{sub_domain}(?:\\x2e#{sub_domain})*"
|
30
|
+
local_part = "#{word}(?:\\x2e#{word})*"
|
31
|
+
addr_spec = "#{local_part}\\x40#{domain}"
|
32
|
+
pattern = /\A#{addr_spec}\z/
|
33
|
+
end
|
34
|
+
else
|
35
|
+
# minimal regex until I sort out the problem above
|
36
|
+
EmailAddress = /\A.*@.*\z/
|
30
37
|
end
|
31
38
|
end
|
data/lib/doodle/version.rb
CHANGED
data/spec/arg_order_spec.rb
CHANGED
@@ -12,9 +12,9 @@ describe 'arg_order' do
|
|
12
12
|
end
|
13
13
|
it 'should specify order of positional arguments' do
|
14
14
|
foo = Foo.new 1, 2, 3
|
15
|
-
foo.value.
|
16
|
-
foo.name.
|
17
|
-
foo.extra.
|
15
|
+
foo.value.should_be 1
|
16
|
+
foo.name.should_be 2
|
17
|
+
foo.extra.should_be 3
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'should allow only symbols as arguments to arg_order' do
|
@@ -42,8 +42,8 @@ describe 'arg_order' do
|
|
42
42
|
end
|
43
43
|
it 'should specify order of positional arguments' do
|
44
44
|
f = Bar.new 1, 2
|
45
|
-
f.name.
|
46
|
-
f.value.
|
45
|
+
f.name.should_be 1
|
46
|
+
f.value.should_be 2
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
@@ -61,8 +61,8 @@ describe 'arg_order' do
|
|
61
61
|
end
|
62
62
|
it 'should specify order of positional arguments' do
|
63
63
|
f = Bar.new 1, 2
|
64
|
-
f.value.
|
65
|
-
f.name.
|
64
|
+
f.value.should_be 1
|
65
|
+
f.name.should_be 2
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
@@ -81,8 +81,8 @@ describe 'arg_order' do
|
|
81
81
|
|
82
82
|
it 'should specify order of positional arguments' do
|
83
83
|
f = Bar.new 1
|
84
|
-
f.value.
|
85
|
-
f.name.
|
84
|
+
f.value.should_be 1
|
85
|
+
f.name.should_be "bar"
|
86
86
|
end
|
87
87
|
end
|
88
88
|
end
|
@@ -101,8 +101,8 @@ describe 'arg_order' do
|
|
101
101
|
|
102
102
|
it 'should specify order of positional arguments' do
|
103
103
|
f = Bar.new 1, "bar"
|
104
|
-
f.value.
|
105
|
-
f.name.
|
104
|
+
f.value.should_be 1
|
105
|
+
f.name.should_be "bar"
|
106
106
|
end
|
107
107
|
end
|
108
108
|
end
|
data/spec/attributes_spec.rb
CHANGED
@@ -64,10 +64,10 @@ describe Doodle::Attribute, 'basics' do
|
|
64
64
|
@bar.attributes[:ivar2].optional?.should == false
|
65
65
|
end
|
66
66
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
67
|
+
# it "should have parents in correct order" do
|
68
|
+
# expected_parents = RUBY_VERSION <= "1.8.6" ? [Foo, Object] : [Foo, Object, BasicObject]
|
69
|
+
# Bar.parents.should == expected_parents
|
70
|
+
# end
|
71
71
|
|
72
72
|
it "should have Bar's singleton parents in reverse order of definition" do
|
73
73
|
@bar.singleton_class.parents.should == []
|
@@ -128,10 +128,10 @@ describe Doodle::Attribute, 'attribute order' do
|
|
128
128
|
end
|
129
129
|
end
|
130
130
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
131
|
+
# it 'should keep order of inherited attributes' do
|
132
|
+
# expected_parents = RUBY_VERSION <= "1.8.6" ? [B, A, Doodle, Object] : [B, A, Doodle, Object, BasicObject]
|
133
|
+
# C.parents.should == expected_parents
|
134
|
+
# end
|
135
135
|
|
136
136
|
it 'should keep order of inherited attributes' do
|
137
137
|
C.attributes.keys.should == [:a, :b, :c]
|
data/spec/bugs_spec.rb
CHANGED
@@ -15,8 +15,8 @@ describe 'Doodle', 'parents' do
|
|
15
15
|
|
16
16
|
it 'should not duplicate validations when accessing them!' do
|
17
17
|
foo = Foo 2
|
18
|
-
foo.validations.size.
|
19
|
-
foo.validations.size.
|
18
|
+
foo.validations.size.should_be 1
|
19
|
+
foo.validations.size.should_be 1
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -48,8 +48,8 @@ describe 'Doodle', ' loading good data from yaml' do
|
|
48
48
|
|
49
49
|
it 'should apply conversions' do
|
50
50
|
foo = YAML::load(@str).validate!
|
51
|
-
foo.date.
|
52
|
-
foo.date.class.
|
51
|
+
foo.date.should_be Date.new(2000, 7, 1)
|
52
|
+
foo.date.class.should_be Date
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
@@ -124,7 +124,7 @@ describe Doodle, 'initializing from hashes and yaml' do
|
|
124
124
|
yaml = person.to_yaml
|
125
125
|
# be careful here - Ruby yaml is finicky (spaces after class names)
|
126
126
|
yaml = yaml.gsub(/\s*\n/m, "\n")
|
127
|
-
yaml.
|
127
|
+
yaml.should_be %[--- !ruby/object:Person
|
128
128
|
address:
|
129
129
|
- !ruby/object:AddressLine
|
130
130
|
text: Henry Wood House
|
@@ -134,7 +134,7 @@ name: Sean
|
|
134
134
|
]
|
135
135
|
person = YAML.load(yaml)
|
136
136
|
proc { person.validate! }.should_not raise_error
|
137
|
-
person.address.all?{ |x| x.kind_of? AddressLine }.
|
137
|
+
person.address.all?{ |x| x.kind_of? AddressLine }.should_be true
|
138
138
|
|
139
139
|
end
|
140
140
|
end
|
@@ -167,7 +167,7 @@ describe 'Doodle', 'hiding @__doodle__' do
|
|
167
167
|
end
|
168
168
|
it 'should not include @__doodle__ in instance_variables' do
|
169
169
|
foo = Foo 2
|
170
|
-
foo.instance_variables.size.
|
170
|
+
foo.instance_variables.size.should_be 1
|
171
171
|
foo.instance_variables.first.should =~ /^@var1$/
|
172
172
|
end
|
173
173
|
it 'should not reveal @__doodle__ in inspect string' do
|
@@ -176,7 +176,7 @@ describe 'Doodle', 'hiding @__doodle__' do
|
|
176
176
|
end
|
177
177
|
it 'should not include @__doodle__ in instance_variables' do
|
178
178
|
foo = Bar 2
|
179
|
-
foo.instance_variables.size.
|
179
|
+
foo.instance_variables.size.should_be 1
|
180
180
|
foo.instance_variables.first.should =~ /^@var2$/
|
181
181
|
end
|
182
182
|
it 'should correctly inspect when using included module' do
|
@@ -185,17 +185,17 @@ describe 'Doodle', 'hiding @__doodle__' do
|
|
185
185
|
end
|
186
186
|
it 'should correctly inspect string' do
|
187
187
|
foo = DString("Hello")
|
188
|
-
foo.inspect.
|
188
|
+
foo.inspect.should_be '"Hello"'
|
189
189
|
end
|
190
190
|
it 'should correctly inspect hash' do
|
191
191
|
foo = DHash.new(2)
|
192
192
|
foo[:a] = 1
|
193
|
-
foo.inspect.
|
194
|
-
foo[:b].
|
193
|
+
foo.inspect.should_be '{:a=>1}'
|
194
|
+
foo[:b].should_be 2
|
195
195
|
end
|
196
196
|
it 'should correctly inspect array' do
|
197
197
|
foo = DArray(3, 2)
|
198
|
-
foo.inspect.
|
198
|
+
foo.inspect.should_be '[2, 2, 2]'
|
199
199
|
end
|
200
200
|
end
|
201
201
|
end
|
data/spec/class_spec.rb
CHANGED
@@ -22,65 +22,65 @@ describe Doodle, 'class attributes' do
|
|
22
22
|
|
23
23
|
it 'should create class attribute' do
|
24
24
|
Foo.metadata = 'Foo metadata'
|
25
|
-
Foo.metadata.
|
25
|
+
Foo.metadata.should_be 'Foo metadata'
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'should access @foo class attribute via self.class' do
|
29
29
|
@foo.class.metadata = '@foo metadata'
|
30
|
-
@foo.class.metadata.
|
31
|
-
Foo.metadata.
|
30
|
+
@foo.class.metadata.should_be '@foo metadata'
|
31
|
+
Foo.metadata.should_be '@foo metadata'
|
32
32
|
|
33
33
|
Foo.metadata = 'Foo metadata'
|
34
|
-
Foo.metadata.
|
35
|
-
@foo.class.metadata.
|
34
|
+
Foo.metadata.should_be 'Foo metadata'
|
35
|
+
@foo.class.metadata.should_be 'Foo metadata'
|
36
36
|
end
|
37
37
|
|
38
38
|
it "should list all class's own attributes" do
|
39
|
-
Foo.singleton_class.attributes(false).keys.
|
39
|
+
Foo.singleton_class.attributes(false).keys.should_be [:metadata]
|
40
40
|
end
|
41
41
|
|
42
42
|
it "should list all class's own attributes" do
|
43
|
-
Foo.singleton_class.attributes.keys.
|
43
|
+
Foo.singleton_class.attributes.keys.should_be [:metadata]
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'should create Bar class attribute' do
|
47
47
|
Bar.metadata = 'Bar metadata'
|
48
|
-
Bar.metadata.
|
48
|
+
Bar.metadata.should_be 'Bar metadata'
|
49
49
|
end
|
50
50
|
|
51
51
|
it 'should access @bar class attribute via self.class' do
|
52
52
|
@bar.class.metadata = '@bar metadata'
|
53
|
-
@bar.class.metadata.
|
54
|
-
Bar.metadata.
|
53
|
+
@bar.class.metadata.should_be '@bar metadata'
|
54
|
+
Bar.metadata.should_be '@bar metadata'
|
55
55
|
|
56
56
|
Bar.metadata = 'Bar metadata'
|
57
|
-
Bar.metadata.
|
58
|
-
@bar.class.metadata.
|
57
|
+
Bar.metadata.should_be 'Bar metadata'
|
58
|
+
@bar.class.metadata.should_be 'Bar metadata'
|
59
59
|
end
|
60
60
|
|
61
61
|
it 'should not allow inherited class attributes to interfere with each other' do
|
62
62
|
Foo.metadata = 'Foo metadata'
|
63
63
|
@bar.class.metadata = '@bar metadata'
|
64
|
-
@bar.class.metadata.
|
65
|
-
Bar.metadata.
|
64
|
+
@bar.class.metadata.should_be '@bar metadata'
|
65
|
+
Bar.metadata.should_be '@bar metadata'
|
66
66
|
|
67
67
|
Bar.metadata = 'Bar metadata'
|
68
|
-
Bar.metadata.
|
69
|
-
@bar.class.metadata.
|
68
|
+
Bar.metadata.should_be 'Bar metadata'
|
69
|
+
@bar.class.metadata.should_be 'Bar metadata'
|
70
70
|
|
71
|
-
Foo.metadata.
|
72
|
-
@foo.class.metadata.
|
71
|
+
Foo.metadata.should_be 'Foo metadata'
|
72
|
+
@foo.class.metadata.should_be 'Foo metadata'
|
73
73
|
end
|
74
74
|
|
75
75
|
it "should list all class's own attributes" do
|
76
|
-
Bar.singleton_class.attributes(false).keys.
|
76
|
+
Bar.singleton_class.attributes(false).keys.should_be [:doc]
|
77
77
|
end
|
78
78
|
|
79
79
|
it "should list all class's singleton attributes" do
|
80
|
-
Bar.singleton_class.attributes.keys.
|
80
|
+
Bar.singleton_class.attributes.keys.should_be [:doc]
|
81
81
|
end
|
82
82
|
it "should list all class's class_attributes" do
|
83
|
-
Bar.class_attributes.keys.
|
83
|
+
Bar.class_attributes.keys.should_be [:metadata, :doc]
|
84
84
|
end
|
85
85
|
end
|
86
86
|
end
|
data/spec/collector_spec.rb
CHANGED
@@ -16,11 +16,11 @@ describe Doodle, "Simple collector" do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
it "should define a collector method :item" do
|
19
|
-
@foo.methods.map{ |x| x.to_sym }.include?(:item).
|
19
|
+
@foo.methods.map{ |x| x.to_sym }.include?(:item).should_be true
|
20
20
|
end
|
21
21
|
|
22
22
|
it "should collect items into attribute :list" do
|
23
|
-
@foo.list.
|
23
|
+
@foo.list.should_be ["Hello", "World"]
|
24
24
|
end
|
25
25
|
|
26
26
|
end
|
@@ -37,7 +37,11 @@ describe Doodle, "Typed collector with default collector name" do
|
|
37
37
|
end
|
38
38
|
@event = Event do
|
39
39
|
location "Stage 1"
|
40
|
-
|
40
|
+
# todo: move this into spec
|
41
|
+
# should handle collected arguments with block only
|
42
|
+
location do
|
43
|
+
name "Stage 2"
|
44
|
+
end
|
41
45
|
end
|
42
46
|
end
|
43
47
|
after :each do
|
@@ -45,11 +49,11 @@ describe Doodle, "Typed collector with default collector name" do
|
|
45
49
|
end
|
46
50
|
|
47
51
|
it "should define a collector method :location" do
|
48
|
-
@event.methods.map{ |x| x.to_sym }.include?(:location).
|
52
|
+
@event.methods.map{ |x| x.to_sym }.include?(:location).should_be true
|
49
53
|
end
|
50
54
|
|
51
55
|
it "should collect items into attribute :list" do
|
52
|
-
@event.locations.map{|loc| loc.name}.
|
56
|
+
@event.locations.map{|loc| loc.name}.should_be ["Stage 1", "Stage 2"]
|
53
57
|
end
|
54
58
|
|
55
59
|
end
|
@@ -66,7 +70,7 @@ describe Doodle, "Typed collector with specified collector name" do
|
|
66
70
|
end
|
67
71
|
end
|
68
72
|
it "should define a collector method :place" do
|
69
|
-
Event.instance_methods.map{ |x| x.to_sym}.include?(:place).
|
73
|
+
Event.instance_methods.map{ |x| x.to_sym}.include?(:place).should_be true
|
70
74
|
end
|
71
75
|
end
|
72
76
|
end
|
@@ -89,8 +93,8 @@ describe Doodle, "typed collector with specified collector name" do
|
|
89
93
|
place "Stage 2"
|
90
94
|
end
|
91
95
|
}.should_not raise_error
|
92
|
-
event.locations.map{|loc| loc.name}.
|
93
|
-
event.locations.map{|loc| loc.class}.
|
96
|
+
event.locations.map{|loc| loc.name}.should_be ["Stage 1", "Stage 2"]
|
97
|
+
event.locations.map{|loc| loc.class}.should_be [Location, Location]
|
94
98
|
end
|
95
99
|
end
|
96
100
|
end
|
@@ -122,10 +126,82 @@ describe Doodle, "typed collector with specified collector name initialized from
|
|
122
126
|
proc {
|
123
127
|
event = Event(data)
|
124
128
|
}.should_not raise_error
|
125
|
-
event.locations.map{|loc| loc.name}.
|
126
|
-
event.locations.map{|loc| loc.class}.
|
127
|
-
event.locations[0].events[0].kind_of?(Event).
|
129
|
+
event.locations.map{|loc| loc.name}.should_be ["Stage 1", "Stage 2"]
|
130
|
+
event.locations.map{|loc| loc.class}.should_be [Location, Location]
|
131
|
+
event.locations[0].events[0].kind_of?(Event).should_be true
|
128
132
|
end
|
129
133
|
end
|
130
134
|
end
|
131
135
|
|
136
|
+
describe Doodle, "Simple keyed collector" do
|
137
|
+
temporary_constant :Foo do
|
138
|
+
before :each do
|
139
|
+
class Foo < Doodle
|
140
|
+
has :list, :collect => :item, :key => :size
|
141
|
+
end
|
142
|
+
@foo = Foo do
|
143
|
+
item "Hello"
|
144
|
+
item "World"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
after :each do
|
148
|
+
remove_ivars :foo
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should define a collector method :item" do
|
152
|
+
@foo.methods.map{ |x| x.to_sym }.include?(:item).should_be true
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should collect items into attribute :list" do
|
156
|
+
@foo.list.should_be( { 5 => "World" } )
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe Doodle, "Simple keyed collector #2" do
|
163
|
+
temporary_constant :Foo, :Item do
|
164
|
+
before :each do
|
165
|
+
class Item < Doodle
|
166
|
+
has :name
|
167
|
+
end
|
168
|
+
class Foo < Doodle
|
169
|
+
has :list, :collect => Item, :key => :name
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should define a collector method :item" do
|
174
|
+
foo = Foo.new
|
175
|
+
foo.methods.map{ |x| x.to_sym }.include?(:item).should_be true
|
176
|
+
foo.respond_to?(:item).should_be true
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should collect items into attribute :list #1" do
|
180
|
+
foo = Foo do
|
181
|
+
item "Hello"
|
182
|
+
item "World"
|
183
|
+
end
|
184
|
+
foo.list.to_a.map{ |k, v| [k, v.class, v.name] }.should_be( [["Hello", Item, "Hello"], ["World", Item, "World"]] )
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should collect keyword argument enumerable into attribute :list" do
|
188
|
+
foo = Foo(:list =>
|
189
|
+
[
|
190
|
+
{ :name => "Hello" },
|
191
|
+
{ :name => "World" }
|
192
|
+
]
|
193
|
+
)
|
194
|
+
foo.list.to_a.map{ |k, v| [k, v.class, v.name] }.should_be( [["Hello", Item, "Hello"], ["World", Item, "World"]] )
|
195
|
+
end
|
196
|
+
|
197
|
+
it "should collect positional argument enumerable into attribute :list" do
|
198
|
+
foo = Foo([
|
199
|
+
{ :name => "Hello" },
|
200
|
+
{ :name => "World" }
|
201
|
+
]
|
202
|
+
)
|
203
|
+
foo.list.to_a.map{ |k, v| [k, v.class, v.name] }.should_be( [["Hello", Item, "Hello"], ["World", Item, "World"]] )
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
end
|