attributor 2.2.1 → 2.3.0

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.
@@ -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: