attributor 2.2.1 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +12 -4
- data/lib/attributor.rb +4 -2
- data/lib/attributor/attribute.rb +8 -9
- data/lib/attributor/exceptions.rb +6 -6
- data/lib/attributor/extensions/randexp.rb +5 -0
- data/lib/attributor/types/bigdecimal.rb +28 -0
- data/lib/attributor/types/boolean.rb +2 -0
- data/lib/attributor/types/collection.rb +6 -5
- data/lib/attributor/types/csv.rb +21 -0
- data/lib/attributor/types/date.rb +37 -0
- data/lib/attributor/types/date_time.rb +1 -1
- data/lib/attributor/types/hash.rb +64 -18
- data/lib/attributor/types/model.rb +14 -6
- data/lib/attributor/types/string.rb +1 -1
- data/lib/attributor/types/time.rb +39 -0
- data/lib/attributor/version.rb +1 -1
- data/spec/attribute_spec.rb +5 -12
- data/spec/support/hashes.rb +7 -0
- data/spec/support/models.rb +3 -1
- data/spec/types/bigdecimal_spec.rb +48 -0
- data/spec/types/boolean_spec.rb +4 -0
- data/spec/types/collection_spec.rb +12 -1
- data/spec/types/csv_spec.rb +31 -0
- data/spec/types/date_spec.rb +94 -0
- data/spec/types/date_time_spec.rb +21 -17
- data/spec/types/float_spec.rb +4 -0
- data/spec/types/hash_spec.rb +122 -11
- data/spec/types/ids_spec.rb +2 -2
- data/spec/types/integer_spec.rb +3 -0
- data/spec/types/model_spec.rb +16 -4
- data/spec/types/string_spec.rb +4 -0
- data/spec/types/time_spec.rb +91 -0
- metadata +12 -1
data/spec/types/float_spec.rb
CHANGED
data/spec/types/hash_spec.rb
CHANGED
@@ -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 =~ [
|
275
|
+
dumped_value.keys.should =~ ['id1','id2']
|
265
276
|
dumped_value.values.should have(2).items
|
266
|
-
|
267
|
-
|
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
|
data/spec/types/ids_spec.rb
CHANGED
@@ -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
|
data/spec/types/integer_spec.rb
CHANGED
data/spec/types/model_spec.rb
CHANGED
@@ -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
|
data/spec/types/string_spec.rb
CHANGED
@@ -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.
|
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:
|