doodle 0.1.8 → 0.1.9

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.
@@ -2,7 +2,7 @@ class Doodle #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
- TINY = 8
5
+ TINY = 9
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -3,227 +3,164 @@
3
3
  #
4
4
  # DESCRIPTION
5
5
  # Hash with preserved order and some array-like extensions
6
- # Public domain.
6
+ # Public domain.
7
7
  #
8
8
  # THANKS
9
9
  # Andrew Johnson for his suggestions and fixes of Hash[],
10
10
  # merge, to_a, inspect and shift
11
- class OrderedHash < ::Hash
12
- #--{{{
11
+ class Doodle
12
+ class OrderedHash < ::Hash
13
13
  attr_accessor :order
14
14
 
15
15
  class << self
16
- #--{{{
17
- def [] *args
18
- #--{{{
19
- hsh = OrderedHash.new
20
- if Hash === args[0]
21
- hsh.replace args[0]
22
- elsif (args.size % 2) != 0
23
- raise ArgumentError, "odd number of elements for Hash"
24
- else
25
- hsh[args.shift] = args.shift while args.size > 0
26
- end
27
- hsh
28
- #--}}}
16
+ def [](*args)
17
+ hsh = OrderedHash.new
18
+ if Hash === args[0]
19
+ hsh.replace args[0]
20
+ elsif (args.size % 2) != 0
21
+ raise ArgumentError, "odd number of elements for Hash"
22
+ else
23
+ hsh[args.shift] = args.shift while args.size > 0
29
24
  end
30
- #--}}}
25
+ hsh
26
+ end
31
27
  end
32
- # def initialize
33
- ##--{{{
34
- # @order = []
35
- ##--}}}
36
- # end
37
28
  def initialize(*a, &b)
38
- #--{{{
39
29
  super
40
30
  @order = []
41
- #--}}}
42
31
  end
43
- def store_only a,b
44
- #--{{{
45
- store a,b
46
- #--}}}
32
+ def store_only(a,b)
33
+ store a,b
47
34
  end
48
- alias orig_store store
49
- def store a,b
50
- #--{{{
51
- @order.push a unless has_key? a
52
- super a,b
53
- #--}}}
35
+ alias orig_store store
36
+ def store(a,b)
37
+ @order.push a unless has_key? a
38
+ super a,b
54
39
  end
55
40
  alias []= store
56
- def == hsh2
57
- #--{{{
58
- return false if @order != hsh2.order
59
- super hsh2
60
- #--}}}
41
+ def ==(hsh2)
42
+ return false if @order != hsh2.order
43
+ super hsh2
61
44
  end
62
45
  def clear
63
- #--{{{
64
- @order = []
65
- super
66
- #--}}}
46
+ @order = []
47
+ super
67
48
  end
68
- def delete key
69
- #--{{{
70
- @order.delete key
71
- super
72
- #--}}}
49
+ def delete(key)
50
+ @order.delete key
51
+ super
73
52
  end
74
53
  def each_key
75
- #--{{{
76
- @order.each { |k| yield k }
77
- self
78
- #--}}}
54
+ @order.each { |k| yield k }
55
+ self
79
56
  end
80
57
  def each_value
81
- #--{{{
82
- @order.each { |k| yield self[k] }
83
- self
84
- #--}}}
58
+ @order.each { |k| yield self[k] }
59
+ self
85
60
  end
86
61
  def each
87
- #--{{{
88
- @order.each { |k| yield k,self[k] }
89
- self
90
- #--}}}
62
+ @order.each { |k| yield k,self[k] }
63
+ self
91
64
  end
92
- alias each_pair each
65
+ alias each_pair each
93
66
  def delete_if
94
- #--{{{
95
- @order.clone.each { |k|
96
- delete k if yield
97
- }
98
- self
99
- #--}}}
67
+ @order.clone.each { |k|
68
+ delete k if yield
69
+ }
70
+ self
100
71
  end
101
72
  def values
102
- #--{{{
103
- ary = []
104
- @order.each { |k| ary.push self[k] }
105
- ary
106
- #--}}}
73
+ ary = []
74
+ @order.each { |k| ary.push self[k] }
75
+ ary
107
76
  end
108
77
  def keys
109
- #--{{{
110
- @order
111
- #--}}}
78
+ @order
112
79
  end
113
80
  def invert
