requisite 0.2.0 → 0.2.1
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/CHANGES.md +3 -0
- data/lib/requisite/api_model.rb +20 -11
- data/lib/requisite/version.rb +1 -1
- data/test/requisite/api_model_test.rb +49 -42
- metadata +2 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0900379bbe4e112f2e983138cba06a3f4c399d8b
|
4
|
+
data.tar.gz: 30ee7ec731114380f827676e2e881510b860d38e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d979fd487435e6ef9b025db1d4ed6f7d09a6c897a1bf2f440bd19e4328f8b0e5ca663a2582cba8827a4bc5fcc0cfbebb959f18e3a6621ba2339228ac378bcbd
|
7
|
+
data.tar.gz: b4b83bf22163cc36b6dbd144cafbacf9f803e52076b9a969e001c167f608d387a394e8d124260379de44c5c27b55c5992a0acb0fe73e7d7151170a9f7d7e72e5
|
data/CHANGES.md
CHANGED
data/lib/requisite/api_model.rb
CHANGED
@@ -3,22 +3,31 @@ require 'json'
|
|
3
3
|
module Requisite
|
4
4
|
class ApiModel < BoundaryObject
|
5
5
|
attr_reader :model
|
6
|
-
|
6
|
+
|
7
7
|
def initialize(model={})
|
8
8
|
@model = model.kind_of?(Hash) ? Hash[model.map{ |k, v| [k.to_sym, v] }] : model
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
def convert(name)
|
12
12
|
attribute_from_model(name)
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
def convert!(name)
|
16
|
-
|
16
|
+
raise NotImplementedError.new("'#{name}' not found on model") unless model_responds_to_attribute_query?(name)
|
17
|
+
attribute_from_model(name)
|
17
18
|
end
|
18
19
|
|
19
20
|
def attribute_from_model(name)
|
20
21
|
if @model.kind_of?(Hash)
|
21
22
|
@model[name]
|
23
|
+
else
|
24
|
+
@model.send(name)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def model_responds_to_attribute_query?(name)
|
29
|
+
if @model.kind_of?(Hash)
|
30
|
+
@model[name] != nil
|
22
31
|
else
|
23
32
|
@model.send(name) if @model.respond_to?(name)
|
24
33
|
end
|
@@ -37,11 +46,11 @@ module Requisite
|
|
37
46
|
end
|
38
47
|
end
|
39
48
|
end
|
40
|
-
|
49
|
+
|
41
50
|
def to_json
|
42
51
|
to_hash.to_json
|
43
52
|
end
|
44
|
-
|
53
|
+
|
45
54
|
def parse_typed_hash(name, hash)
|
46
55
|
{}.tap do |result|
|
47
56
|
passed_hash = attribute_from_model(name)
|
@@ -52,7 +61,7 @@ module Requisite
|
|
52
61
|
end
|
53
62
|
end
|
54
63
|
end
|
55
|
-
|
64
|
+
|
56
65
|
def parse_scalar_hash(name)
|
57
66
|
{}.tap do |result|
|
58
67
|
passed_hash = attribute_from_model(name) || {}
|
@@ -62,7 +71,7 @@ module Requisite
|
|
62
71
|
end
|
63
72
|
end
|
64
73
|
end
|
65
|
-
|
74
|
+
|
66
75
|
def parse_typed_array(name, type)
|
67
76
|
[].tap do |result|
|
68
77
|
passed_array = attribute_from_model(name) || []
|
@@ -72,13 +81,13 @@ module Requisite
|
|
72
81
|
end
|
73
82
|
end
|
74
83
|
end
|
75
|
-
|
84
|
+
|
76
85
|
def with_type!(desired_type)
|
77
86
|
yield.tap do |value|
|
78
87
|
raise_bad_type_if_type_mismatch(value, desired_type) if value
|
79
88
|
end
|
80
89
|
end
|
81
|
-
|
90
|
+
|
82
91
|
def first_attribute_from_model(*attributes)
|
83
92
|
attributes.each do |attribute|
|
84
93
|
value = attribute_from_model(attribute)
|
@@ -88,7 +97,7 @@ module Requisite
|
|
88
97
|
end
|
89
98
|
nil
|
90
99
|
end
|
91
|
-
|
100
|
+
|
92
101
|
private
|
93
102
|
|
94
103
|
def preprocess_model
|
data/lib/requisite/version.rb
CHANGED
@@ -4,7 +4,7 @@ require 'test_helper'
|
|
4
4
|
module Requisite
|
5
5
|
class DummyApiModel < Requisite::ApiModel
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
describe ApiModel do
|
9
9
|
it 'creates methods from serialized_attributes block' do
|
10
10
|
DummyApiModel.serialized_attributes { attribute :a; attribute :b }
|
@@ -15,7 +15,7 @@ module Requisite
|
|
15
15
|
response.must_respond_to :a
|
16
16
|
response.must_respond_to :b
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
it 'attribute provides a default implementation of calling a hash model' do
|
20
20
|
DummyApiModel.serialized_attributes { attribute :c }
|
21
21
|
mock = {:c => 'C'}
|
@@ -24,7 +24,7 @@ module Requisite
|
|
24
24
|
end
|
25
25
|
|
26
26
|
let(:params_hash) { {:c => 'C', :num => 12} }
|
27
|
-
|
27
|
+
|
28
28
|
it 'attribute provides a default implementation of calling a model' do
|
29
29
|
DummyApiModel.serialized_attributes { attribute :c }
|
30
30
|
response = DummyApiModel.new(params_hash)
|
@@ -36,77 +36,77 @@ module Requisite
|
|
36
36
|
response = DummyApiModel.new
|
37
37
|
response.to_hash.must_equal(:c => 'see')
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
it 'ignores default if value given' do
|
41
41
|
DummyApiModel.serialized_attributes { attribute :num, default: 0 }
|
42
42
|
response = DummyApiModel.new(params_hash)
|
43
43
|
response.to_hash.must_equal(:num => 12)
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
it 'attribute can be set to stringify fields' do
|
47
47
|
DummyApiModel.serialized_attributes { attribute :num, stringify: true }
|
48
48
|
response = DummyApiModel.new(params_hash)
|
49
49
|
response.to_hash.must_equal(:num => '12')
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
it 'attribute can be set to rename fields' do
|
53
53
|
DummyApiModel.serialized_attributes { attribute :my_num, rename: :num }
|
54
54
|
response = DummyApiModel.new(params_hash)
|
55
55
|
response.to_hash.must_equal(:my_num => 12)
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
it 'attribute can assert type of a field' do
|
59
59
|
DummyApiModel.serialized_attributes { attribute :num, type: String }
|
60
60
|
response = DummyApiModel.new(params_hash)
|
61
61
|
proc { response.to_hash }.must_raise(BadTypeError)
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
it 'with_type! helper raises on mismatched type' do
|
65
65
|
model = DummyApiModel.new()
|
66
66
|
proc { model.with_type!(String) { 1 + 2 }}.must_raise(Requisite::BadTypeError)
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
it 'first_attribute_from_model helper finds first matching attriubute' do
|
70
70
|
model = DummyApiModel.new(:oh => 12, :a => nil, :b => 'B', :c => 'C')
|
71
71
|
model.first_attribute_from_model(:a, :b, :c).must_equal('B')
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
it 'attribute can assert type of a boolean field' do
|
75
75
|
DummyApiModel.serialized_attributes { attribute :truthy_val, type: Requisite::Boolean }
|
76
76
|
response = DummyApiModel.new(:truthy_val => false)
|
77
77
|
response.to_hash.must_equal(:truthy_val => false)
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
it 'attribute does not include values of nil' do
|
81
81
|
DummyApiModel.serialized_attributes { attribute :num, type: String }
|
82
82
|
response = DummyApiModel.new({:num => nil})
|
83
83
|
response.to_hash.must_equal({})
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
it 'attribute can be stringified and renamed with default fields' do
|
87
87
|
DummyApiModel.serialized_attributes { attribute :my_num, rename: :num, stringify: true, default: 22 }
|
88
88
|
response = DummyApiModel.new
|
89
89
|
response.to_hash.must_equal(:my_num => '22')
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
it 'attribute can be stringified after type check' do
|
93
93
|
DummyApiModel.serialized_attributes { attribute :num, stringify: true, type: Fixnum }
|
94
94
|
response = DummyApiModel.new(params_hash)
|
95
95
|
response.to_hash.must_equal(:num => '12')
|
96
96
|
end
|
97
|
-
|
97
|
+
|
98
98
|
it 'attribute type checks after rename' do
|
99
99
|
DummyApiModel.serialized_attributes { attribute :my_num, rename: :num, type: String }
|
100
100
|
response = DummyApiModel.new(params_hash)
|
101
101
|
proc { response.to_hash }.must_raise(BadTypeError)
|
102
102
|
end
|
103
|
-
|
103
|
+
|
104
104
|
it 'attribute can be stringified, renamed, defaulted and have type checking on a field' do
|
105
105
|
DummyApiModel.serialized_attributes { attribute :my_num, rename: :num, stringify: true, default: 22, type: String }
|
106
106
|
response = DummyApiModel.new
|
107
107
|
proc { response.to_hash }.must_raise(BadTypeError)
|
108
108
|
end
|
109
|
-
|
109
|
+
|
110
110
|
let(:invalid_params_hash) { {:d => nil} }
|
111
111
|
|
112
112
|
it "attribute! raises an error if not found on model" do
|
@@ -114,13 +114,20 @@ module Requisite
|
|
114
114
|
response = DummyApiModel.new(invalid_params_hash)
|
115
115
|
proc { response.to_hash }.must_raise(NotImplementedError, "'d' not found on model")
|
116
116
|
end
|
117
|
-
|
117
|
+
|
118
|
+
it 'attribute! does not raise an error if value on model is false' do
|
119
|
+
params_hash = {:d => false}
|
120
|
+
DummyApiModel.serialized_attributes { attribute! :d }
|
121
|
+
response = DummyApiModel.new(params_hash)
|
122
|
+
response.to_hash.must_equal({d: false})
|
123
|
+
end
|
124
|
+
|
118
125
|
it 'attribute! can be set to stringify fields' do
|
119
126
|
DummyApiModel.serialized_attributes { attribute! :num, stringify: true }
|
120
127
|
response = DummyApiModel.new(params_hash)
|
121
128
|
response.to_hash.must_equal(:num => '12')
|
122
129
|
end
|
123
|
-
|
130
|
+
|
124
131
|
it 'attribute! can be set to rename fields' do
|
125
132
|
DummyApiModel.serialized_attributes { attribute! :my_num, rename: :num }
|
126
133
|
response = DummyApiModel.new(params_hash)
|
@@ -132,7 +139,7 @@ module Requisite
|
|
132
139
|
response = DummyApiModel.new(params_hash)
|
133
140
|
response.model.must_equal(params_hash)
|
134
141
|
end
|
135
|
-
|
142
|
+
|
136
143
|
it 'sets the model from an object' do
|
137
144
|
mc = MockClass.new
|
138
145
|
mc.a = 'a'
|
@@ -142,109 +149,109 @@ module Requisite
|
|
142
149
|
response.model.must_equal(mc)
|
143
150
|
response.to_hash.must_equal(:a => 'a')
|
144
151
|
end
|
145
|
-
|
152
|
+
|
146
153
|
it 'has alias a for attribute' do
|
147
154
|
DummyApiModel.serialized_attributes { a :num }
|
148
155
|
response = DummyApiModel.new(params_hash)
|
149
156
|
response.to_hash.must_equal(:num => 12)
|
150
157
|
end
|
151
|
-
|
158
|
+
|
152
159
|
it 'has alias a! for attribute!' do
|
153
160
|
DummyApiModel.serialized_attributes { a! :num }
|
154
161
|
response = DummyApiModel.new(params_hash)
|
155
162
|
response.to_hash.must_equal(:num => 12)
|
156
163
|
end
|
157
|
-
|
164
|
+
|
158
165
|
it 'can convert to json' do
|
159
166
|
DummyApiModel.serialized_attributes { a! :num }
|
160
167
|
response = DummyApiModel.new(params_hash)
|
161
168
|
response.to_json.must_equal("{\"num\":12}")
|
162
169
|
end
|
163
|
-
|
170
|
+
|
164
171
|
it 'drops non-listed parameters' do
|
165
172
|
DummyApiModel.serialized_attributes { attribute :num }
|
166
173
|
response = DummyApiModel.new({num: 12, other: 'value'})
|
167
174
|
response.to_hash.must_equal(:num => 12)
|
168
175
|
end
|
169
|
-
|
176
|
+
|
170
177
|
describe 'with nested structures' do
|
171
|
-
|
178
|
+
|
172
179
|
describe 'with typed arrays' do
|
173
180
|
it 'allows arrays of one type' do
|
174
181
|
DummyApiModel.serialized_attributes { attribute :ids, typed_array: Fixnum }
|
175
182
|
response = DummyApiModel.new({ids: [1, 2, 3]})
|
176
183
|
response.to_hash.must_equal(:ids => [1, 2, 3])
|
177
184
|
end
|
178
|
-
|
185
|
+
|
179
186
|
it 'raises errors when array has a wrongly typed value' do
|
180
187
|
DummyApiModel.serialized_attributes { attribute :ids, typed_array: Requisite::Boolean }
|
181
188
|
response = DummyApiModel.new({ids: [true, 'value', false]})
|
182
189
|
Proc.new {response.to_hash}.must_raise(BadTypeError)
|
183
190
|
end
|
184
191
|
end
|
185
|
-
|
192
|
+
|
186
193
|
describe 'with typed nested hashes' do
|
187
194
|
it 'drops non listed parameters in nested hashes' do
|
188
195
|
DummyApiModel.serialized_attributes { attribute :data, typed_hash: { num: Numeric, bool: Requisite::Boolean } }
|
189
196
|
response = DummyApiModel.new({data: { num: 12, value: 'x', bool: true }})
|
190
197
|
response.to_hash.must_equal(:data => { :num => 12, :bool => true })
|
191
198
|
end
|
192
|
-
|
199
|
+
|
193
200
|
it 'can stringify nested hashes' do
|
194
201
|
DummyApiModel.serialized_attributes { attribute :data, typed_hash: { num: Numeric }, stringify: true }
|
195
202
|
response = DummyApiModel.new({data: { num: 12, value: 'x' }})
|
196
203
|
response.to_hash.must_equal(:data => "{:num=>12}")
|
197
204
|
end
|
198
|
-
|
205
|
+
|
199
206
|
it 'raises an error when nested hash values of the wrong type' do
|
200
207
|
DummyApiModel.serialized_attributes { attribute :data, typed_hash: { num: Numeric } }
|
201
208
|
Proc.new {DummyApiModel.new({data: { num: '12'}}).to_hash}.must_raise(BadTypeError)
|
202
209
|
end
|
203
|
-
|
210
|
+
|
204
211
|
it 'can rename param and work with nested hashes' do
|
205
212
|
DummyApiModel.serialized_attributes { attribute :my_data, typed_hash: { num: Numeric }, rename: :data }
|
206
213
|
response = DummyApiModel.new({data: { num: 12, value: 'x' }})
|
207
214
|
response.to_hash.must_equal(:my_data => { :num => 12 })
|
208
215
|
end
|
209
|
-
|
216
|
+
|
210
217
|
it 'can set a default value for a nested hash' do
|
211
218
|
DummyApiModel.serialized_attributes { attribute :data, typed_hash: { num: Numeric }, default: { num: 4 } }
|
212
219
|
response = DummyApiModel.new({data: { value: 'x' }})
|
213
220
|
response.to_hash.must_equal(:data => { :num => 4 })
|
214
221
|
end
|
215
|
-
|
222
|
+
|
216
223
|
it 'drops non listed fields with attribute!' do
|
217
224
|
DummyApiModel.serialized_attributes { attribute! :data, typed_hash: { num: Numeric } }
|
218
225
|
response = DummyApiModel.new({data: { num: 12, value: 'x' }})
|
219
226
|
response.to_hash.must_equal(:data => { :num => 12 })
|
220
227
|
end
|
221
|
-
|
228
|
+
|
222
229
|
it 'attribute! does not raise an error with missing values in hash' do
|
223
230
|
DummyApiModel.serialized_attributes { attribute! :data, typed_hash: { num: Numeric } }
|
224
231
|
response = DummyApiModel.new({data: { value: 'x' }})
|
225
232
|
response.to_hash.must_equal(:data => { })
|
226
233
|
end
|
227
234
|
end
|
228
|
-
|
235
|
+
|
229
236
|
describe 'with scalar only nested hashes' do
|
230
237
|
it 'should parse scalar hashes permitting anything scalar' do
|
231
238
|
DummyApiModel.serialized_attributes { attribute :data, scalar_hash: true }
|
232
239
|
response = DummyApiModel.new({data: { num: 12, value: 'x', :truthy => false }})
|
233
240
|
response.to_hash.must_equal(:data => { :num => 12, :value => 'x', :truthy => false })
|
234
241
|
end
|
235
|
-
|
242
|
+
|
236
243
|
it 'should parse a renamed scalar hash' do
|
237
244
|
DummyApiModel.serialized_attributes { attribute :my_data, scalar_hash: true, rename: :data }
|
238
245
|
response = DummyApiModel.new({data: { num: 12, value: 'x' }})
|
239
246
|
response.to_hash.must_equal(:my_data => { :num => 12, :value => 'x' })
|
240
247
|
end
|
241
|
-
|
248
|
+
|
242
249
|
it 'should stringify a scalar hash' do
|
243
250
|
DummyApiModel.serialized_attributes { attribute :data, scalar_hash: true, stringify: true }
|
244
251
|
response = DummyApiModel.new({data: { num: 12, value: 'x' }})
|
245
252
|
response.to_hash.must_equal(:data => "{:num=>12, :value=>\"x\"}")
|
246
253
|
end
|
247
|
-
|
254
|
+
|
248
255
|
it 'should parse scalar hashes permitting anything scalar with object' do
|
249
256
|
mc = MockClass.new
|
250
257
|
mc.a = 'a'
|
@@ -253,13 +260,13 @@ module Requisite
|
|
253
260
|
response = DummyApiModel.new(mc)
|
254
261
|
response.to_hash.must_equal(:b => { :num => 12, :value => 'x' })
|
255
262
|
end
|
256
|
-
|
263
|
+
|
257
264
|
it 'should fail to parse scalar hashes when non scalar values present' do
|
258
265
|
DummyApiModel.serialized_attributes { attribute :data, scalar_hash: true }
|
259
266
|
Proc.new { DummyApiModel.new({data: { num: 12, value: { nested: 'value' } }}).to_hash}.must_raise(BadTypeError)
|
260
267
|
Proc.new { DummyApiModel.new({data: { num: 12, value: ['array value'] }}).to_hash}.must_raise(BadTypeError)
|
261
268
|
end
|
262
|
-
|
269
|
+
|
263
270
|
it 'should fail to parse scalar hashes permitting anything scalar with object' do
|
264
271
|
mc = MockClass.new
|
265
272
|
mc.a = 'a'
|
@@ -268,19 +275,19 @@ module Requisite
|
|
268
275
|
response = DummyApiModel.new(mc)
|
269
276
|
Proc.new { response.to_hash }.must_raise(BadTypeError)
|
270
277
|
end
|
271
|
-
|
278
|
+
|
272
279
|
it 'can set a default value for a scalar hash' do
|
273
280
|
DummyApiModel.serialized_attributes { attribute :data, scalar_hash: true, default: { num: 9, value: 'y' } }
|
274
281
|
response = DummyApiModel.new({data: { }})
|
275
282
|
response.to_hash.must_equal(:data => { :num => 9, :value => 'y' })
|
276
283
|
end
|
277
|
-
|
284
|
+
|
278
285
|
it 'doesnt raise with attribute! when an empty hash passed' do
|
279
286
|
DummyApiModel.serialized_attributes { attribute! :data, scalar_hash: true }
|
280
287
|
response = DummyApiModel.new({data: {}})
|
281
288
|
response.to_hash.must_equal(:data => {})
|
282
289
|
end
|
283
|
-
|
290
|
+
|
284
291
|
it 'raises with attribute! when nil is passed' do
|
285
292
|
DummyApiModel.serialized_attributes { attribute! :data, scalar_hash: true }
|
286
293
|
response = DummyApiModel.new({data: nil})
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: requisite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Osler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-03-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -79,4 +79,3 @@ test_files:
|
|
79
79
|
- test/requisite/api_model_test.rb
|
80
80
|
- test/requisite/api_user_test.rb
|
81
81
|
- test/test_helper.rb
|
82
|
-
has_rdoc:
|