compel 0.1.3 → 0.2.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/Gemfile +7 -0
- data/README.md +65 -54
- data/lib/compel/builder/boolean.rb +13 -0
- data/lib/compel/builder/common.rb +24 -0
- data/lib/compel/builder/common_value.rb +34 -0
- data/lib/compel/builder/date.rb +23 -0
- data/lib/compel/builder/datetime.rb +23 -0
- data/lib/compel/builder/float.rb +15 -0
- data/lib/compel/builder/hash.rb +22 -0
- data/lib/compel/builder/integer.rb +15 -0
- data/lib/compel/builder/json.rb +13 -0
- data/lib/compel/builder/methods.rb +60 -0
- data/lib/compel/builder/schema.rb +27 -0
- data/lib/compel/builder/string.rb +30 -0
- data/lib/compel/builder/time.rb +23 -0
- data/lib/compel/coercion/boolean.rb +1 -1
- data/lib/compel/coercion/date.rb +19 -2
- data/lib/compel/coercion/datetime.rb +19 -2
- data/lib/compel/coercion/float.rb +1 -1
- data/lib/compel/coercion/hash.rb +1 -1
- data/lib/compel/coercion/integer.rb +1 -1
- data/lib/compel/coercion/json.rb +1 -1
- data/lib/compel/coercion/regexp.rb +17 -0
- data/lib/compel/coercion/string.rb +1 -1
- data/lib/compel/coercion/time.rb +19 -2
- data/lib/compel/coercion/type.rb +0 -13
- data/lib/compel/coercion.rb +8 -10
- data/lib/compel/contract.rb +18 -62
- data/lib/compel/exceptions/invalid_hash_error.rb +9 -0
- data/lib/compel/exceptions/type_error.rb +7 -0
- data/lib/compel/exceptions/validation_error.rb +7 -0
- data/lib/compel/validation.rb +36 -50
- data/lib/compel/validators/base.rb +19 -0
- data/lib/compel/validators/hash_validator.rb +51 -0
- data/lib/compel/validators/type_validator.rb +30 -0
- data/lib/compel/version.rb +1 -1
- data/lib/compel.rb +16 -11
- data/spec/compel/builder_spec.rb +226 -0
- data/spec/compel/coercion_spec.rb +85 -18
- data/spec/compel/compel_spec.rb +368 -160
- data/spec/compel/sinatra_integration_spec.rb +73 -0
- data/spec/compel/validation_spec.rb +122 -8
- data/spec/spec_helper.rb +19 -0
- data/spec/support/sinatra_app.rb +43 -0
- metadata +28 -10
- data/lib/compel/invalid_params_error.rb +0 -9
- data/lib/compel/param.rb +0 -46
- data/lib/compel/param_type_error.rb +0 -7
- data/lib/compel/param_validation_error.rb +0 -7
- data/spec/compel/contract_spec.rb +0 -36
- data/spec/compel/param_spec.rb +0 -25
@@ -0,0 +1,226 @@
|
|
1
|
+
describe Compel::Builder do
|
2
|
+
|
3
|
+
context 'Schema' do
|
4
|
+
|
5
|
+
subject(:builder) { Compel::Builder::String.new }
|
6
|
+
|
7
|
+
it 'shoudl' do
|
8
|
+
object = {
|
9
|
+
first_name: 'Joaquim',
|
10
|
+
birth_date: '1989-0',
|
11
|
+
address: {
|
12
|
+
line_one: 'Lisboa',
|
13
|
+
post_code: '1100',
|
14
|
+
country_code: 'PT'
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
schema = Compel.hash.keys({
|
19
|
+
first_name: Compel.string.required,
|
20
|
+
last_name: Compel.string.required,
|
21
|
+
birth_date: Compel.date.iso8601,
|
22
|
+
address: Compel.hash.keys({
|
23
|
+
line_one: Compel.string.required,
|
24
|
+
line_two: Compel.string.default('-'),
|
25
|
+
post_code: Compel.string.format(/^\d{4}-\d{3}$/).required,
|
26
|
+
country_code: Compel.string.in(['PT', 'GB']).default('PT')
|
27
|
+
})
|
28
|
+
})
|
29
|
+
|
30
|
+
result = Compel.run(object, schema)
|
31
|
+
|
32
|
+
expect(result).to \
|
33
|
+
eq({
|
34
|
+
"first_name" => "Joaquim",
|
35
|
+
"birth_date" => "1989-0",
|
36
|
+
"address" => {
|
37
|
+
"line_one" => "Lisboa",
|
38
|
+
"post_code" => "1100",
|
39
|
+
"country_code" => "PT",
|
40
|
+
"line_two" => "-"
|
41
|
+
},
|
42
|
+
"errors" => {
|
43
|
+
"last_name" => ["is required"],
|
44
|
+
"birth_date" => ["'1989-0' is not a parsable date with format: %Y-%m-%d"],
|
45
|
+
"address" => {
|
46
|
+
"post_code" => ["must match format ^\\d{4}-\\d{3}$"]
|
47
|
+
}
|
48
|
+
}
|
49
|
+
})
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should build new Schema for givin type' do
|
53
|
+
expect(builder.type).to be(Compel::Coercion::String)
|
54
|
+
expect(builder.options.keys).to eq([])
|
55
|
+
expect(builder.required?).to be false
|
56
|
+
expect(builder.default_value).to be nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should build Schema' do
|
60
|
+
schema = Compel.hash.keys({
|
61
|
+
a: Compel.float,
|
62
|
+
b: Compel.string,
|
63
|
+
c: Compel.hash.keys({
|
64
|
+
cc: Compel.integer.length(1)
|
65
|
+
}),
|
66
|
+
d: Compel.json,
|
67
|
+
e: Compel.time,
|
68
|
+
f: Compel.datetime,
|
69
|
+
g: Compel.date,
|
70
|
+
h: Compel.integer
|
71
|
+
})
|
72
|
+
|
73
|
+
keys_schemas = schema.options[:keys]
|
74
|
+
|
75
|
+
expect(keys_schemas.a.type).to be Compel::Coercion::Float
|
76
|
+
expect(keys_schemas.b.type).to be Compel::Coercion::String
|
77
|
+
expect(keys_schemas.c.type).to be Compel::Coercion::Hash
|
78
|
+
expect(keys_schemas.d.type).to be Compel::Coercion::JSON
|
79
|
+
expect(keys_schemas.e.type).to be Compel::Coercion::Time
|
80
|
+
expect(keys_schemas.f.type).to be Compel::Coercion::DateTime
|
81
|
+
expect(keys_schemas.g.type).to be Compel::Coercion::Date
|
82
|
+
expect(keys_schemas.h.type).to be Compel::Coercion::Integer
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should validate hash object from schema' do
|
86
|
+
schema = Compel.hash.keys({
|
87
|
+
a: Compel.float.required
|
88
|
+
})
|
89
|
+
|
90
|
+
expect(schema.validate({ a: nil }).errors.a).to \
|
91
|
+
include('is required')
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'Builder::CommonValue' do
|
95
|
+
|
96
|
+
context '#in, #range, #min, #max' do
|
97
|
+
|
98
|
+
it 'should have value' do
|
99
|
+
[:in, :range, :min, :max].each do |method|
|
100
|
+
builder.send(method, "#{method}")
|
101
|
+
expect(builder.options[method]).to eq("#{method}")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'Builder::Common' do
|
110
|
+
|
111
|
+
context '#is, #default' do
|
112
|
+
|
113
|
+
it 'should have value' do
|
114
|
+
[:is, :default].each do |method|
|
115
|
+
builder.send(method, "#{method}")
|
116
|
+
expect(builder.options[method]).to eq("#{method}")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
context '#required' do
|
123
|
+
|
124
|
+
it 'should be false' do
|
125
|
+
expect(builder.required?).to be false
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should be true' do
|
129
|
+
builder.required
|
130
|
+
|
131
|
+
expect(builder.required?).to be true
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
context '#length' do
|
137
|
+
|
138
|
+
it 'should have value' do
|
139
|
+
builder.length(5)
|
140
|
+
|
141
|
+
expect(builder.options[:length]).to be 5
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'should raise exception for invalid type' do
|
145
|
+
expect { builder.length('abc') }.to \
|
146
|
+
raise_error Compel::TypeError, "'abc' is not a valid Integer"
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'Date' do
|
154
|
+
|
155
|
+
subject(:builder) { Compel::Builder::Date.new }
|
156
|
+
|
157
|
+
context '#format' do
|
158
|
+
|
159
|
+
it 'should have value' do
|
160
|
+
builder.format('%d-%m-%Y')
|
161
|
+
|
162
|
+
expect(builder.options[:format]).to eq('%d-%m-%Y')
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'should have value' do
|
166
|
+
builder.iso8601
|
167
|
+
|
168
|
+
expect(builder.options[:format]).to eq('%Y-%m-%d')
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
context 'String' do
|
176
|
+
|
177
|
+
context '#format' do
|
178
|
+
|
179
|
+
it 'should raise exception for invalid type' do
|
180
|
+
expect { builder.format('abc') }.to \
|
181
|
+
raise_error Compel::TypeError, "'abc' is not a valid Regexp"
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'should have value' do
|
185
|
+
builder.format(/1/)
|
186
|
+
|
187
|
+
expect(builder.options[:format]).to eq(/1/)
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
context '#min_length' do
|
193
|
+
|
194
|
+
it 'should raise exception for invalid type' do
|
195
|
+
expect { builder.min_length('a') }.to \
|
196
|
+
raise_error Compel::TypeError, "'a' is not a valid Integer"
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'should have value' do
|
200
|
+
builder.min_length(4)
|
201
|
+
|
202
|
+
expect(builder.options[:min_length]).to eq(4)
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
context '#max_length' do
|
208
|
+
|
209
|
+
it 'should raise exception for invalid type' do
|
210
|
+
expect { builder.max_length('a') }.to \
|
211
|
+
raise_error Compel::TypeError, "'a' is not a valid Integer"
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'should have value' do
|
215
|
+
builder.max_length(10)
|
216
|
+
|
217
|
+
expect(builder.options[:max_length]).to eq(10)
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
225
|
+
|
226
|
+
end
|
@@ -23,7 +23,7 @@ describe Compel::Coercion do
|
|
23
23
|
expect(Compel::Coercion.valid?('123abc', Integer)).to eq(false)
|
24
24
|
|
25
25
|
expect { Compel::Coercion.coerce!('123abc', Integer) }.to \
|
26
|
-
raise_error Compel::
|
26
|
+
raise_error Compel::TypeError, "'123abc' is not a valid Integer"
|
27
27
|
end
|
28
28
|
|
29
29
|
end
|
@@ -40,7 +40,7 @@ describe Compel::Coercion do
|
|
40
40
|
expect(Compel::Coercion.valid?('1.a233', Float)).to eq(false)
|
41
41
|
|
42
42
|
expect { Compel::Coercion.coerce!('1.a233', Float) }.to \
|
43
|
-
raise_error Compel::
|
43
|
+
raise_error Compel::TypeError, "'1.a233' is not a valid Float"
|
44
44
|
end
|
45
45
|
|
46
46
|
end
|
@@ -59,39 +59,89 @@ describe Compel::Coercion do
|
|
59
59
|
expect(Compel::Coercion.valid?(value, String)).to eq(false)
|
60
60
|
|
61
61
|
expect { Compel::Coercion.coerce!(value, String) }.to \
|
62
|
-
raise_error Compel::
|
62
|
+
raise_error Compel::TypeError, "'#{value}' is not a valid String"
|
63
63
|
end
|
64
64
|
|
65
65
|
end
|
66
66
|
|
67
67
|
context 'Date' do
|
68
68
|
|
69
|
-
it 'should coerce' do
|
69
|
+
it 'should coerce with default format' do
|
70
70
|
value = Compel::Coercion.coerce!('2015-12-22', Date)
|
71
71
|
|
72
72
|
expect(value).to eq(Date.parse('2015-12-22'))
|
73
73
|
end
|
74
74
|
|
75
|
+
it 'should coerce with format' do
|
76
|
+
value = Compel::Coercion.coerce!('22-12-2015', Date, { format: '%d-%m-%Y'})
|
77
|
+
|
78
|
+
expect(value).to eq(Date.strptime('22-12-2015', '%d-%m-%Y'))
|
79
|
+
end
|
80
|
+
|
75
81
|
it 'should not coerce' do
|
76
82
|
value = '2015-0'
|
77
83
|
|
78
84
|
expect(Compel::Coercion.valid?(value, Date)).to eq(false)
|
79
85
|
|
80
86
|
expect { Compel::Coercion.coerce!(value, Date) }.to \
|
81
|
-
raise_error
|
87
|
+
raise_error \
|
88
|
+
Compel::TypeError,
|
89
|
+
"'#{value}' is not a parsable date with format: %Y-%m-%d"
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should not coerce 1' do
|
93
|
+
default_format = '%Y-%m-%d'
|
94
|
+
value = '22-12-2015'
|
95
|
+
|
96
|
+
expect { Compel::Coercion.coerce!(value, Date) }.to \
|
97
|
+
raise_error \
|
98
|
+
Compel::TypeError,
|
99
|
+
"'#{value}' is not a parsable date with format: #{default_format}"
|
82
100
|
end
|
83
101
|
|
84
102
|
end
|
85
103
|
|
86
|
-
context 'DateTime' do
|
104
|
+
context 'DateTime & Time' do
|
87
105
|
|
88
106
|
it 'should coerce' do
|
89
|
-
|
107
|
+
[DateTime, Time].each do |time_klass|
|
108
|
+
value = Compel::Coercion.coerce!('2015-12-22', time_klass, format: '%Y-%m-%d')
|
109
|
+
|
110
|
+
expect(value).to be_a time_klass
|
111
|
+
expect(value.year).to eq(2015)
|
112
|
+
expect(value.month).to eq(12)
|
113
|
+
expect(value.day).to eq(22)
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should coerce iso8601 format' do
|
119
|
+
[DateTime, Time].each do |time_klass|
|
120
|
+
value = Compel::Coercion.coerce!('2015-12-22T09:30:10', time_klass)
|
121
|
+
|
122
|
+
expect(value).to be_a time_klass
|
123
|
+
expect(value.year).to eq(2015)
|
124
|
+
expect(value.month).to eq(12)
|
125
|
+
expect(value.day).to eq(22)
|
126
|
+
expect(value.hour).to eq(9)
|
127
|
+
expect(value.min).to eq(30)
|
128
|
+
expect(value.sec).to eq(10)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'should not coerce' do
|
133
|
+
default_format = '%FT%T'
|
134
|
+
value = '22-12-2015'
|
135
|
+
|
136
|
+
[DateTime, Time].each do |time_klass|
|
137
|
+
type_down_cased = "#{time_klass}".downcase
|
138
|
+
|
139
|
+
expect { Compel::Coercion.coerce!('22-12-2015', time_klass) }.to \
|
140
|
+
raise_error \
|
141
|
+
Compel::TypeError,
|
142
|
+
"'#{value}' is not a parsable #{type_down_cased} with format: #{default_format}"
|
143
|
+
end
|
90
144
|
|
91
|
-
expect(value).to be_a DateTime
|
92
|
-
expect(value.year).to eq(2015)
|
93
|
-
expect(value.month).to eq(12)
|
94
|
-
expect(value.day).to eq(22)
|
95
145
|
end
|
96
146
|
|
97
147
|
end
|
@@ -136,17 +186,17 @@ describe Compel::Coercion do
|
|
136
186
|
|
137
187
|
it 'should not coerce' do
|
138
188
|
expect { Compel::Coercion.coerce!(123, Hash) }.to \
|
139
|
-
raise_error Compel::
|
189
|
+
raise_error Compel::TypeError, "'123' is not a valid Hash"
|
140
190
|
end
|
141
191
|
|
142
192
|
it 'should not coerce 1' do
|
143
193
|
expect { Compel::Coercion.coerce!('hash', Hash) }.to \
|
144
|
-
raise_error Compel::
|
194
|
+
raise_error Compel::TypeError, "'hash' is not a valid Hash"
|
145
195
|
end
|
146
196
|
|
147
197
|
it 'should not coerce 2' do
|
148
198
|
expect { Compel::Coercion.coerce!(['hash'], Hash) }.to \
|
149
|
-
raise_error Compel::
|
199
|
+
raise_error Compel::TypeError, "'[\"hash\"]' is not a valid Hash"
|
150
200
|
end
|
151
201
|
|
152
202
|
end
|
@@ -167,18 +217,35 @@ describe Compel::Coercion do
|
|
167
217
|
|
168
218
|
context 'Boolean' do
|
169
219
|
|
170
|
-
it 'should coerce' do
|
171
|
-
value = Compel::Coercion.coerce!('f', Compel::Boolean)
|
220
|
+
it 'should coerce false' do
|
221
|
+
value = Compel::Coercion.coerce!('f', Compel::Coercion::Boolean)
|
172
222
|
|
173
223
|
expect(value).to eq(false)
|
174
224
|
end
|
175
225
|
|
176
|
-
it 'should coerce' do
|
177
|
-
value = Compel::Coercion.coerce!('0', Compel::Boolean)
|
226
|
+
it 'should coerce false 1' do
|
227
|
+
value = Compel::Coercion.coerce!('0', Compel::Coercion::Boolean)
|
178
228
|
|
179
229
|
expect(value).to eq(false)
|
180
230
|
end
|
181
231
|
|
232
|
+
it 'should coerce true' do
|
233
|
+
value = Compel::Coercion.coerce!('t', Compel::Coercion::Boolean)
|
234
|
+
|
235
|
+
expect(value).to eq(true)
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'should coerce true 1' do
|
239
|
+
value = Compel::Coercion.coerce!('true', Compel::Coercion::Boolean)
|
240
|
+
|
241
|
+
expect(value).to eq(true)
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'should not coerce' do
|
245
|
+
expect{ Compel::Coercion.coerce!('trye', Compel::Coercion::Boolean) }.to \
|
246
|
+
raise_error Compel::TypeError, "'trye' is not a valid Boolean"
|
247
|
+
end
|
248
|
+
|
182
249
|
end
|
183
250
|
|
184
251
|
end
|