114
- #--{{{
115
- hsh2 = Hash.new
116
- @order.each { |k| hsh2[self[k]] = k }
117
- hsh2
118
- #--}}}
119
- end
120
- def reject &block
121
- #--{{{
122
- self.dup.delete_if(&block)
123
- #--}}}
124
- end
125
- def reject! &block
126
- #--{{{
127
- hsh2 = reject(&block)
128
- self == hsh2 ? nil : hsh2
129
- #--}}}
130
- end
131
- def replace hsh2
132
- #--{{{
133
- @order = hsh2.keys
134
- super hsh2
135
- #--}}}
81
+ hsh2 = Hash.new
82
+ @order.each { |k| hsh2[self[k]] = k }
83
+ hsh2
84
+ end
85
+ def reject(&block)
86
+ self.dup.delete_if(&block)
87
+ end
88
+ def reject!(&block)
89
+ hsh2 = reject(&block)
90
+ self == hsh2 ? nil : hsh2
91
+ end
92
+ def replace(hsh2)
93
+ @order = hsh2.keys
94
+ super hsh2
136
95
  end
137
96
  def shift
138
- #--{{{
139
- key = @order.first
140
- key ? [key,delete(key)] : super
141
- #--}}}
142
- end
143
- def unshift k,v
144
- #--{{{
145
- unless self.include? k
146
- @order.unshift k
147
- orig_store(k,v)
148
- true
149
- else
150
- false
151
- end
152
- #--}}}
153
- end
154
- def push k,v
155
- #--{{{
156
- unless self.include? k
157
- @order.push k
158
- orig_store(k,v)
159
- true
160
- else
161
- false
162
- end
163
- #--}}}
97
+ key = @order.first
98
+ key ? [key,delete(key)] : super
99
+ end
100
+ def unshift(k,v)
101
+ unless self.include? k
102
+ @order.unshift k
103
+ orig_store(k,v)
104
+ true
105
+ else
106
+ false
107
+ end
108
+ end
109
+ def push(k,v)
110
+ unless self.include? k
111
+ @order.push k
112
+ orig_store(k,v)
113
+ true
114
+ else
115
+ false
116
+ end
164
117
  end
165
118
  def pop
166
- #--{{{
167
- key = @order.last
168
- key ? [key,delete(key)] : nil
169
- #--}}}
119
+ key = @order.last
120
+ key ? [key,delete(key)] : nil
170
121
  end
171
122
  def to_a
172
- #--{{{
173
- ary = []
174
- each { |k,v| ary << [k,v] }
175
- ary
176
- #--}}}
123
+ ary = []
124
+ each { |k,v| ary << [k,v] }
125
+ ary
177
126
  end
178
127
  def to_s
179
- #--{{{
180
- self.to_a.to_s
181
- #--}}}
128
+ self.to_a.to_s
182
129
  end
183
130
  def inspect
184
- #--{{{
185
- ary = []
186
- each {|k,v| ary << k.inspect + "=>" + v.inspect}
187
- '{' + ary.join(", ") + '}'
188
- #--}}}
189
- end
190
- def update hsh2
191
- #--{{{
192
- hsh2.each { |k,v| self[k] = v }
193
- self
194
- #--}}}
131
+ ary = []
132
+ each {|k,v| ary << k.inspect + "=>" + v.inspect}
133
+ '{' + ary.join(", ") + '}'
134
+ end
135
+ def update(hsh2)
136
+ hsh2.each { |k,v| self[k] = v }
137
+ self
195
138
  end
196
139
  alias :merge! update
197
140
  def merge(hsh2)
198
- #--{{{
199
- self.dup.update(hsh2)
200
- #--}}}
141
+ self.dup.update(hsh2)
201
142
  end
202
143
  def select
203
- #--{{{
204
- ary = []
205
- each { |k,v| ary << [k,v] if yield k,v }
206
- ary
207
- #--}}}
144
+ ary = []
145
+ each { |k,v| ary << [k,v] if yield k,v }
146
+ ary
208
147
  end
209
148
  def class
210
- #--{{{
211
149
  Hash
212
- #--}}}
213
150
  end
214
151
 
215
152
  attr_accessor "to_yaml_style"
216
- def yaml_inline= bool
153
+ def yaml_inline=(bool)
217
154
  if respond_to?("to_yaml_style")
218
155
  self.to_yaml_style = :inline
219
156
  else
220
157
  unless defined? @__yaml_inline_meth
221
158
  @__yaml_inline_meth =
222
159
  lambda {|opts|
223
- YAML::quick_emit(object_id, opts) {|emitter|
224
- emitter << '{ ' << map{|kv| kv.join ': '}.join(', ') << ' }'
225
- }
160
+ YAML::quick_emit(object_id, opts) {|emitter|
161
+ emitter << '{ ' << map{|kv| kv.join ': '}.join(', ') << ' }'
226
162
  }
163
+ }
227
164
  class << self
228
165
  def to_yaml opts = {}
229
166
  begin
@@ -239,5 +176,5 @@ class OrderedHash < ::Hash
239
176
  @__yaml_inline = bool
240
177
  end
241
178
  def yaml_inline!() self.yaml_inline = true end
