attributor 2.2.1 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -25,6 +25,10 @@ describe Attributor::Float do
25
25
  context '.load' do
26
26
  let(:value) { nil }
27
27
 
28
+ it 'returns nil for nil' do
29
+ type.load(nil).should be(nil)
30
+ end
31
+
28
32
  context 'for incoming Float values' do
29
33
 
30
34
  it 'returns the incoming value' do
@@ -52,6 +52,16 @@ describe Attributor::Hash do
52
52
  let(:value) { {one: 'two', three: 4} }
53
53
  subject(:hash) { type.load(value) }
54
54
 
55
+ context 'for nil with recurse: true' do
56
+ let(:value) { nil }
57
+ subject(:hash) { HashWithModel.load(value, recurse:true) }
58
+
59
+ it 'works' do
60
+ hash[:name].should eq('Turkey McDucken')
61
+ hash[:chicken].age.should eq(1)
62
+ end
63
+ end
64
+
55
65
  context 'for a simple hash' do
56
66
  it { should eq(value) }
57
67
  it 'equals the hash' do
@@ -259,17 +269,17 @@ describe Attributor::Hash do
259
269
 
260
270
  it 'returns a hash with the dumped values and keys' do
261
271
  subtype.should_receive(:dump).exactly(2).times.and_call_original
272
+
262
273
  dumped_value = type.dump(value, opts)
263
274
  dumped_value.should be_kind_of(::Hash)
264
- dumped_value.keys.should =~ [:id1,:id2]
275
+ dumped_value.keys.should =~ ['id1','id2']
265
276
  dumped_value.values.should have(2).items
266
- value[:id1].should be_kind_of subtype
267
- value[:id2].should be_kind_of subtype
268
- dumped_value[:id1].should == value1
269
- dumped_value[:id2].should == value2
277
+ dumped_value['id1'].should == value1
278
+ dumped_value['id2'].should == value2
270
279
  end
271
280
 
272
281
  end
282
+
273
283
  end
274
284
 
275
285
  context '#validate' do
@@ -390,21 +400,71 @@ describe Attributor::Hash do
390
400
  end
391
401
  let(:hash) { {one: value_type.example} }
392
402
 
393
- it 'works too' do
394
- #pp output
395
- end
396
-
397
403
  end
398
404
  context 'will always return a top level hash' do
399
405
  subject(:type_dump){ type.dump(value) }
400
406
  let(:key_type){ Attributor::Object }
401
407
  let(:value_type){ Attributor::Object }
402
-
408
+
403
409
  it 'even when key/types are object' do
404
410
  subject.should be_kind_of(::Hash)
405
411
  subject.should eq( hash )
406
412
  end
407
413
  end
414
+
415
+ context 'for a hash with defined keys' do
416
+ let(:type) do
417
+ Class.new(Attributor::Hash) do
418
+ keys do
419
+ key 'id', Integer
420
+ key 'chicken', Chicken
421
+ end
422
+ end
423
+ end
424
+
425
+ let(:chicken) { {'name' => 'bob'} }
426
+
427
+ let(:value) { {'id' => '1', 'chicken' => chicken } }
428
+ let(:expected) { {'id' => 1, 'chicken' => Chicken.dump(chicken) } }
429
+
430
+ it 'properly dumps the values' do
431
+ type.dump(value).should eq(expected)
432
+ end
433
+
434
+ context 'with allow_extra: true' do
435
+ let(:type) do
436
+ Class.new(Attributor::Hash) do
437
+ keys allow_extra: true do
438
+ key 'id', Integer
439
+ key 'chicken', Chicken
440
+ end
441
+ end
442
+ end
443
+
444
+ let(:value) { {'id' => '1', 'chicken' => chicken, 'rank' => 'bob rank'} }
445
+ let(:expected) { {'id' => 1, 'chicken' => Chicken.dump(chicken), 'rank' => 'bob rank' } }
446
+ it 'preserves the extra keys at the top level' do
447
+ type.dump(value).should eq(expected)
448
+ end
449
+
450
+ context 'with extra option' do
451
+ let(:type) do
452
+ Class.new(Attributor::Hash) do
453
+ keys allow_extra: true do
454
+ key 'id', Integer
455
+ key 'chicken', Chicken
456
+ extra 'other', Attributor::Hash
457
+ end
458
+ end
459
+ end
460
+
461
+ let(:expected) { {'id' => 1, 'chicken' => Chicken.dump(chicken), 'other' => {'rank' => 'bob rank' }} }
462
+ it 'dumps the extra keys inside the subhash' do
463
+ type.dump(value).should eq(expected)
464
+ end
465
+ end
466
+ end
467
+ end
408
468
  end
