compel 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +7 -0
  3. data/README.md +65 -54
  4. data/lib/compel/builder/boolean.rb +13 -0
  5. data/lib/compel/builder/common.rb +24 -0
  6. data/lib/compel/builder/common_value.rb +34 -0
  7. data/lib/compel/builder/date.rb +23 -0
  8. data/lib/compel/builder/datetime.rb +23 -0
  9. data/lib/compel/builder/float.rb +15 -0
  10. data/lib/compel/builder/hash.rb +22 -0
  11. data/lib/compel/builder/integer.rb +15 -0
  12. data/lib/compel/builder/json.rb +13 -0
  13. data/lib/compel/builder/methods.rb +60 -0
  14. data/lib/compel/builder/schema.rb +27 -0
  15. data/lib/compel/builder/string.rb +30 -0
  16. data/lib/compel/builder/time.rb +23 -0
  17. data/lib/compel/coercion/boolean.rb +1 -1
  18. data/lib/compel/coercion/date.rb +19 -2
  19. data/lib/compel/coercion/datetime.rb +19 -2
  20. data/lib/compel/coercion/float.rb +1 -1
  21. data/lib/compel/coercion/hash.rb +1 -1
  22. data/lib/compel/coercion/integer.rb +1 -1
  23. data/lib/compel/coercion/json.rb +1 -1
  24. data/lib/compel/coercion/regexp.rb +17 -0
  25. data/lib/compel/coercion/string.rb +1 -1
  26. data/lib/compel/coercion/time.rb +19 -2
  27. data/lib/compel/coercion/type.rb +0 -13
  28. data/lib/compel/coercion.rb +8 -10
  29. data/lib/compel/contract.rb +18 -62
  30. data/lib/compel/exceptions/invalid_hash_error.rb +9 -0
  31. data/lib/compel/exceptions/type_error.rb +7 -0
  32. data/lib/compel/exceptions/validation_error.rb +7 -0
  33. data/lib/compel/validation.rb +36 -50
  34. data/lib/compel/validators/base.rb +19 -0
  35. data/lib/compel/validators/hash_validator.rb +51 -0
  36. data/lib/compel/validators/type_validator.rb +30 -0
  37. data/lib/compel/version.rb +1 -1
  38. data/lib/compel.rb +16 -11
  39. data/spec/compel/builder_spec.rb +226 -0
  40. data/spec/compel/coercion_spec.rb +85 -18
  41. data/spec/compel/compel_spec.rb +368 -160
  42. data/spec/compel/sinatra_integration_spec.rb +73 -0
  43. data/spec/compel/validation_spec.rb +122 -8
  44. data/spec/spec_helper.rb +19 -0
  45. data/spec/support/sinatra_app.rb +43 -0
  46. metadata +28 -10
  47. data/lib/compel/invalid_params_error.rb +0 -9
  48. data/lib/compel/param.rb +0 -46
  49. data/lib/compel/param_type_error.rb +0 -7
  50. data/lib/compel/param_validation_error.rb +0 -7
  51. data/spec/compel/contract_spec.rb +0 -36
  52. 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::ParamTypeError, "'123abc' is not a valid Integer"
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::ParamTypeError, "'1.a233' is not a valid Float"
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::ParamTypeError, "'#{value}' is not a valid String"
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 Compel::ParamTypeError, "'#{value}' is not a valid Date"
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
- value = Compel::Coercion.coerce!('2015-12-22', DateTime)
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::ParamTypeError, "'123' is not a valid Hash"
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::ParamTypeError, "'hash' is not a valid Hash"
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::ParamTypeError, "'[\"hash\"]' is not a valid Hash"
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