242
- #--}}}
243
- end # class OrderedHash
179
+ end # class OrderedHash
180
+ end
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,52 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ require 'yaml'
3
+
4
+ describe 'Doodle', 'block initialization of scalar attributes' do
5
+ temporary_constant :Foo, :Bar, :Farm, :Barn, :Animal do
6
+ before :each do
7
+ class Animal < Doodle
8
+ has :species
9
+ end
10
+ class Barn < Doodle
11
+ has :animals, :collect => Animal
12
+ end
13
+ class Farm < Doodle
14
+ has Barn
15
+ end
16
+ class Foo < Doodle
17
+ has :ivar1, :kind => String
18
+ end
19
+ class Bar < Doodle
20
+ has :block, :kind => Proc
21
+ end
22
+ end
23
+
24
+ it 'should initialize an scalar attribute from a block' do
25
+ farm = Farm do
26
+ barn do
27
+ animal "pig"
28
+ end
29
+ end
30
+ farm.barn.animals[0].species.should_be "pig"
31
+ end
32
+ it 'should fail trying to initialize an inappropriate attribute (not a Doodle or Proc) from a block' do
33
+ proc {
34
+ foo = Foo do
35
+ ivar1 do
36
+ "hello"
37
+ end
38
+ end
39
+ }.should raise_error(ArgumentError)
40
+ end
41
+ it 'should initialize a Proc attribute from a block' do
42
+ bar = Bar do
43
+ block do
44
+ "hello"
45
+ end
46
+ end
47
+ bar.block.class.should_be Proc
48
+ bar.block.call.should_be "hello"
49
+ end
50
+ end
51
+ end
52
+
@@ -12,7 +12,7 @@ describe 'Doodle', 'inheriting validations' do
12
12
  end
13
13
  end
14
14
  end
15
-
15
+
16
16
  it 'should not duplicate validations when accessing them!' do
17
17
  foo = Foo 2
18
18
  foo.doodle.validations.size.should_be 1
@@ -21,7 +21,7 @@ describe 'Doodle', 'inheriting validations' do
21
21
  end
22
22
  end
23
23
 
24
- describe 'Doodle', ' loading good data from yaml' do
24
+ describe 'Doodle', 'loading good data from yaml' do
25
25
  temporary_constant :Foo do
26
26
  before :each do
27
27
  class Foo < Doodle
@@ -30,12 +30,12 @@ describe 'Doodle', ' loading good data from yaml' do
30
30
  Date.parse(s)
31
31
  end
32
32
  end
33
- end
33
+ end
34
34
  @str = %[
35
35
  --- !ruby/object:Foo
36
36
  date: "2000-7-01"
37
37
  ]
38
-
38
+
39
39
  end
40
40
 
41
41
  it 'should succeed without validation' do
@@ -45,7 +45,7 @@ describe 'Doodle', ' loading good data from yaml' do
45
45
  it 'should validate ok' do
46
46
  proc { foo = YAML::load(@str).validate! }.should_not raise_error
47
47
  end
48
-
48
+
49
49
  it 'should apply conversions' do
50
50
  foo = YAML::load(@str).validate!
51
51
  foo.date.should_be Date.new(2000, 7, 1)
@@ -54,7 +54,7 @@ describe 'Doodle', ' loading good data from yaml' do
54
54
  end
55
55
  end
56
56
 
57
- describe 'Doodle', ' loading bad data from yaml' do
57
+ describe 'Doodle', 'loading bad data from yaml' do
58
58
  temporary_constant :Foo do
59
59
  before :each do
60
60
  class Foo < Doodle
@@ -67,7 +67,7 @@ describe 'Doodle', ' loading bad data from yaml' do
67
67
  @str = %[
68
68
  --- !ruby/object:Foo
69
69
  date: "2000"
70
- ]
70
+ ]
71
71
  end
72
72
 
73
73
  it 'should succeed without validation' do
@@ -94,7 +94,7 @@ describe 'Doodle', 'loading bad data from yaml with default defined' do
94
94
  @str = %[
95
95
  --- !ruby/object:Foo
96
96
  date: "2000"
97
- ]
97
+ ]
98
98
  end
99
99
 
100
100
  it 'should succeed without validation' do
@@ -141,7 +141,7 @@ describe Doodle, 'initializing from hashes and yaml' do
141
141
 
