attributor 2.5.0 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +5 -1
- data/CHANGELOG.md +12 -2
- data/README.md +5 -5
- data/lib/attributor/attribute.rb +1 -4
- data/lib/attributor/attribute_resolver.rb +12 -3
- data/lib/attributor/example_mixin.rb +1 -1
- data/lib/attributor/types/csv.rb +4 -2
- data/lib/attributor/types/date.rb +1 -1
- data/lib/attributor/types/date_time.rb +1 -1
- data/lib/attributor/types/hash.rb +64 -22
- data/lib/attributor/types/tempfile.rb +1 -1
- data/lib/attributor/types/time.rb +1 -1
- data/lib/attributor/version.rb +1 -1
- data/spec/attribute_resolver_spec.rb +32 -1
- data/spec/attribute_spec.rb +15 -6
- data/spec/types/collection_spec.rb +1 -1
- data/spec/types/csv_spec.rb +4 -0
- data/spec/types/date_spec.rb +5 -0
- data/spec/types/date_time_spec.rb +5 -0
- data/spec/types/hash_spec.rb +121 -2
- data/spec/types/model_spec.rb +1 -1
- data/spec/types/time_spec.rb +5 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b366557c378f786a7a4620793c05bdb06504ef3e
|
4
|
+
data.tar.gz: 728171cc3c89f03c7f998fb24db74fada6c845a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: facbc89fd9ac8b18cd60611b3699bf3308854890becc782522959497d81c6c89abf59dbc29219c5c9e378a8ff317bfb67b511696c377bd6c024ad234ba3f5866
|
7
|
+
data.tar.gz: 0abb9af1bde8c73bf374686aeb441ef6aba3426f9767970a072d2730d6e71b3e164c9458d1bcb42a48851f424bfdff302096a78300bf8758c0b5461743a13e8f
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,18 @@
|
|
1
1
|
Attributor Changelog
|
2
2
|
============================
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
2.6.0
|
5
|
+
-----
|
6
|
+
|
7
|
+
* Fixed bug in `example_mixin` where lazy_attributes were not evaluated.
|
8
|
+
* Fixed bug in `Hash` where the class would refuse to load from another `Attributor::Hash` when there were no keys defined and they were seemingly compatible.
|
9
|
+
* Fixed a `Hash.dump` bug where nil attribute values would transitively be `dumpe`d therefore causing a nil dereference.
|
10
|
+
* Hardened the `dump`ing of types to support nil values.
|
11
|
+
* Fix `attribute.example` to actually accept native types (that are not only Strings)
|
12
|
+
* Fixed bug where `Hash#get` would insert a nil value if asked for a key that was not present in the hash.
|
13
|
+
* Fixed bug in `Hash.from_hash` where it would add nil values for keys that are defined on the type but not present in the input.
|
14
|
+
* Added `Hash#merge` that works with two identically-typed hashes
|
15
|
+
* Added `Hash#each_pair` for better duck-type compatibility with ::Hash.
|
6
16
|
|
7
17
|
2.5.0
|
8
18
|
----
|
data/README.md
CHANGED
@@ -22,23 +22,23 @@ With Attributor you can:
|
|
22
22
|
|
23
23
|
### Running specs:
|
24
24
|
|
25
|
-
|
25
|
+
bundle exec rake spec
|
26
26
|
|
27
27
|
Note: This should also compute code coverage. See below for details on viewing code coverage.
|
28
28
|
|
29
29
|
### Generating documentation:
|
30
30
|
|
31
|
-
|
31
|
+
bundle exec yard
|
32
32
|
|
33
33
|
### Computing documentation coverage:
|
34
34
|
|
35
|
-
|
35
|
+
bundle exec yardstick 'lib/**/*.rb'
|
36
36
|
|
37
37
|
### Computing code coverage:
|
38
38
|
|
39
|
-
|
39
|
+
bundle exec rake spec
|
40
40
|
|
41
|
-
|
41
|
+
open coverage/index.html
|
42
42
|
|
43
43
|
|
44
44
|
## Contributing to attributor
|
data/lib/attributor/attribute.rb
CHANGED
@@ -135,9 +135,6 @@ module Attributor
|
|
135
135
|
if self.options.has_key? :example
|
136
136
|
val = self.options[:example]
|
137
137
|
case val
|
138
|
-
when ::String
|
139
|
-
# FIXME: spec this properly to use self.type.native_type
|
140
|
-
val
|
141
138
|
when ::Regexp
|
142
139
|
self.load(val.gen,context)
|
143
140
|
when ::Array
|
@@ -154,7 +151,7 @@ module Attributor
|
|
154
151
|
when nil
|
155
152
|
nil
|
156
153
|
else
|
157
|
-
|
154
|
+
self.load(val)
|
158
155
|
end
|
159
156
|
else
|
160
157
|
if (option_values = self.options[:values])
|
@@ -5,6 +5,7 @@ module Attributor
|
|
5
5
|
|
6
6
|
class AttributeResolver
|
7
7
|
ROOT_PREFIX = '$'.freeze
|
8
|
+
COLLECTION_INDEX_KEY = /^at\((\d+)\)$/.freeze
|
8
9
|
|
9
10
|
class Data < ::Hash
|
10
11
|
include Hashie::Extensions::MethodReader
|
@@ -17,7 +18,6 @@ module Attributor
|
|
17
18
|
end
|
18
19
|
|
19
20
|
|
20
|
-
# TODO: support collection queries
|
21
21
|
def query!(key_path, path_prefix=ROOT_PREFIX)
|
22
22
|
# If the incoming key_path is not an absolute path, append the given prefix
|
23
23
|
# NOTE: Need to index key_path by range here because Ruby 1.8 returns a
|
@@ -30,12 +30,21 @@ module Attributor
|
|
30
30
|
# Discard the initial element, which should always be ROOT_PREFIX at this point
|
31
31
|
_root, *path = key_path.split(SEPARATOR)
|
32
32
|
|
33
|
-
# Follow the hierarchy path to the requested node and return it
|
33
|
+
# Follow the hierarchy path to the requested node and return it:
|
34
34
|
# Example path => ["instance", "ssh_key", "name"]
|
35
35
|
# Example @data => {"instance" => { "ssh_key" => { "name" => "foobar" } }}
|
36
|
+
#
|
37
|
+
# at(n) is a collection index:
|
38
|
+
# Example path => ["filters", "at(0)", "type"]
|
39
|
+
# Example data => {"filters" => [{ "type" => "instance:tag" }]}
|
40
|
+
#
|
36
41
|
result = path.inject(@data) do |hash, key|
|
37
42
|
return nil if hash.nil?
|
38
|
-
|
43
|
+
if (match = key.match(COLLECTION_INDEX_KEY))
|
44
|
+
hash[match[1].to_i]
|
45
|
+
else
|
46
|
+
hash.send key
|
47
|
+
end
|
39
48
|
end
|
40
49
|
result
|
41
50
|
end
|
data/lib/attributor/types/csv.rb
CHANGED
@@ -12,9 +12,11 @@ module Attributor
|
|
12
12
|
values
|
13
13
|
when ::Array
|
14
14
|
values.collect { |value| member_attribute.dump(value,opts).to_s }.join(',')
|
15
|
+
when nil
|
16
|
+
nil
|
15
17
|
else
|
16
|
-
context = opts[:context]
|
17
|
-
name =
|
18
|
+
context = opts[:context] || DEFAULT_ROOT_CONTEXT
|
19
|
+
name = context.last.to_s
|
18
20
|
type = values.class.name
|
19
21
|
reason = "Attributor::CSV only supports dumping values of type " +
|
20
22
|
"Array or String, not #{values.class.name}."
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module Attributor
|
2
2
|
class Hash
|
3
|
-
extend Forwardable
|
4
3
|
|
5
4
|
MAX_EXAMPLE_DEPTH = 5
|
6
5
|
CIRCULAR_REFERENCE_MARKER = '...'.freeze
|
@@ -157,7 +156,7 @@ module Attributor
|
|
157
156
|
|
158
157
|
def self.example(context=nil, **values)
|
159
158
|
if (key_type == Object && value_type == Object && self.keys.empty?)
|
160
|
-
return self.new
|
159
|
+
return self.new
|
161
160
|
end
|
162
161
|
|
163
162
|
context ||= ["#{Hash}-#{rand(10000000)}"]
|
@@ -185,8 +184,11 @@ module Attributor
|
|
185
184
|
|
186
185
|
|
187
186
|
def self.dump(value, **opts)
|
188
|
-
self.load(value)
|
189
|
-
dump(**opts)
|
187
|
+
if loaded = self.load(value)
|
188
|
+
loaded.dump(**opts)
|
189
|
+
else
|
190
|
+
nil
|
191
|
+
end
|
190
192
|
end
|
191
193
|
|
192
194
|
|
@@ -221,10 +223,6 @@ module Attributor
|
|
221
223
|
elsif value.is_a?(self)
|
222
224
|
return value
|
223
225
|
elsif value.kind_of?(Attributor::Hash)
|
224
|
-
if (value.keys - self.attributes.keys).any?
|
225
|
-
raise Attributor::IncompatibleTypeError, context: context, value_type: value.class, type: self
|
226
|
-
end
|
227
|
-
|
228
226
|
loaded_value = value.contents
|
229
227
|
elsif value.is_a?(::Hash)
|
230
228
|
loaded_value = value
|
@@ -255,11 +253,17 @@ module Attributor
|
|
255
253
|
|
256
254
|
def get(key, context: self.generate_subcontext(Attributor::DEFAULT_ROOT_CONTEXT,key))
|
257
255
|
key = self.class.key_attribute.load(key, context)
|
258
|
-
|
256
|
+
|
259
257
|
value = @contents[key]
|
260
258
|
|
259
|
+
# FIXME: getting an unset value here should not force it in the hash
|
261
260
|
if (attribute = self.class.keys[key])
|
262
|
-
|
261
|
+
loaded_value = attribute.load(value, context)
|
262
|
+
if loaded_value.nil?
|
263
|
+
return nil
|
264
|
+
else
|
265
|
+
return self[key] = loaded_value
|
266
|
+
end
|
263
267
|
end
|
264
268
|
|
265
269
|
if self.class.options[:case_insensitive_load]
|
@@ -338,7 +342,8 @@ module Attributor
|
|
338
342
|
self.keys.each do |key_name, attribute|
|
339
343
|
next if hash.key?(key_name)
|
340
344
|
sub_context = self.generate_subcontext(context,key_name)
|
341
|
-
|
345
|
+
default = attribute.load(nil, sub_context, recurse: recurse)
|
346
|
+
hash[key_name] = default unless default.nil?
|
342
347
|
end
|
343
348
|
|
344
349
|
hash
|
@@ -379,17 +384,54 @@ module Attributor
|
|
379
384
|
|
380
385
|
# TODO: Think about the format of the subcontexts to use: let's use .at(key.to_s)
|
381
386
|
attr_reader :contents
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
387
|
+
|
388
|
+
def [](k)
|
389
|
+
@contents[k]
|
390
|
+
end
|
391
|
+
|
392
|
+
def []=(k,v)
|
393
|
+
@contents[k] = v
|
394
|
+
end
|
395
|
+
|
396
|
+
def each(&block)
|
397
|
+
@contents.each(&block)
|
398
|
+
end
|
399
|
+
|
400
|
+
def each_pair(&block)
|
401
|
+
@contents.each_pair(&block)
|
402
|
+
end
|
403
|
+
|
404
|
+
def size
|
405
|
+
@contents.size
|
406
|
+
end
|
407
|
+
|
408
|
+
def keys
|
409
|
+
@contents.keys
|
410
|
+
end
|
411
|
+
|
412
|
+
def values
|
413
|
+
@contents.values
|
414
|
+
end
|
415
|
+
|
416
|
+
def empty?
|
417
|
+
@contents.empty?
|
418
|
+
end
|
419
|
+
|
420
|
+
def key?(k)
|
421
|
+
@contents.key?(k)
|
422
|
+
end
|
423
|
+
alias_method :has_key?, :key?
|
424
|
+
|
425
|
+
def merge(h)
|
426
|
+
case h
|
427
|
+
when self.class
|
428
|
+
self.class.new(@contents.merge(h.contents))
|
429
|
+
when Attributor::Hash
|
430
|
+
raise ArgumentError, "cannot merge Attributor::Hash instances of different types" unless h.is_a?(self.class)
|
431
|
+
else
|
432
|
+
raise TypeError, "no implicit conversion of #{h.class} into Attributor::Hash"
|
433
|
+
end
|
434
|
+
end
|
393
435
|
|
394
436
|
attr_reader :validating, :dumping
|
395
437
|
|
data/lib/attributor/version.rb
CHANGED
@@ -66,6 +66,37 @@ describe Attributor::AttributeResolver do
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
+
context 'querying collection indices from models' do
|
70
|
+
let(:instances) { [instance1, instance2] }
|
71
|
+
let(:instance1) { double('instance1', :ssh_key => ssh_key1) }
|
72
|
+
let(:instance2) { double('instance2', :ssh_key => ssh_key2) }
|
73
|
+
let(:ssh_key1) { double('ssh_key', :name => value) }
|
74
|
+
let(:ssh_key2) { double('ssh_key', :name => 'second') }
|
75
|
+
let(:args) { [path, prefix].compact }
|
76
|
+
|
77
|
+
before { subject.register('instances', instances) }
|
78
|
+
|
79
|
+
it 'resolves the index to the correct member of the collection' do
|
80
|
+
subject.query('instances').should be instances
|
81
|
+
subject.query('instances.at(1).ssh_key').should be ssh_key2
|
82
|
+
subject.query('instances.at(0).ssh_key.name').should be value
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'returns nil for index out of range' do
|
86
|
+
subject.query('instances.at(2)').should be(nil)
|
87
|
+
subject.query('instances.at(-1)').should be(nil)
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'with a prefix' do
|
91
|
+
let(:key) { 'name' }
|
92
|
+
let(:prefix) { '$.instances.at(0).ssh_key'}
|
93
|
+
let(:value) { 'some_name' }
|
94
|
+
|
95
|
+
it 'resolves the index to the correct member of the collection' do
|
96
|
+
subject.query(key, prefix).should be(value)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
69
100
|
|
70
101
|
context 'checking attribute conditions' do
|
71
102
|
let(:key) { "instance.ssh_key.name" }
|
@@ -123,7 +154,7 @@ describe Attributor::AttributeResolver do
|
|
123
154
|
end
|
124
155
|
end
|
125
156
|
|
126
|
-
|
157
|
+
pending 'with a hash condition' do
|
127
158
|
end
|
128
159
|
|
129
160
|
context 'with a proc condition' do
|
data/spec/attribute_spec.rb
CHANGED
@@ -146,12 +146,21 @@ describe Attributor::Attribute do
|
|
146
146
|
|
147
147
|
context 'for a type with a non-String native_type' do
|
148
148
|
let(:type) { IntegerAttributeType}
|
149
|
-
|
150
|
-
|
151
|
-
example
|
152
|
-
|
153
|
-
|
154
|
-
|
149
|
+
context 'using a regexp' do
|
150
|
+
let(:example) { /\d{5}/ }
|
151
|
+
it 'coerces the example value properly' do
|
152
|
+
example.should_receive(:gen).and_call_original
|
153
|
+
type.should_receive(:load).and_call_original
|
154
|
+
|
155
|
+
subject.example.should be_kind_of(type.native_type)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
context 'usign a native Integer type' do
|
159
|
+
let(:example) { 5 }
|
160
|
+
it 'coerces the example value properly' do
|
161
|
+
type.should_receive(:load).and_call_original
|
162
|
+
subject.example.should be_kind_of(type.native_type)
|
163
|
+
end
|
155
164
|
end
|
156
165
|
end
|
157
166
|
end
|
@@ -152,7 +152,7 @@ describe Attributor::Collection do
|
|
152
152
|
it "raises error when incoming value is not of member_type" do
|
153
153
|
expect {
|
154
154
|
val = type.of(member_type).load(value)
|
155
|
-
}.to raise_error(Attributor::AttributorException)
|
155
|
+
}.to raise_error(Attributor::AttributorException,/Unknown key received/)
|
156
156
|
end
|
157
157
|
|
158
158
|
end
|
data/spec/types/csv_spec.rb
CHANGED
data/spec/types/date_spec.rb
CHANGED
@@ -18,6 +18,11 @@ describe Attributor::DateTime do
|
|
18
18
|
it 'is formatted correctly' do
|
19
19
|
value.should match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[\+-]\d{2}:\d{2}/)
|
20
20
|
end
|
21
|
+
context 'nil values' do
|
22
|
+
it 'should be nil' do
|
23
|
+
type.dump(nil).should be_nil
|
24
|
+
end
|
25
|
+
end
|
21
26
|
end
|
22
27
|
|
23
28
|
|
data/spec/types/hash_spec.rb
CHANGED
@@ -110,6 +110,82 @@ describe Attributor::Hash do
|
|
110
110
|
end
|
111
111
|
end
|
112
112
|
end
|
113
|
+
|
114
|
+
context 'for another Attributor Hash with a compatible type definition' do
|
115
|
+
let(:other_hash) do
|
116
|
+
Attributor::Hash.of(key: Integer, value: Integer)
|
117
|
+
end
|
118
|
+
let(:value) { other_hash.example }
|
119
|
+
it 'succeeds' do
|
120
|
+
type.load(value)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'for Hash with defined keys' do
|
125
|
+
let(:type) do
|
126
|
+
Class.new(Attributor::Hash) do
|
127
|
+
keys do
|
128
|
+
key 'id', Integer
|
129
|
+
key 'name', String, default: "unnamed"
|
130
|
+
key 'chicken', Chicken
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
let(:value) { {'chicken' => Chicken.example} }
|
136
|
+
|
137
|
+
subject(:hash) { type.load(value) }
|
138
|
+
|
139
|
+
it { should_not have_key('id') }
|
140
|
+
it 'has the defaulted key' do
|
141
|
+
hash.should have_key('name')
|
142
|
+
hash['name'].should eq('unnamed')
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'for a different Attributor Hash' do
|
147
|
+
let(:loader_hash) do
|
148
|
+
Class.new(Attributor::Hash) do
|
149
|
+
keys do
|
150
|
+
key :id, String
|
151
|
+
key :name, String
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
let(:value) { value_hash.example }
|
156
|
+
context 'with compatible key definitions' do
|
157
|
+
let(:value_hash) do
|
158
|
+
Class.new(Attributor::Hash) do
|
159
|
+
keys do
|
160
|
+
key :id, String
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'succeeds' do
|
166
|
+
loader_hash.load(value)
|
167
|
+
end
|
168
|
+
|
169
|
+
context 'with a not compatible key definition' do
|
170
|
+
let(:value_hash) do
|
171
|
+
Class.new(Attributor::Hash) do
|
172
|
+
keys do
|
173
|
+
key :id, String
|
174
|
+
key :weird_key, String
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'complains about an unknown key' do
|
180
|
+
expect {
|
181
|
+
loader_hash.load(value)
|
182
|
+
}.to raise_error(Attributor::AttributorException,/Unknown key received: :weird_key/)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
|
113
189
|
end
|
114
190
|
|
115
191
|
|
@@ -254,6 +330,9 @@ describe Attributor::Hash do
|
|
254
330
|
end
|
255
331
|
|
256
332
|
context 'for a typed hash' do
|
333
|
+
before do
|
334
|
+
subtype.should_receive(:dump).exactly(2).times.and_call_original
|
335
|
+
end
|
257
336
|
let(:value1) { {first: "Joe", last: "Moe"} }
|
258
337
|
let(:value2) { {first: "Mary", last: "Foe"} }
|
259
338
|
let(:value) { { id1: subtype.new(value1), id2: subtype.new(value2) } }
|
@@ -268,8 +347,6 @@ describe Attributor::Hash do
|
|
268
347
|
let(:type) { Attributor::Hash.of(key: String, value: subtype) }
|
269
348
|
|
270
349
|
it 'returns a hash with the dumped values and keys' do
|
271
|
-
subtype.should_receive(:dump).exactly(2).times.and_call_original
|
272
|
-
|
273
350
|
dumped_value = type.dump(value, opts)
|
274
351
|
dumped_value.should be_kind_of(::Hash)
|
275
352
|
dumped_value.keys.should =~ ['id1','id2']
|
@@ -278,6 +355,17 @@ describe Attributor::Hash do
|
|
278
355
|
dumped_value['id2'].should == value2
|
279
356
|
end
|
280
357
|
|
358
|
+
context 'that has nil attribute values' do
|
359
|
+
let(:value) { { id1: nil, id2: subtype.new(value2) } }
|
360
|
+
|
361
|
+
it 'correctly returns nil rather than trying to dump their contents' do
|
362
|
+
dumped_value = type.dump(value, opts)
|
363
|
+
dumped_value.should be_kind_of(::Hash)
|
364
|
+
dumped_value.keys.should =~ ['id1','id2']
|
365
|
+
dumped_value['id1'].should == nil
|
366
|
+
dumped_value['id2'].should == value2
|
367
|
+
end
|
368
|
+
end
|
281
369
|
end
|
282
370
|
|
283
371
|
end
|
@@ -593,10 +681,41 @@ describe Attributor::Hash do
|
|
593
681
|
|
594
682
|
hash.get('foo').should be(bar)
|
595
683
|
end
|
684
|
+
|
685
|
+
it 'does not set a key that is unset' do
|
686
|
+
hash.should_not have_key('id')
|
687
|
+
hash.get('id').should be(nil)
|
688
|
+
hash.should_not have_key('id')
|
689
|
+
end
|
690
|
+
|
596
691
|
end
|
597
692
|
|
598
693
|
end
|
599
694
|
|
600
695
|
end
|
601
696
|
|
697
|
+
context '#merge' do
|
698
|
+
let(:hash_of_strings) { Attributor::Hash.of(key: String) }
|
699
|
+
let(:hash_of_symbols) { Attributor::Hash.of(key: Symbol) }
|
700
|
+
|
701
|
+
let(:merger) { hash_of_strings.load('a' => 1) }
|
702
|
+
let(:good_mergee) { hash_of_strings.load('b' => 2) }
|
703
|
+
let(:bad_mergee) { hash_of_symbols.load(c: 3) }
|
704
|
+
let(:result) { hash_of_strings.load('a' => 1, 'b' => 2) }
|
705
|
+
|
706
|
+
it 'validates that the mergee is of like type' do
|
707
|
+
expect { merger.merge(bad_mergee) }.to raise_error(ArgumentError)
|
708
|
+
expect { merger.merge({}) }.to raise_error(TypeError)
|
709
|
+
expect { merger.merge(nil) }.to raise_error(TypeError)
|
710
|
+
end
|
711
|
+
|
712
|
+
it 'returns a like-typed result' do
|
713
|
+
expect(merger.merge(good_mergee)).to be_a(hash_of_strings)
|
714
|
+
end
|
715
|
+
|
716
|
+
it 'merges' do
|
717
|
+
expect(merger.merge(good_mergee)).to eq(result)
|
718
|
+
end
|
719
|
+
|
720
|
+
end
|
602
721
|
end
|
data/spec/types/model_spec.rb
CHANGED
@@ -172,7 +172,7 @@ describe Attributor::Model do
|
|
172
172
|
expect {
|
173
173
|
turducken = Turducken.example
|
174
174
|
chicken = Chicken.load(turducken,context)
|
175
|
-
}.to raise_error(Attributor::
|
175
|
+
}.to raise_error(Attributor::AttributorException, /Unknown key received/)
|
176
176
|
end
|
177
177
|
end
|
178
178
|
|
data/spec/types/time_spec.rb
CHANGED
@@ -18,6 +18,11 @@ describe Attributor::Time do
|
|
18
18
|
it 'is formatted correctly' do
|
19
19
|
value.should match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[\+-]\d{2}:\d{2}/)
|
20
20
|
end
|
21
|
+
context 'nil values' do
|
22
|
+
it 'should be nil' do
|
23
|
+
type.dump(nil).should be_nil
|
24
|
+
end
|
25
|
+
end
|
21
26
|
end
|
22
27
|
|
23
28
|
|
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.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josep M. Blanquer
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-03-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: hashie
|