attributor 2.5.0 → 2.6.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.
- 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
|