attributor 5.0.2 → 5.1.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/.rubocop.yml +30 -0
- data/.travis.yml +6 -4
- data/CHANGELOG.md +6 -1
- data/Gemfile +1 -1
- data/Guardfile +14 -8
- data/Rakefile +4 -5
- data/attributor.gemspec +34 -29
- data/lib/attributor.rb +23 -29
- data/lib/attributor/attribute.rb +108 -127
- data/lib/attributor/attribute_resolver.rb +12 -26
- data/lib/attributor/dsl_compiler.rb +17 -21
- data/lib/attributor/dumpable.rb +1 -2
- data/lib/attributor/example_mixin.rb +5 -8
- data/lib/attributor/exceptions.rb +5 -6
- data/lib/attributor/extensions/randexp.rb +3 -5
- data/lib/attributor/extras/field_selector.rb +4 -4
- data/lib/attributor/extras/field_selector/transformer.rb +6 -7
- data/lib/attributor/families/numeric.rb +0 -2
- data/lib/attributor/families/temporal.rb +1 -4
- data/lib/attributor/hash_dsl_compiler.rb +22 -25
- data/lib/attributor/type.rb +24 -32
- data/lib/attributor/types/bigdecimal.rb +7 -14
- data/lib/attributor/types/boolean.rb +5 -8
- data/lib/attributor/types/class.rb +9 -10
- data/lib/attributor/types/collection.rb +34 -44
- data/lib/attributor/types/container.rb +9 -15
- data/lib/attributor/types/csv.rb +7 -10
- data/lib/attributor/types/date.rb +20 -25
- data/lib/attributor/types/date_time.rb +7 -14
- data/lib/attributor/types/float.rb +4 -6
- data/lib/attributor/types/hash.rb +171 -196
- data/lib/attributor/types/ids.rb +2 -6
- data/lib/attributor/types/integer.rb +12 -17
- data/lib/attributor/types/model.rb +39 -48
- data/lib/attributor/types/object.rb +2 -4
- data/lib/attributor/types/polymorphic.rb +118 -0
- data/lib/attributor/types/regexp.rb +4 -5
- data/lib/attributor/types/string.rb +6 -7
- data/lib/attributor/types/struct.rb +8 -15
- data/lib/attributor/types/symbol.rb +3 -6
- data/lib/attributor/types/tempfile.rb +5 -6
- data/lib/attributor/types/time.rb +11 -11
- data/lib/attributor/types/uri.rb +9 -10
- data/lib/attributor/version.rb +1 -1
- data/spec/attribute_resolver_spec.rb +57 -78
- data/spec/attribute_spec.rb +174 -216
- data/spec/attributor_spec.rb +11 -15
- data/spec/dsl_compiler_spec.rb +19 -33
- data/spec/dumpable_spec.rb +6 -7
- data/spec/extras/field_selector/field_selector_spec.rb +1 -1
- data/spec/families_spec.rb +1 -3
- data/spec/hash_dsl_compiler_spec.rb +65 -74
- data/spec/spec_helper.rb +9 -3
- data/spec/support/hashes.rb +2 -3
- data/spec/support/models.rb +30 -36
- data/spec/support/polymorphics.rb +10 -0
- data/spec/type_spec.rb +38 -61
- data/spec/types/bigdecimal_spec.rb +11 -15
- data/spec/types/boolean_spec.rb +12 -39
- data/spec/types/class_spec.rb +10 -11
- data/spec/types/collection_spec.rb +72 -81
- data/spec/types/container_spec.rb +22 -26
- data/spec/types/csv_spec.rb +15 -16
- data/spec/types/date_spec.rb +16 -33
- data/spec/types/date_time_spec.rb +16 -33
- data/spec/types/file_upload_spec.rb +1 -2
- data/spec/types/float_spec.rb +7 -14
- data/spec/types/hash_spec.rb +285 -289
- data/spec/types/ids_spec.rb +5 -7
- data/spec/types/integer_spec.rb +37 -46
- data/spec/types/model_spec.rb +111 -128
- data/spec/types/polymorphic_spec.rb +134 -0
- data/spec/types/regexp_spec.rb +4 -7
- data/spec/types/string_spec.rb +17 -21
- data/spec/types/struct_spec.rb +40 -47
- data/spec/types/tempfile_spec.rb +1 -2
- data/spec/types/temporal_spec.rb +9 -0
- data/spec/types/time_spec.rb +16 -32
- data/spec/types/type_spec.rb +15 -0
- data/spec/types/uri_spec.rb +6 -7
- metadata +77 -25
data/spec/types/boolean_spec.rb
CHANGED
@@ -1,93 +1,66 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
2
2
|
|
3
3
|
describe Attributor::Boolean do
|
4
|
-
|
5
4
|
subject(:type) { Attributor::Boolean }
|
6
5
|
|
7
6
|
it 'it is not Dumpable' do
|
8
|
-
type.new.is_a?(Attributor::Dumpable).
|
7
|
+
expect(type.new.is_a?(Attributor::Dumpable)).not_to be(true)
|
9
8
|
end
|
10
9
|
|
11
10
|
context '.valid_type?' do
|
12
|
-
|
13
11
|
context 'for incoming Boolean values' do
|
14
|
-
|
15
12
|
[false, true].each do |value|
|
16
|
-
|
17
13
|
it "returns true for #{value.inspect}" do
|
18
|
-
type.valid_type?(value).
|
14
|
+
expect(type.valid_type?(value)).to be_truthy
|
19
15
|
end
|
20
|
-
|
21
16
|
end
|
22
|
-
|
23
17
|
end
|
24
18
|
|
25
19
|
context 'for incoming non-Boolean values' do
|
26
|
-
|
27
20
|
['false', 2, 1.0, Class, Object.new].each do |value|
|
28
|
-
|
29
21
|
it "returns false for #{value.inspect}" do
|
30
|
-
type.valid_type?(value).
|
22
|
+
expect(type.valid_type?(value)).to be_falsey
|
31
23
|
end
|
32
|
-
|
33
24
|
end
|
34
|
-
|
35
25
|
end
|
36
|
-
|
37
26
|
end
|
38
27
|
|
39
28
|
context '.example' do
|
40
|
-
it
|
41
|
-
[true, false].
|
29
|
+
it 'should return a valid Boolean' do
|
30
|
+
expect([true, false]).to include type.example
|
42
31
|
end
|
43
32
|
end
|
44
33
|
|
45
34
|
context '.load' do
|
46
|
-
|
47
35
|
context 'for incoming Boolean false values' do
|
48
|
-
|
49
36
|
[false, 'false', 'FALSE', '0', 0, 'f', 'F'].each do |value|
|
50
|
-
|
51
37
|
it "returns false for #{value.inspect}" do
|
52
|
-
type.load(value).
|
38
|
+
expect(type.load(value)).to be(false)
|
53
39
|
end
|
54
|
-
|
55
40
|
end
|
56
|
-
|
57
41
|
end
|
58
42
|
|
59
43
|
context 'for incoming Boolean false values' do
|
60
|
-
|
61
44
|
[true, 'true', 'TRUE', '1', 1, 't', 'T'].each do |value|
|
62
|
-
|
63
45
|
it "returns true for #{value.inspect}" do
|
64
|
-
type.load(value).
|
46
|
+
expect(type.load(value)).to be(true)
|
65
47
|
end
|
66
|
-
|
67
48
|
end
|
68
|
-
|
69
49
|
end
|
70
50
|
|
71
51
|
it 'returns nil for nil' do
|
72
|
-
type.load(nil).
|
52
|
+
expect(type.load(nil)).to be(nil)
|
73
53
|
end
|
74
54
|
|
75
55
|
context 'that are not valid Booleans' do
|
76
|
-
let(:context){
|
56
|
+
let(:context) { %w(root subattr) }
|
77
57
|
['string', 2, 1.0, Class, Object.new].each do |value|
|
78
|
-
|
79
58
|
it "raises Attributor::CoercionError for #{value.inspect}" do
|
80
|
-
expect
|
81
|
-
type.load(value,context)
|
82
|
-
|
59
|
+
expect do
|
60
|
+
type.load(value, context)
|
61
|
+
end.to raise_error(Attributor::CoercionError, /Error coercing from .+ to Attributor::Boolean.* #{context.join('.')}/)
|
83
62
|
end
|
84
|
-
|
85
63
|
end
|
86
|
-
|
87
64
|
end
|
88
|
-
|
89
65
|
end
|
90
|
-
|
91
66
|
end
|
92
|
-
|
93
|
-
|
data/spec/types/class_spec.rb
CHANGED
@@ -2,15 +2,14 @@ require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
|
2
2
|
require 'backports'
|
3
3
|
|
4
4
|
describe Attributor::Class do
|
5
|
-
|
6
5
|
subject(:type) { Attributor::Class }
|
7
6
|
|
8
7
|
it 'it is not Dumpable' do
|
9
|
-
type.new.is_a?(Attributor::Dumpable).
|
8
|
+
expect(type.new.is_a?(Attributor::Dumpable)).not_to be(true)
|
10
9
|
end
|
11
10
|
|
12
11
|
its(:native_type) { should be(::Class) }
|
13
|
-
its(:family) { should
|
12
|
+
its(:family) { should eq 'string' }
|
14
13
|
|
15
14
|
context '.example' do
|
16
15
|
its(:example) { should be_a(::String) }
|
@@ -28,8 +27,8 @@ describe Attributor::Class do
|
|
28
27
|
|
29
28
|
context 'for incoming String values' do
|
30
29
|
['Object', '::Object', '::Hash', 'Attributor::Struct'].each do |value|
|
31
|
-
it "loads
|
32
|
-
type.load(value).
|
30
|
+
it "loads #{value.inspect}" do
|
31
|
+
expect(type.load(value)).to eq(value.constantize)
|
33
32
|
end
|
34
33
|
end
|
35
34
|
end
|
@@ -37,7 +36,7 @@ describe Attributor::Class do
|
|
37
36
|
context 'for incoming Class values' do
|
38
37
|
[Object, ::Object, ::Hash, Attributor::Struct].each do |value|
|
39
38
|
it "loads '#{value}' as #{value}" do
|
40
|
-
type.load(value).
|
39
|
+
expect(type.load(value)).to eq(value)
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
@@ -47,11 +46,11 @@ describe Attributor::Class do
|
|
47
46
|
subject(:type) { Attributor::Class.of(klass) }
|
48
47
|
|
49
48
|
it "loads 'Integer' as Integer" do
|
50
|
-
type.load('Integer').
|
49
|
+
expect(type.load('Integer')).to eq(Integer)
|
51
50
|
end
|
52
51
|
|
53
|
-
it
|
54
|
-
type.load(nil).
|
52
|
+
it 'returns specified class for nil' do
|
53
|
+
expect(type.load(nil)).to be(klass)
|
55
54
|
end
|
56
55
|
|
57
56
|
it "raises when given a class that doesn't match specified class" do
|
@@ -60,11 +59,11 @@ describe Attributor::Class do
|
|
60
59
|
end
|
61
60
|
|
62
61
|
it 'returns nil for nil' do
|
63
|
-
type.load(nil).
|
62
|
+
expect(type.load(nil)).to be(nil)
|
64
63
|
end
|
65
64
|
|
66
65
|
it 'raises when given a non-String' do
|
67
|
-
expect {type.load(1)}.to raise_exception(Attributor::IncompatibleTypeError)
|
66
|
+
expect { type.load(1) }.to raise_exception(Attributor::IncompatibleTypeError)
|
68
67
|
end
|
69
68
|
end
|
70
69
|
end
|
@@ -1,16 +1,14 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
2
2
|
|
3
3
|
describe Attributor::Collection do
|
4
|
-
|
5
4
|
subject(:type) { Attributor::Collection }
|
6
5
|
|
7
6
|
context '.of' do
|
8
|
-
|
9
7
|
[Attributor::Integer, Attributor::Struct].each do |member_type|
|
10
8
|
it "returns an anonymous class with correct member_attribute of type #{member_type}" do
|
11
9
|
klass = type.of(member_type)
|
12
|
-
klass.
|
13
|
-
klass.member_type.
|
10
|
+
expect(klass).to be_a(::Class)
|
11
|
+
expect(klass.member_type).to eq member_type
|
14
12
|
end
|
15
13
|
end
|
16
14
|
|
@@ -21,13 +19,12 @@ describe Attributor::Collection do
|
|
21
19
|
#::Object
|
22
20
|
].each do |member_type|
|
23
21
|
it "raises when given invalid element type #{member_type}" do
|
24
|
-
expect {
|
22
|
+
expect { type.of(member_type) }.to raise_error(Attributor::AttributorException)
|
25
23
|
end
|
26
24
|
end
|
27
25
|
end
|
28
26
|
|
29
27
|
context '.construct' do
|
30
|
-
|
31
28
|
# context 'with a Model (or Struct) member_type' do
|
32
29
|
# let(:member_type) { Attributor::Struct }
|
33
30
|
|
@@ -52,14 +49,13 @@ describe Attributor::Collection do
|
|
52
49
|
# end
|
53
50
|
|
54
51
|
context 'with :member_options option' do
|
55
|
-
let(:element_options) { {:
|
52
|
+
let(:element_options) { { identity: 'name' } }
|
56
53
|
end
|
57
|
-
|
58
54
|
end
|
59
55
|
|
60
56
|
context '.native_type' do
|
61
|
-
it
|
62
|
-
type.native_type.
|
57
|
+
it 'returns Array' do
|
58
|
+
expect(type.native_type).to be(type)
|
63
59
|
end
|
64
60
|
end
|
65
61
|
|
@@ -72,7 +68,7 @@ describe Attributor::Collection do
|
|
72
68
|
'["alpha", 2, 3.0]'
|
73
69
|
].each do |value|
|
74
70
|
it "parses JSON string as array when incoming value is #{value.inspect}" do
|
75
|
-
type.decode_json(value).
|
71
|
+
expect(type.decode_json(value)).to eq JSON.parse(value)
|
76
72
|
end
|
77
73
|
end
|
78
74
|
end
|
@@ -86,50 +82,47 @@ describe Attributor::Collection do
|
|
86
82
|
nil
|
87
83
|
].each do |value|
|
88
84
|
it "parses JSON string as array when incoming value is #{value.inspect}" do
|
89
|
-
expect
|
85
|
+
expect do
|
90
86
|
type.decode_json(value)
|
91
|
-
|
87
|
+
end.to raise_error(Attributor::AttributorException)
|
92
88
|
end
|
93
89
|
end
|
94
90
|
end
|
95
|
-
|
96
91
|
end
|
97
92
|
|
98
93
|
context '.load' do
|
99
94
|
context 'from a Set' do
|
100
|
-
let(:values) { [1,2,3]}
|
95
|
+
let(:values) { [1, 2, 3] }
|
101
96
|
let(:value) { Set.new(values) }
|
102
97
|
it 'loads properly' do
|
103
|
-
type.load(value).
|
98
|
+
expect(type.load(value)).to match_array values
|
104
99
|
end
|
105
|
-
|
106
100
|
end
|
107
101
|
|
108
102
|
context 'with unspecified element type' do
|
109
103
|
context 'for nil values' do
|
110
104
|
it 'returns nil' do
|
111
|
-
type.load(nil).
|
105
|
+
expect(type.load(nil)).to be nil
|
112
106
|
end
|
113
107
|
end
|
114
108
|
|
115
109
|
context 'for valid values' do
|
116
110
|
[
|
117
111
|
[],
|
118
|
-
[1,2,3],
|
119
|
-
[Object.new, [1,2], nil, true]
|
112
|
+
[1, 2, 3],
|
113
|
+
[Object.new, [1, 2], nil, true]
|
120
114
|
].each do |value|
|
121
115
|
it "returns value when incoming value is #{value.inspect}" do
|
122
|
-
|
123
|
-
type.load(value).should =~ value
|
116
|
+
expect(type.load(value)).to match_array value
|
124
117
|
end
|
125
118
|
end
|
126
119
|
end
|
127
120
|
|
128
121
|
context 'for invalid values' do
|
129
|
-
let(:context){
|
122
|
+
let(:context) { %w(root subattr) }
|
130
123
|
[1, Object.new, false, true, 3.0].each do |value|
|
131
124
|
it "raises error when incoming value is #{value.inspect} (propagating the context)" do
|
132
|
-
expect { type.load(value,context).
|
125
|
+
expect { expect(type.load(value, context)).to eq value }.to raise_error(Attributor::IncompatibleTypeError, /#{context.join('.')}/)
|
133
126
|
end
|
134
127
|
end
|
135
128
|
end
|
@@ -138,15 +131,15 @@ describe Attributor::Collection do
|
|
138
131
|
context 'with Attributor::Type element type' do
|
139
132
|
context 'for valid values' do
|
140
133
|
{
|
141
|
-
Attributor::String =>
|
142
|
-
Attributor::Integer => [1,
|
143
|
-
Attributor::Float => [1.0,
|
144
|
-
Attributor::DateTime => [
|
134
|
+
Attributor::String => %w(foo bar),
|
135
|
+
Attributor::Integer => [1, '2', 3],
|
136
|
+
Attributor::Float => [1.0, '2.0', Math::PI, Math::E],
|
137
|
+
Attributor::DateTime => ['2001-02-03T04:05:06+07:00', 'Sat, 3 Feb 2001 04:05:06 +0700'],
|
145
138
|
::Chicken => [::Chicken.new, ::Chicken.new]
|
146
139
|
}.each do |member_type, value|
|
147
140
|
it "returns loaded value when member_type is #{member_type} and value is #{value.inspect}" do
|
148
|
-
expected_result = value.map {|v| member_type.load(v)}
|
149
|
-
type.of(member_type).load(value).
|
141
|
+
expected_result = value.map { |v| member_type.load(v) }
|
142
|
+
expect(type.of(member_type).load(value)).to match_array expected_result
|
150
143
|
end
|
151
144
|
end
|
152
145
|
end
|
@@ -154,17 +147,15 @@ describe Attributor::Collection do
|
|
154
147
|
context 'for invalid values' do
|
155
148
|
let(:member_type) { ::Chicken }
|
156
149
|
let(:value) { [::Turducken.example] }
|
157
|
-
it
|
158
|
-
expect
|
159
|
-
|
160
|
-
|
150
|
+
it 'raises error when incoming value is not of member_type' do
|
151
|
+
expect do
|
152
|
+
type.of(member_type).load(value)
|
153
|
+
end.to raise_error(Attributor::AttributorException, /Unknown key received/)
|
161
154
|
end
|
162
|
-
|
163
155
|
end
|
164
156
|
end
|
165
157
|
|
166
158
|
context 'with Attributor::Struct element type' do
|
167
|
-
|
168
159
|
# FIXME: Raise in all cases of empty Structs
|
169
160
|
# context 'for empty structs' do
|
170
161
|
# let(:attribute_definition) do
|
@@ -188,7 +179,7 @@ describe Attributor::Collection do
|
|
188
179
|
# it "returns value when incoming value is #{value.inspect}" do
|
189
180
|
# #pending
|
190
181
|
# expected_value = value.map {|v| empty_struct.load(v)}
|
191
|
-
# type.of(Struct).load(value).should
|
182
|
+
# type.of(Struct).load(value).should eq expected_value
|
192
183
|
# end
|
193
184
|
# end
|
194
185
|
# end
|
@@ -206,13 +197,11 @@ describe Attributor::Collection do
|
|
206
197
|
# end
|
207
198
|
# end
|
208
199
|
|
209
|
-
|
210
200
|
# end
|
211
201
|
|
212
|
-
|
213
202
|
context 'for simple structs' do
|
214
203
|
let(:attribute_definition) do
|
215
|
-
|
204
|
+
proc do
|
216
205
|
attribute :name, Attributor::String
|
217
206
|
end
|
218
207
|
end
|
@@ -221,26 +210,26 @@ describe Attributor::Collection do
|
|
221
210
|
|
222
211
|
context 'for valid struct values' do
|
223
212
|
[
|
224
|
-
[{
|
213
|
+
[{ 'name' => 'value' }, { 'name' => 'another_value' }], # Ruby hash
|
225
214
|
['{"name":"value"}'], # JSON hash
|
226
215
|
].each do |value|
|
227
216
|
it "returns value when incoming value is #{value.inspect}" do
|
228
|
-
expected_value = value.map {|v| simple_struct.load(v.clone)}
|
229
|
-
type.of(simple_struct).load(value).
|
217
|
+
expected_value = value.map { |v| simple_struct.load(v.clone) }
|
218
|
+
expect(type.of(simple_struct).load(value)).to match_array expected_value
|
230
219
|
end
|
231
220
|
end
|
232
221
|
end
|
233
222
|
|
234
223
|
context 'for invalid struct values' do
|
235
224
|
[
|
236
|
-
[{
|
225
|
+
[{ 'name' => 'value' }, { 'foo' => 'another_value' }], # Ruby hash
|
237
226
|
['{"bar":"value"}'], # JSON hash
|
238
|
-
[1,2]
|
227
|
+
[1, 2]
|
239
228
|
].each do |value|
|
240
229
|
it "raises when incoming value is #{value.inspect}" do
|
241
|
-
expect
|
230
|
+
expect do
|
242
231
|
type.of(simple_struct).load(value)
|
243
|
-
|
232
|
+
end.to raise_error(Attributor::AttributorException)
|
244
233
|
end
|
245
234
|
end
|
246
235
|
end
|
@@ -251,37 +240,36 @@ describe Attributor::Collection do
|
|
251
240
|
context '.validate' do
|
252
241
|
context 'compatible type values' do
|
253
242
|
let(:collection_members) { [1, 2, 'three'] }
|
254
|
-
let(:expected_errors) { [
|
243
|
+
let(:expected_errors) { ['error 1', 'error 2', 'error 3'] }
|
255
244
|
|
256
245
|
let(:value) { type.load(collection_members) }
|
257
246
|
|
258
247
|
before do
|
259
248
|
collection_members.zip(expected_errors).each do |member, expected_error|
|
260
|
-
type.member_attribute.
|
261
|
-
with(member,an_instance_of(Array))
|
262
|
-
and_return([expected_error])
|
249
|
+
expect(type.member_attribute).to receive(:validate)
|
250
|
+
.with(member, an_instance_of(Array)) # we don't care about the exact context here
|
251
|
+
.and_return([expected_error])
|
263
252
|
end
|
264
253
|
end
|
265
254
|
|
266
255
|
it 'validates members' do
|
267
|
-
type.validate(value).
|
256
|
+
expect(type.validate(value)).to match_array expected_errors
|
268
257
|
end
|
269
258
|
end
|
270
259
|
context 'invalid incoming types' do
|
271
260
|
subject(:type) { Attributor::Collection.of(Integer) }
|
272
261
|
it 'raise an exception' do
|
273
|
-
expect
|
262
|
+
expect do
|
274
263
|
type.validate('invalid_value')
|
275
|
-
|
264
|
+
end.to raise_error(ArgumentError, /can not validate object of type String/)
|
276
265
|
end
|
277
266
|
end
|
278
267
|
end
|
279
268
|
|
280
|
-
|
281
269
|
context '.example' do
|
282
|
-
it
|
270
|
+
it 'returns an instance of the type' do
|
283
271
|
value = type.example
|
284
|
-
value.
|
272
|
+
expect(value).to be_a(type)
|
285
273
|
end
|
286
274
|
|
287
275
|
[
|
@@ -294,46 +282,50 @@ describe Attributor::Collection do
|
|
294
282
|
].each do |member_type|
|
295
283
|
it "returns an Array of native types of #{member_type}" do
|
296
284
|
value = Attributor::Collection.of(member_type).example
|
297
|
-
value.
|
298
|
-
value.all? { |element| member_type.valid_type?(element) }.
|
285
|
+
expect(value).not_to be_empty
|
286
|
+
expect(value.all? { |element| member_type.valid_type?(element) }).to be_truthy
|
299
287
|
end
|
300
288
|
end
|
301
289
|
|
302
|
-
it
|
303
|
-
type.example(options: {size: 5}).size.
|
290
|
+
it 'returns an Array with size specified' do
|
291
|
+
expect(type.example(options: { size: 5 }).size).to eq(5)
|
304
292
|
end
|
305
293
|
|
306
|
-
it
|
294
|
+
it 'returns an Array with size within a range' do
|
307
295
|
5.times do
|
308
|
-
type.example(options: {size: (2..4)}).size.
|
296
|
+
expect(type.example(options: { size: (2..4) }).size).to be_within(1).of(3)
|
309
297
|
end
|
310
298
|
end
|
311
299
|
|
312
|
-
context
|
300
|
+
context 'passing a non array context' do
|
313
301
|
it 'still is handled correctly ' do
|
314
|
-
expect
|
315
|
-
type.example(
|
316
|
-
|
302
|
+
expect do
|
303
|
+
type.example('SimpleString')
|
304
|
+
end.to_not raise_error
|
317
305
|
end
|
318
306
|
end
|
319
|
-
|
320
307
|
end
|
321
308
|
|
322
309
|
context '.describe' do
|
323
|
-
let(:type){ Attributor::Collection.of(Attributor::String)}
|
324
|
-
let(:example){ nil }
|
325
|
-
subject(:described){ type.describe(example: example)}
|
310
|
+
let(:type) { Attributor::Collection.of(Attributor::String) }
|
311
|
+
let(:example) { nil }
|
312
|
+
subject(:described) { type.describe(example: example) }
|
326
313
|
it 'includes the member_attribute' do
|
327
|
-
described.
|
328
|
-
described
|
314
|
+
expect(described).to have_key(:member_attribute)
|
315
|
+
expect(described).not_to have_key(:example)
|
316
|
+
expect(described[:member_attribute]).not_to have_key(:example)
|
329
317
|
end
|
330
318
|
|
331
319
|
context 'with an example' do
|
332
|
-
let(:example){ type.example }
|
320
|
+
let(:example) { type.example }
|
333
321
|
it 'includes the member_attribute with an example from the first member' do
|
334
|
-
described.
|
335
|
-
described[:member_attribute].
|
336
|
-
described[:member_attribute].
|
322
|
+
expect(described).to have_key(:member_attribute)
|
323
|
+
expect(described[:member_attribute]).to have_key(:example)
|
324
|
+
expect(described[:member_attribute]).to eq(type.member_attribute.describe(example: example.first))
|
325
|
+
end
|
326
|
+
it 'includes the incoming example for the whole collection as well' do
|
327
|
+
expect(described).to have_key(:example)
|
328
|
+
expect(described[:example]).to eq(example)
|
337
329
|
end
|
338
330
|
end
|
339
331
|
end
|
@@ -342,15 +334,14 @@ describe Attributor::Collection do
|
|
342
334
|
let(:type) { Attributor::Collection.of(Cormorant) }
|
343
335
|
|
344
336
|
it 'it is Dumpable' do
|
345
|
-
type.new.is_a?(Attributor::Dumpable).
|
337
|
+
expect(type.new.is_a?(Attributor::Dumpable)).to be(true)
|
346
338
|
end
|
347
339
|
|
348
340
|
subject(:example) { type.example }
|
349
341
|
it 'dumps' do
|
350
|
-
expect
|
342
|
+
expect do
|
351
343
|
example.dump
|
352
|
-
|
344
|
+
end.to_not raise_error
|
353
345
|
end
|
354
346
|
end
|
355
|
-
|
356
347
|
end
|