doodle 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|