409
469
 
410
470
  context 'with case_insensitive_load option for string keys' do
@@ -453,7 +513,7 @@ describe Attributor::Hash do
453
513
  output[:two].should eq('two')
454
514
  output[:three].should eq('3')
455
515
  end
456
-
516
+
457
517
  its( :validate ){ should be_empty }
458
518
  end
459
519
 
@@ -486,6 +546,57 @@ describe Attributor::Hash do
486
546
  end
487
547
  end
488
548
 
549
+ context '#get and #set' do
550
+ let(:type) do
551
+ Class.new(Attributor::Hash) do
552
+ keys do
553
+ key 'id', Integer
554
+ key 'chicken', Chicken
555
+ extra 'others', Attributor::Hash, default: {}
556
+ end
557
+ end
558
+ end
559
+
560
+ let(:chicken) { {name: 'bob'} }
561
+ subject(:hash) { type.new }
562
+
563
+ context '#set' do
564
+ it 'sets values into "extra" keys if appplicable' do
565
+ hash.should_not have_key('others')
566
+ hash.set 'foo', 'bar'
567
+ hash['others'].should have_key('foo')
568
+ hash.should have_key('others')
569
+ hash['others']['foo'].should eq('bar')
570
+ end
571
+
572
+ it 'loads values before saving into the contents' do
573
+ hash.set 'chicken', chicken
574
+ hash['chicken'].should be_a(Chicken)
575
+ end
576
+ end
577
+
578
+ context '#get' do
579
+ before do
580
+ hash['chicken'] = chicken
581
+ hash['chicken'].should eq(chicken)
582
+ end
583
+
584
+ it 'loads and updates the saved value' do
585
+ hash.get('chicken').should be_a(Chicken)
586
+ hash['chicken'].should be_a(Chicken)
587
+ end
588
+
589
+ it 'retrieves values from an "extra" key' do
590
+ bar = double('bar')
591
+ hash.set 'foo', bar
592
+ hash.get('others').get('foo').should be(bar)
593
+
594
+ hash.get('foo').should be(bar)
595
+ end
596
+ end
597
+
598
+ end
599
+
489
600
  end
490
601
 
491
602
  end
@@ -16,8 +16,8 @@ describe Attributor::Ids do
16
16
  ids.load(value).should eq(emails)
17
17
  end
18
18
 
19
- it 'generates valid examples' do
20
- ids.validate(ids.example).should be_empty
19
+ it 'generates valid, loadable examples' do
20
+ ids.validate(ids.load(ids.example)).should be_empty
21
21
  end
22
22
 
23
23
  end
@@ -107,6 +107,9 @@ describe Attributor::Integer do
107
107
  context '.load' do
108
108
  let(:value) { nil }
109
109
 
110
+ it 'returns nil for nil' do
111
+ type.load(nil).should be(nil)
112
+ end
110
113
 
111
114
  context 'for incoming integer values' do
112
115
  let(:value) { 1 }
@@ -66,7 +66,7 @@ describe Attributor::Model do
66
66
  context 'with infinitely-expanding sub-attributes' do
67
67
  let(:model_class) do
68
68
  Class.new(Attributor::Model) do
69
- this = self
69
+ this = self
70
70
  attributes do
71
71
  attribute :name, String
72
72
  attribute :child, this
@@ -120,6 +120,16 @@ describe Attributor::Model do
120
120
  it 'returns nil' do
121
121
  Chicken.load(nil).should be_nil
122
122
  end
123
+
124
+ context 'with recurse: true' do
125
+ subject(:turducken) { Turducken.load(nil, [], recurse: true) }
126
+
127
+ it 'loads with default values' do
128
+ turducken.name.should eq("Turkey McDucken")
129
+ turducken.chicken.age.should be(1)
130
+ end
131
+
132
+ end
123
133
  end
124
134
 
125
135
  context 'with a JSON-serialized hash' do
