doodle 0.1.8 → 0.1.9

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