attributor 5.4 → 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/CHANGELOG.md +17 -0
- data/lib/attributor/attribute.rb +101 -84
- data/lib/attributor/extras/field_selector.rb +4 -0
- data/lib/attributor/families/numeric.rb +19 -6
- data/lib/attributor/families/temporal.rb +16 -9
- data/lib/attributor/hash_dsl_compiler.rb +6 -5
- data/lib/attributor/type.rb +26 -3
- data/lib/attributor/types/bigdecimal.rb +6 -1
- data/lib/attributor/types/boolean.rb +5 -0
- data/lib/attributor/types/collection.rb +19 -0
- data/lib/attributor/types/csv.rb +4 -0
- data/lib/attributor/types/date.rb +7 -1
- data/lib/attributor/types/date_time.rb +7 -1
- data/lib/attributor/types/float.rb +4 -3
- data/lib/attributor/types/hash.rb +86 -23
- data/lib/attributor/types/integer.rb +7 -1
- data/lib/attributor/types/model.rb +9 -21
- data/lib/attributor/types/object.rb +5 -0
- data/lib/attributor/types/polymorphic.rb +0 -1
- data/lib/attributor/types/string.rb +19 -0
- data/lib/attributor/types/symbol.rb +5 -0
- data/lib/attributor/types/tempfile.rb +4 -0
- data/lib/attributor/types/time.rb +6 -2
- data/lib/attributor/types/uri.rb +8 -0
- data/lib/attributor/version.rb +1 -1
- data/lib/attributor.rb +3 -7
- data/spec/attribute_spec.rb +148 -124
- data/spec/extras/field_selector/field_selector_spec.rb +9 -0
- data/spec/hash_dsl_compiler_spec.rb +5 -5
- data/spec/spec_helper.rb +0 -2
- data/spec/support/integers.rb +7 -0
- data/spec/support/models.rb +7 -7
- data/spec/types/bigdecimal_spec.rb +8 -0
- data/spec/types/boolean_spec.rb +10 -0
- data/spec/types/collection_spec.rb +16 -0
- data/spec/types/date_spec.rb +9 -0
- data/spec/types/date_time_spec.rb +9 -0
- data/spec/types/float_spec.rb +8 -0
- data/spec/types/hash_spec.rb +181 -22
- data/spec/types/integer_spec.rb +9 -0
- data/spec/types/model_spec.rb +7 -1
- data/spec/types/string_spec.rb +10 -0
- data/spec/types/temporal_spec.rb +5 -1
- data/spec/types/time_spec.rb +9 -0
- data/spec/types/uri_spec.rb +9 -0
- metadata +5 -6
- data/lib/attributor/attribute_resolver.rb +0 -111
- data/spec/attribute_resolver_spec.rb +0 -237
@@ -1,237 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
|
-
|
3
|
-
describe Attributor::AttributeResolver do
|
4
|
-
let(:value) { /\w+/.gen }
|
5
|
-
|
6
|
-
context 'registering and querying simple values' do
|
7
|
-
let(:name) { 'string_value' }
|
8
|
-
before { subject.register(name, value) }
|
9
|
-
|
10
|
-
it 'works' do
|
11
|
-
expect(subject.query(name)).to be value
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
context 'querying and registering nested values' do
|
16
|
-
let(:one) { double(two: value) }
|
17
|
-
let(:key) { 'one.two' }
|
18
|
-
before { subject.register('one', one) }
|
19
|
-
|
20
|
-
it 'works' do
|
21
|
-
expect(subject.query(key)).to be value
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
context 'querying nested values from models' do
|
26
|
-
let(:instance) { double('instance', ssh_key: ssh_key) }
|
27
|
-
let(:ssh_key) { double('ssh_key', name: value) }
|
28
|
-
let(:key) { 'instance.ssh_key.name' }
|
29
|
-
|
30
|
-
before { subject.register('instance', instance) }
|
31
|
-
|
32
|
-
it 'works' do
|
33
|
-
expect(subject.query('instance')).to be instance
|
34
|
-
expect(subject.query('instance.ssh_key')).to be ssh_key
|
35
|
-
expect(subject.query(key)).to be value
|
36
|
-
end
|
37
|
-
|
38
|
-
context 'with a prefix' do
|
39
|
-
let(:key) { 'name' }
|
40
|
-
let(:prefix) { '$.instance.ssh_key' }
|
41
|
-
let(:value) { 'some_name' }
|
42
|
-
it 'works' do
|
43
|
-
expect(subject.query(key, prefix)).to be(value)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
context 'querying values that do not exist' do
|
49
|
-
context 'for a straight key' do
|
50
|
-
let(:key) { 'missing' }
|
51
|
-
it 'returns nil' do
|
52
|
-
expect(subject.query(key)).to be_nil
|
53
|
-
end
|
54
|
-
end
|
55
|
-
context 'for a nested key' do
|
56
|
-
let(:key) { 'nested.missing' }
|
57
|
-
it 'returns nil' do
|
58
|
-
expect(subject.query(key)).to be_nil
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
context 'querying collection indices from models' do
|
64
|
-
let(:instances) { [instance1, instance2] }
|
65
|
-
let(:instance1) { double('instance1', ssh_key: ssh_key1) }
|
66
|
-
let(:instance2) { double('instance2', ssh_key: ssh_key2) }
|
67
|
-
let(:ssh_key1) { double('ssh_key', name: value) }
|
68
|
-
let(:ssh_key2) { double('ssh_key', name: 'second') }
|
69
|
-
let(:args) { [path, prefix].compact }
|
70
|
-
|
71
|
-
before { subject.register('instances', instances) }
|
72
|
-
|
73
|
-
it 'resolves the index to the correct member of the collection' do
|
74
|
-
expect(subject.query('instances')).to be instances
|
75
|
-
expect(subject.query('instances.at(1).ssh_key')).to be ssh_key2
|
76
|
-
expect(subject.query('instances.at(0).ssh_key.name')).to be value
|
77
|
-
end
|
78
|
-
|
79
|
-
it 'returns nil for index out of range' do
|
80
|
-
expect(subject.query('instances.at(2)')).to be(nil)
|
81
|
-
expect(subject.query('instances.at(-1)')).to be(nil)
|
82
|
-
end
|
83
|
-
|
84
|
-
context 'with a prefix' do
|
85
|
-
let(:key) { 'name' }
|
86
|
-
let(:prefix) { '$.instances.at(0).ssh_key' }
|
87
|
-
let(:value) { 'some_name' }
|
88
|
-
|
89
|
-
it 'resolves the index to the correct member of the collection' do
|
90
|
-
expect(subject.query(key, prefix)).to be(value)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
context 'checking attribute conditions' do
|
96
|
-
let(:key) { 'instance.ssh_key.name' }
|
97
|
-
let(:ssh_key) { double('ssh_key', name: value) }
|
98
|
-
let(:instance_id) { 123 }
|
99
|
-
let(:instance) { double('instance', ssh_key: ssh_key, id: instance_id) }
|
100
|
-
|
101
|
-
let(:context) { '$' }
|
102
|
-
|
103
|
-
before { subject.register('instance', instance) }
|
104
|
-
|
105
|
-
let(:present_key) { key }
|
106
|
-
let(:missing_key) { 'instance.ssh_key.something_else' }
|
107
|
-
|
108
|
-
context 'with no condition' do
|
109
|
-
let(:condition) { nil }
|
110
|
-
before { expect(ssh_key).to receive(:something_else).and_return(nil) }
|
111
|
-
it 'works' do
|
112
|
-
expect(subject.check(context, present_key, condition)).to be true
|
113
|
-
expect(subject.check(context, missing_key, condition)).to be false
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
context 'with a string condition' do
|
118
|
-
let(:passing_condition) { value }
|
119
|
-
let(:failing_condition) { /\w+/.gen }
|
120
|
-
|
121
|
-
it 'works' do
|
122
|
-
expect(subject.check(context, key, passing_condition)).to be true
|
123
|
-
expect(subject.check(context, key, failing_condition)).to be false
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
context 'with a regex condition' do
|
128
|
-
let(:passing_condition) { /\w+/ }
|
129
|
-
let(:failing_condition) { /\d+/ }
|
130
|
-
|
131
|
-
it 'works' do
|
132
|
-
expect(subject.check(context, key, passing_condition)).to be true
|
133
|
-
expect(subject.check(context, key, failing_condition)).to be false
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
context 'with an integer condition' do
|
138
|
-
let(:key) { 'instance.id' }
|
139
|
-
let(:passing_condition) { instance_id }
|
140
|
-
let(:failing_condition) { /\w+/.gen }
|
141
|
-
|
142
|
-
it 'works' do
|
143
|
-
expect(subject.check(context, key, passing_condition)).to be true
|
144
|
-
expect(subject.check(context, key, failing_condition)).to be false
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
skip 'with a hash condition' do
|
149
|
-
end
|
150
|
-
|
151
|
-
context 'with a proc condition' do
|
152
|
-
let(:passing_condition) { proc { |test_value| test_value == value } }
|
153
|
-
let(:failing_condition) { proc { |test_value| test_value != value } }
|
154
|
-
|
155
|
-
it 'works' do
|
156
|
-
expect(subject.check(context, key, passing_condition)).to eq(true)
|
157
|
-
expect(subject.check(context, key, failing_condition)).to eq(false)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
context 'with an unsupported condition type' do
|
162
|
-
let(:condition) { double('weird condition type') }
|
163
|
-
it 'raises an error' do
|
164
|
-
expect { subject.check(context, present_key, condition) }.to raise_error(Attributor::AttributorException)
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
context 'with a condition that asserts something IS nil' do
|
169
|
-
let(:ssh_key) { double('ssh_key', name: nil) }
|
170
|
-
it 'can be done using the almighty Proc' do
|
171
|
-
cond = proc { |value| !value.nil? }
|
172
|
-
expect(subject.check(context, key, cond)).to be false
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
context 'with a relative path' do
|
177
|
-
let(:context) { '$.instance.ssh_key' }
|
178
|
-
let(:key) { 'name' }
|
179
|
-
|
180
|
-
it 'works' do
|
181
|
-
expect(subject.check(context, key, value)).to be true
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
# context 'with context stuff...' do
|
187
|
-
|
188
|
-
# let(:ssh_key) { double("ssh_key", name:value) }
|
189
|
-
# let(:instance) { double("instance", ssh_key:ssh_key) }
|
190
|
-
|
191
|
-
# let(:key) { "ssh_key.name" }
|
192
|
-
# let(:key) { "$.payload" }
|
193
|
-
# let(:key) { "ssh_key.name" } # no $ == current object
|
194
|
-
# let(:key) { "@.ssh_key" } # @ is current object
|
195
|
-
|
196
|
-
# before { subject.register('instance', instance) }
|
197
|
-
|
198
|
-
# it 'works?' do
|
199
|
-
# # check dependency for 'instance'
|
200
|
-
# resolver.with 'instance' do |res|
|
201
|
-
# res.check(key)
|
202
|
-
# '$.payload'
|
203
|
-
# end
|
204
|
-
|
205
|
-
# end
|
206
|
-
|
207
|
-
# end
|
208
|
-
|
209
|
-
# context 'integration with attributes that have sub-attributes' do
|
210
|
-
# when you start to parse... do you set the root in the resolver?
|
211
|
-
# end
|
212
|
-
#
|
213
|
-
# context 'actually using the thing' do
|
214
|
-
|
215
|
-
# # we'll always want to add... right? never really remove?
|
216
|
-
# # at least not remove for the duration of a given resolver...
|
217
|
-
# # which will last for one request.
|
218
|
-
# #
|
219
|
-
# # could the resolver be an identity-map of sorts for the request?
|
220
|
-
# # how much overlap is there in there?
|
221
|
-
# #
|
222
|
-
# #
|
223
|
-
|
224
|
-
# it 'is really actually quite useful' do
|
225
|
-
# #attribute = Attributor::Attribute.new ::String, required_if: { "instance.ssh_key.name" : Proc.new { |value| value.nil? } }
|
226
|
-
|
227
|
-
# resolver = Attributor::AttributeResolver.new
|
228
|
-
|
229
|
-
# resolver.register '$.parsed_params', parsed_params
|
230
|
-
# resolver.register '$.payload', payload
|
231
|
-
|
232
|
-
# resolver.query '$.parsed_params.account_id'
|
233
|
-
|
234
|
-
# end
|
235
|
-
|
236
|
-
# end
|
237
|
-
end
|