@@ -128,7 +138,7 @@ describe Attributor::Model do
128
138
  let(:json) { hash.to_json }
129
139
  before do
130
140
  Chicken.should_receive(:from_hash).
131
- with(expected_hash,context)
141
+ with(expected_hash,context, recurse: false)
132
142
  JSON.should_receive(:parse).with(json).and_call_original
133
143
  end
134
144
 
@@ -186,6 +196,7 @@ describe Attributor::Model do
186
196
  end
187
197
 
188
198
 
199
+
189
200
  end
190
201
 
191
202
  end
@@ -208,7 +219,7 @@ describe Attributor::Model do
208
219
  it 'and sets them in loaded format onto the instance attributes' do
209
220
  Chicken.should_receive(:load).with(attributes_data).and_call_original
210
221
  attributes_data.keys.each do |attr_name|
211
- Chicken.attributes[attr_name].should_receive(:load).with(attributes_data[attr_name],instance_of(Array)).and_call_original
222
+ Chicken.attributes[attr_name].should_receive(:load).with(attributes_data[attr_name],instance_of(Array), recurse: false).and_call_original
212
223
  end
213
224
  subject.age.should be(1)
214
225
  subject.email.should be(attributes_data[:email])
@@ -220,7 +231,7 @@ describe Attributor::Model do
220
231
  it 'and sets them in loaded format onto the instance attributes' do
221
232
  Chicken.should_receive(:load).with(attributes_data).and_call_original
222
233
  attributes_hash.keys.each do |attr_name|
223
- Chicken.attributes[attr_name].should_receive(:load).with(attributes_hash[attr_name],instance_of(Array)).and_call_original
234
+ Chicken.attributes[attr_name].should_receive(:load).with(attributes_hash[attr_name],instance_of(Array), recurse: false).and_call_original
224
235
  end
225
236
  subject.age.should be(1)
226
237
  subject.email.should == attributes_hash[:email]
@@ -398,4 +409,5 @@ describe Attributor::Model do
398
409
  end
399
410
 
400
411
 
412
+
401
413
  end
@@ -34,6 +34,10 @@ describe Attributor::String do
34
34
  context '.load' do
35
35
  let(:value) { nil }
36
36
 
37
+ it 'returns nil for nil' do
38
+ type.load(nil).should be(nil)
39
+ end
40
+
37
41
  context 'for incoming String values' do
38
42
 
39
43
  it 'returns the incoming value' do
@@ -0,0 +1,91 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
2
+
3
+ describe Attributor::Time do
4
+
5
+ subject(:type) { Attributor::Time }
6
+
7
+ context '.native_type' do
8
+ its(:native_type) { should be(::Time) }
9
+ end
10
+
11
+ context '.example' do
12
+ its(:example) { should be_a(::Time) }
13
+ end
14
+
15
+ context '.load' do
16
+
17
+ it 'returns nil for nil' do
18
+ type.load(nil).should be(nil)
19
+ end
20
+
21
+ context 'for incoming objects' do
22
+
23
+ it "returns correct Time for DateTime objects" do
24
+ object = Time.now
25
+ loaded = type.load(object)
26
+ loaded.should be_a(::Time)
27
+ loaded.to_time.should == object
28
+ end
29
+
30
+ it "returns correct Time for DateTime objects" do
31
+ object = DateTime.now
32
+ loaded = type.load(object)
33
+ loaded.should be_a(::Time)
34
+ loaded.should eq(object.to_time)
35
+ end
36
+
37
+ end
38
+
39
+ context 'for incoming strings' do
40
+
41
+ [
42
+ '2001-02-03T04:05:06+07:00',
43
+ 'Sat, 03 Feb 2001 04:05:06 GMT',
44
+ '20010203T040506+0700',
45
+ '2001-W05-6T04:05:06+07:00',
46
+ 'H13.02.03T04:05:06+07:00',
47
+ 'Sat, 3 Feb 2001 04:05:06 +0700',
48
+ '2013/08/23 00:39:55 +0000',
49
+ '2007-10-19T04:11:33Z',
50
+ '2001-02-03T04:05:06+07:00.123456', # custom format with microseconds
51
+ ].each do |value|
52
+
53
+ it "returns correct Time for #{value.inspect}" do
54
+ type.load(value).should == Time.parse(value)
55
+ end
56
+
57
+ end
58
+
59
+ [
60
+ '2013/08/33 00:39:55 +0000',
61
+ '2007-10-33T04:11:33Z',
62
+ '2001-02-33T04:05:06+07:00.123456', # custom format with microseconds
63
+ ].each do |value|
64
+
65
+ it "raises Attributor::AttributorException for #{value.inspect}" do
66
+ expect {
67
+ type.load(value)
68
+ }.to raise_error(Attributor::DeserializationError, /Error deserializing a String using Time/)
69
+ end
70
+
71
+ end
72
+
73
+ [
74
+ '',
75
+ 'foobar'
76
+ ].each do |value|
77
+
78
+ it "raises Attributor::AttributorException for #{value.inspect}" do
79
+ expect {
80
+ type.load(value)
81
+ }.to raise_error(Attributor::DeserializationError, /Error deserializing a String using Time/)
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attributor
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.1
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josep M. Blanquer
@@ -260,10 +260,12 @@ files:
260
260
  - lib/attributor/exceptions.rb