142
142
  yaml = %[
143
143
  ---
144
- :address:
144
+ :address:
145
145
  - Henry Wood House
146
146
  - London
147
147
  :name: Sean
@@ -151,14 +151,16 @@ describe Doodle, 'initializing from hashes and yaml' do
151
151
  yaml = person.to_yaml
152
152
  # be careful here - Ruby yaml is finicky (spaces after class names)
153
153
  yaml = yaml.gsub(/\s*\n/m, "\n")
154
- yaml.should_be %[--- !ruby/object:Person
155
- address:
156
- - !ruby/object:AddressLine
157
- text: Henry Wood House
158
- - !ruby/object:AddressLine
159
- text: London
160
- name: Sean
161
- ]
154
+ # yaml.should_be %[--- !ruby/object:Person
155
+ # address:
156
+ # - !ruby/object:AddressLine
157
+ # text: Henry Wood House
158
+ # - !ruby/object:AddressLine
159
+ # text: London
160
+ # name: Sean
161
+ # ]
162
+
163
+ yaml.should_be "--- !ruby/object:Person\naddress:\n- !ruby/object:AddressLine\n text: Henry Wood House\n- !ruby/object:AddressLine\n text: London\nname: Sean\n"
162
164
  person = YAML.load(yaml)
163
165
  proc { person.validate! }.should_not raise_error
164
166
  person.address.all?{ |x| x.kind_of? AddressLine }.should_be true
@@ -187,7 +189,7 @@ describe 'Doodle', 'hiding @__doodle__' do
187
189
  include Doodle::Core
188
190
  end
189
191
  end
190
-
192
+
191
193
  it 'should not reveal @__doodle__ in inspect string' do
192
194
  foo = Foo 2
193
195
  foo.inspect.should_not =~ /@__doodle__/
@@ -226,3 +228,97 @@ describe 'Doodle', 'hiding @__doodle__' do
226
228
  end
227
229
  end
228
230
  end
231
+
232
+ describe 'Doodle', 'initalizing class level collectors' do
233
+ temporary_constant :Menu, :KeyedMenu, :Item, :SubMenu do
234
+ before :each do
235
+ class Item < Doodle
236
+ has :title
237
+ end
238
+ class Menu < Doodle
239
+ class << self
240
+ has :items, :collect => Item
241
+ end
242
+ end
243
+ class KeyedMenu < Doodle
244
+ class << self
245
+ has :items, :collect => Item, :key => :title
246
+ end
247
+ end
248
+ end
249
+
250
+ it 'should collect first item specified in appendable collector' do
251
+ class SubMenu < Menu
252
+ item "Item 1"
253
+ end
254
+ SubMenu.items[0].title.should_be "Item 1"
255
+ end
256
+
257
+ it 'should collect all items specified in appendable collector' do
258
+ class SubMenu < Menu
259
+ item "New Item 1"
260
+ item "New Item 2"
261
+ item "New Item 3"
262
+ end
263
+ SubMenu.items[0].title.should_be "New Item 1"
264
+ SubMenu.items[2].title.should_be "New Item 3"
265
+ SubMenu.items.size.should_be 3
266
+ end
267
+
268
+ it 'should collect first item specified in keyed collector' do
269
+ class SubMenu < KeyedMenu
270
+ item "Item 1"
271
+ end
272
+ SubMenu.items["Item 1"].title.should_be "Item 1"
273
+ end
274
+
275
+ it 'should collect all items specified in keyed collector' do
276
+ class SubMenu < KeyedMenu
277
+ item "New Item 1"
278
+ item "New Item 2"
279
+ item "New Item 3"
280
+ end
281
+ SubMenu.items["New Item 1"].title.should_be "New Item 1"
282
+ SubMenu.items["New Item 3"].title.should_be "New Item 3"
283
+ SubMenu.items.size.should_be 3
284
+ end
285
+
286
+ it 'should collect all items specified in keyed collector in order' do
287
+ class SubMenu < KeyedMenu
288
+ item "New Item 1"
289
+ item "New Item 2"
290
+ item "New Item 3"
291
+ end
292
+ SubMenu.items.to_a[0][0].should_be "New Item 1"
293
+ SubMenu.items.to_a[2][0].should_be "New Item 3"
294
+ SubMenu.items.size.should_be 3
295
+ end
296
+ end
297
+ end
298
+
299
+ describe 'Doodle', 'validating required attributes after default attributes' do
300
+ temporary_constant :Foo do
301
+ before :each do
302
+ class Foo < Doodle
303
+ has :v1, :default => 1
304
+ has :v2
305
+ end
306
+ end
307
+
308
+ it 'should validate required attribute after an attribute with default defined' do
309
+ proc { Foo.new }.should raise_error(Doodle::ValidationError)
310
+ end
311
+
312
+ it 'should validate required attribute after an attribute with default defined specified #1' do
313
+ proc { Foo.new(1) }.should raise_error(Doodle::ValidationError)
314
+ end
315
+
316
+ it 'should validate required attribute after an attribute with default defined specified #2' do
317
+ proc { Foo.new(:v1 => 1) }.should raise_error(Doodle::ValidationError)
318
+ end
319
+
320
+ it 'should validate specified required attribute after an attribute with default defined not specified' do
321
+ proc { Foo.new(:v2 => 2) }.should_not raise_error
322
+ end
323
+ end
324
+ end