261
261
  - lib/attributor/extensions/randexp.rb
262
262
  - lib/attributor/type.rb
263
+ - lib/attributor/types/bigdecimal.rb
263
264
  - lib/attributor/types/boolean.rb
264
265
  - lib/attributor/types/collection.rb
265
266
  - lib/attributor/types/container.rb
266
267
  - lib/attributor/types/csv.rb
268
+ - lib/attributor/types/date.rb
267
269
  - lib/attributor/types/date_time.rb
268
270
  - lib/attributor/types/file_upload.rb
269
271
  - lib/attributor/types/float.rb
@@ -275,19 +277,23 @@ files:
275
277
  - lib/attributor/types/string.rb
276
278
  - lib/attributor/types/struct.rb
277
279
  - lib/attributor/types/tempfile.rb
280
+ - lib/attributor/types/time.rb
278
281
  - lib/attributor/version.rb
279
282
  - spec/attribute_resolver_spec.rb
280
283
  - spec/attribute_spec.rb
281
284
  - spec/attributor_spec.rb
282
285
  - spec/dsl_compiler_spec.rb
283
286
  - spec/spec_helper.rb
287
+ - spec/support/hashes.rb
284
288
  - spec/support/models.rb
285
289
  - spec/support/types.rb
286
290
  - spec/type_spec.rb
291
+ - spec/types/bigdecimal_spec.rb
287
292
  - spec/types/boolean_spec.rb
288
293
  - spec/types/collection_spec.rb
289
294
  - spec/types/container_spec.rb
290
295
  - spec/types/csv_spec.rb
296
+ - spec/types/date_spec.rb
291
297
  - spec/types/date_time_spec.rb
292
298
  - spec/types/file_upload_spec.rb
293
299
  - spec/types/float_spec.rb
@@ -298,6 +304,7 @@ files:
298
304
  - spec/types/string_spec.rb
299
305
  - spec/types/struct_spec.rb
300
306
  - spec/types/tempfile_spec.rb
307
+ - spec/types/time_spec.rb
301
308
  homepage: https://github.com/rightscale/attributor
302
309
  licenses:
303
310
  - MIT
@@ -328,13 +335,16 @@ test_files:
328
335
  - spec/attributor_spec.rb
329
336
  - spec/dsl_compiler_spec.rb
330
337
  - spec/spec_helper.rb
338
+ - spec/support/hashes.rb
331
339
  - spec/support/models.rb
332
340
  - spec/support/types.rb
333
341
  - spec/type_spec.rb
342
+ - spec/types/bigdecimal_spec.rb
334
343
  - spec/types/boolean_spec.rb
335
344
  - spec/types/collection_spec.rb
336
345
  - spec/types/container_spec.rb
337
346
  - spec/types/csv_spec.rb
347
+ - spec/types/date_spec.rb
338
348
  - spec/types/date_time_spec.rb
339
349
  - spec/types/file_upload_spec.rb
340
350
  - spec/types/float_spec.rb
@@ -345,4 +355,5 @@ test_files:
345
355
  - spec/types/string_spec.rb
346
356
  - spec/types/struct_spec.rb
347
357
  - spec/types/tempfile_spec.rb
358
+ - spec/types/time_spec.rb
348
359
  has_rdoc: