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
@@ -1,181 +1,132 @@
1
1
  describe Compel do
2
2
 
3
- def make_the_call(method, params)
4
- Compel.send(method, params) do
5
- param :first_name, String, required: true
6
- param :last_name, String, required: true
7
- param :birth_date, DateTime
8
- end
9
- end
10
-
11
- context '#run!' do
12
-
13
- it 'should raise InvalidParamsError exception' do
14
- params = {
15
- first_name: 'Joaquim'
16
- }
17
-
18
- expect{ make_the_call(:run!, params) }.to \
19
- raise_error Compel::InvalidParamsError, 'params are invalid'
20
- end
21
-
22
- it 'should raise InvalidParamsError exception with errors' do
23
- params = {
24
- first_name: 'Joaquim'
25
- }
26
-
27
- expect{ make_the_call(:run!, params) }.to raise_error do |exception|
28
- expect(exception.params).to eq \
29
- Hashie::Mash.new(first_name: 'Joaquim')
30
-
31
- expect(exception.errors).to eq \
32
- Hashie::Mash.new(last_name: ['is required'])
33
- end
34
- end
35
-
36
- end
37
-
38
- context '#run?' do
39
-
40
- it 'should return true' do
41
- params = {
42
- first_name: 'Joaquim',
43
- last_name: 'Adráz',
44
- birth_date: '1989-08-06T09:00:00'
45
- }
46
-
47
- expect(make_the_call(:run?, params)).to eq(true)
48
- end
49
-
50
- it 'should return false' do
51
- params = {
52
- first_name: 'Joaquim'
53
- }
54
-
55
- expect(make_the_call(:run?, params)).to eq(false)
56
- end
57
-
58
- end
59
-
60
3
  context '#run' do
61
4
 
62
- def make_the_call(method, params)
63
- Compel.send(method, params) do
64
- param :user, Hash, required: true do
65
- param :first_name, String, required: true
66
- param :last_name, String, required: true
67
- param :birth_date, DateTime
68
- param :age, Integer
69
- param :admin, Compel::Boolean
70
- param :blog_role, Hash do
71
- param :admin, Compel::Boolean, required: true
72
- end
73
- end
74
- end
75
- end
5
+ context 'User validation example' do
6
+
7
+ def make_the_call(method, hash)
8
+ schema = Compel.hash.keys({
9
+ user: Compel.hash.keys({
10
+ first_name: Compel.string.required,
11
+ last_name: Compel.string.required,
12
+ birth_date: Compel.datetime,
13
+ age: Compel.integer,
14
+ admin: Compel.boolean,
15
+ blog_role: Compel.hash.keys({
16
+ admin: Compel.boolean.required
17
+ })
18
+ }).required
19
+ })
76
20
 
77
- it 'should compel returning coerced values' do
78
- params = {
79
- user: {
80
- first_name: 'Joaquim',
81
- last_name: 'Adráz',
82
- birth_date: '1989-08-06T09:00:00',
83
- age: '26',
84
- admin: 'f',
85
- blog_role: {
86
- admin: '0'
87
- }
88
- }
89
- }
21
+ Compel.send(method, hash, schema)
22
+ end
90
23
 
91
- expect(make_the_call(:run, params)).to eq \
92
- Hashie::Mash.new({
24
+ it 'should compel returning coerced values' do
25
+ hash = {
93
26
  user: {
94
27
  first_name: 'Joaquim',
95
28
  last_name: 'Adráz',
96
- birth_date: DateTime.parse('1989-08-06T09:00:00'),
97
- age: 26,
98
- admin: false,
29
+ birth_date: '1989-08-06T09:00:00',
30
+ age: '26',
31
+ admin: 'f',
99
32
  blog_role: {
100
- admin: false
33
+ admin: '0'
101
34
  }
102
35
  }
103
- })
104
- end
105
-
106
- it 'should not compel and leave other params untouched' do
107
- params = {
108
- other_param: 1,
109
- user: {
110
- first_name: 'Joaquim'
111
36
  }
112
- }
113
37
 
114
- expect(make_the_call(:run, params)).to eq \
115
- Hashie::Mash.new({
38
+ expect(make_the_call(:run, hash)).to eq \
39
+ Hashie::Mash.new({
40
+ user: {
41
+ first_name: 'Joaquim',
42
+ last_name: 'Adráz',
43
+ birth_date: DateTime.parse('1989-08-06T09:00:00'),
44
+ age: 26,
45
+ admin: false,
46
+ blog_role: {
47
+ admin: false
48
+ }
49
+ }
50
+ })
51
+ end
52
+
53
+ it 'should not compel and leave other hash untouched' do
54
+ hash = {
116
55
  other_param: 1,
117
56
  user: {
118
- first_name: 'Joaquim',
119
- },
120
- errors: {
57
+ first_name: 'Joaquim'
58
+ }
59
+ }
60
+
61
+ expect(make_the_call(:run, hash)).to eq \
62
+ Hashie::Mash.new({
63
+ other_param: 1,
121
64
  user: {
122
- last_name: ['is required']
65
+ first_name: 'Joaquim',
66
+ },
67
+ errors: {
68
+ user: {
69
+ last_name: ['is required']
70
+ }
123
71
  }
124
- }
125
- })
126
- end
72
+ })
73
+ end
127
74
 
128
- it 'should not compel for invalid params' do
129
- expect{ make_the_call(:run, 1) }.to \
130
- raise_error Compel::ParamTypeError, 'params must be an Hash'
131
- end
75
+ it 'should not compel for invalid hash' do
76
+ expect{ make_the_call(:run, 1) }.to \
77
+ raise_error Compel::TypeError, 'must be an Hash'
78
+ end
132
79
 
133
- it 'should not compel for invalid params 1' do
134
- expect{ make_the_call(:run, nil) }.to \
135
- raise_error Compel::ParamTypeError, 'params must be an Hash'
136
- end
80
+ it 'should not compel for invalid hash 1' do
81
+ expect{ make_the_call(:run, nil) }.to \
82
+ raise_error Compel::TypeError, 'must be an Hash'
83
+ end
137
84
 
138
- it 'should not compel' do
139
- params = {
140
- user: {
141
- first_name: 'Joaquim'
85
+ it 'should not compel' do
86
+ hash = {
87
+ user: {
88
+ first_name: 'Joaquim'
89
+ }
142
90
  }
143
- }
144
91
 
145
- expect(make_the_call(:run, params)).to eq \
146
- Hashie::Mash.new({
147
- user:{
148
- first_name: 'Joaquim',
149
- },
150
- errors: {
151
- user: {
152
- last_name: ['is required']
92
+ expect(make_the_call(:run, hash)).to eq \
93
+ Hashie::Mash.new({
94
+ user:{
95
+ first_name: 'Joaquim',
96
+ },
97
+ errors: {
98
+ user: {
99
+ last_name: ['is required']
100
+ }
153
101
  }
154
- }
155
- })
102
+ })
103
+ end
104
+
156
105
  end
157
106
 
158
- context 'nested Hash' do
159
-
160
- def make_the_call(method, params)
161
- Compel.send(method, params) do
162
- param :address, Hash, required: true do
163
- param :line_one, String, required: true
164
- param :line_two, String
165
- param :post_code, Hash, required: true do
166
- param :prefix, Integer, length: 4, required: true
167
- param :suffix, Integer, length: 3
168
- param :county, Hash do
169
- param :code, String, length: 2, required: true
170
- param :name, String
171
- end
172
- end
173
- end
174
- end
107
+ context 'Address validation example' do
108
+
109
+ def make_the_call(method, hash)
110
+ schema = Compel.hash.keys({
111
+ address: Compel.hash.keys({
112
+ line_one: Compel.string.required,
113
+ line_two: Compel.string,
114
+ post_code: Compel.hash.keys({
115
+ prefix: Compel.integer.length(4).required,
116
+ suffix: Compel.integer.length(3),
117
+ county: Compel.hash.keys({
118
+ code: Compel.string.length(2).required,
119
+ name: Compel.string
120
+ })
121
+ }).required
122
+ }).required
123
+ })
124
+
125
+ Compel.send(method, hash, schema)
175
126
  end
176
127
 
177
128
  it 'should run?' do
178
- params = {
129
+ hash = {
179
130
  address: {
180
131
  line_one: 'Lisbon',
181
132
  line_two: 'Portugal',
@@ -186,17 +137,17 @@ describe Compel do
186
137
  }
187
138
  }
188
139
 
189
- expect(make_the_call(:run?, params)).to eq(true)
140
+ expect(make_the_call(:run?, hash)).to eq(true)
190
141
  end
191
142
 
192
143
  it 'should not compel' do
193
- params = {
144
+ hash = {
194
145
  address: {
195
146
  line_two: 'Portugal'
196
147
  }
197
148
  }
198
149
 
199
- expect(make_the_call(:run, params)).to eq \
150
+ expect(make_the_call(:run, hash)).to eq \
200
151
  Hashie::Mash.new({
201
152
  address: {
202
153
  line_two: 'Portugal'
@@ -211,7 +162,7 @@ describe Compel do
211
162
  end
212
163
 
213
164
  it 'should not compel 1' do
214
- params = {
165
+ hash = {
215
166
  address: {
216
167
  line_two: 'Portugal',
217
168
  post_code: {
@@ -223,7 +174,7 @@ describe Compel do
223
174
  }
224
175
  }
225
176
 
226
- expect(make_the_call(:run, params)).to eq \
177
+ expect(make_the_call(:run, hash)).to eq \
227
178
  Hashie::Mash.new({
228
179
  address: {
229
180
  line_two: 'Portugal',
@@ -246,7 +197,7 @@ describe Compel do
246
197
  end
247
198
 
248
199
  it 'should not compel 2' do
249
- params = {
200
+ hash = {
250
201
  address: {
251
202
  post_code: {
252
203
  suffix: '1234'
@@ -254,7 +205,7 @@ describe Compel do
254
205
  }
255
206
  }
256
207
 
257
- expect(make_the_call(:run, params)).to eq \
208
+ expect(make_the_call(:run, hash)).to eq \
258
209
  Hashie::Mash.new({
259
210
  address: {
260
211
  post_code: {
@@ -274,7 +225,7 @@ describe Compel do
274
225
  end
275
226
 
276
227
  it 'should not compel 3' do
277
- params = {
228
+ hash = {
278
229
  address: {
279
230
  post_code: {
280
231
  prefix: '1100',
@@ -284,7 +235,7 @@ describe Compel do
284
235
  }
285
236
  }
286
237
 
287
- expect(make_the_call(:run, params)).to eq \
238
+ expect(make_the_call(:run, hash)).to eq \
288
239
  Hashie::Mash.new({
289
240
  address: {
290
241
  post_code: {
@@ -308,12 +259,13 @@ describe Compel do
308
259
  end
309
260
 
310
261
  it 'should not compel 4' do
311
- params = {
262
+ hash = {
312
263
  address: nil
313
264
  }
314
265
 
315
- expect(make_the_call(:run, params)).to eq \
266
+ expect(make_the_call(:run, hash)).to eq \
316
267
  Hashie::Mash.new({
268
+ address: nil,
317
269
  errors: {
318
270
  address: ['is required']
319
271
  }
@@ -331,6 +283,262 @@ describe Compel do
331
283
 
332
284
  end
333
285
 
286
+ context 'Boolean' do
287
+
288
+ context 'required option' do
289
+
290
+ it 'should compel' do
291
+ schema = Compel.hash.keys({
292
+ admin: Compel.boolean.required
293
+ })
294
+
295
+ expect(Compel.run?({ admin: 1 }, schema)).to be true
296
+ end
297
+
298
+ it 'should not compel' do
299
+ schema = Compel.hash.keys({
300
+ admin: Compel.boolean.required
301
+ })
302
+
303
+ expect(Compel.run({ admin: nil }, schema).errors[:admin]).to \
304
+ include('is required')
305
+ end
306
+
307
+ end
308
+
309
+ context 'default option' do
310
+
311
+ it 'should compel' do
312
+ schema = Compel.hash.keys({
313
+ admin: Compel.boolean.default(false)
314
+ })
315
+
316
+ expect(Compel.run({ admin: nil }, schema).admin).to be false
317
+ end
318
+
319
+ end
320
+
321
+ context 'is option' do
322
+
323
+ it 'should compel' do
324
+ schema = Compel.hash.keys({
325
+ admin: Compel.boolean.is(1)
326
+ })
327
+
328
+ expect(Compel.run?({ admin: 1 }, schema)).to be true
329
+ end
330
+
331
+ it 'should not compel' do
332
+ schema = Compel.hash.keys({
333
+ admin: Compel.boolean.is(1)
334
+ })
335
+
336
+ expect(Compel.run({ admin: 0 }, schema).errors[:admin]).to \
337
+ include('must be 1')
338
+ end
339
+
340
+ end
341
+
342
+ end
343
+
344
+ context 'String' do
345
+
346
+ context 'format option' do
347
+
348
+ it 'should compel' do
349
+ schema = Compel.hash.keys({
350
+ post_code: Compel.string.format(/^\d{4}-\d{3}$/)
351
+ })
352
+
353
+ expect(Compel.run?({ post_code: '1100-100' }, schema)).to be true
354
+ end
355
+
356
+ it 'should not compel' do
357
+ schema = Compel.hash.keys({
358
+ post_code: Compel.string.format(/^\d{4}-\d{3}$/)
359
+ })
360
+
361
+ expect(Compel.run({ post_code: '110-100' }, schema).errors[:post_code]).to \
362
+ include('must match format ^\\d{4}-\\d{3}$')
363
+ end
364
+
365
+ end
366
+
367
+ end
368
+
369
+ context 'Time' do
370
+
371
+ context 'format option' do
372
+
373
+ it 'should not compel' do
374
+ schema = Compel.hash.keys({
375
+ birth_date: Compel.time
376
+ })
377
+
378
+ expect(Compel.run({ birth_date: '1989-08-06' }, schema).errors.birth_date).to \
379
+ include("'1989-08-06' is not a parsable time with format: %FT%T")
380
+ end
381
+
382
+ it 'should compel with format' do
383
+ schema = Compel.hash.keys({
384
+ birth_date: Compel.time.format('%Y-%m-%d')
385
+ })
386
+
387
+ expect(Compel.run({ birth_date: '1989-08-06' }, schema).birth_date).to \
388
+ eq(Time.new(1989, 8, 6))
389
+ end
390
+
391
+ it 'should compel by default' do
392
+ schema = Compel.hash.keys({
393
+ birth_date: Compel.time
394
+ })
395
+
396
+ expect(Compel.run({ birth_date: '1989-08-06T09:00:00' }, schema).birth_date).to \
397
+ eq(Time.new(1989, 8, 6, 9))
398
+ end
399
+
400
+ it 'should compel with iso8601 format' do
401
+ schema = Compel.hash.keys({
402
+ birth_date: Compel.time.iso8601
403
+ })
404
+
405
+ expect(Compel.run({ birth_date: '1989-08-06T09:00:00' }, schema).birth_date).to \
406
+ eq(Time.new(1989, 8, 6, 9))
407
+ end
408
+
409
+ end
410
+
411
+ end
412
+
413
+ end
414
+
415
+ context 'DateTime' do
416
+
417
+ context 'format option' do
418
+
419
+ it 'should not compel' do
420
+ schema = Compel.hash.keys({
421
+ birth_date: Compel.datetime
422
+ })
423
+
424
+ expect(Compel.run({ birth_date: '1989-08-06' }, schema).errors.birth_date).to \
425
+ include("'1989-08-06' is not a parsable datetime with format: %FT%T")
426
+ end
427
+
428
+ it 'should compel with format' do
429
+ schema = Compel.hash.keys({
430
+ birth_date: Compel.datetime.format('%Y-%m-%d')
431
+ })
432
+
433
+ expect(Compel.run({ birth_date: '1989-08-06' }, schema).birth_date).to \
434
+ eq(DateTime.new(1989, 8, 6))
435
+ end
436
+
437
+ it 'should compel by default' do
438
+ schema = Compel.hash.keys({
439
+ birth_date: Compel.datetime
440
+ })
441
+
442
+ expect(Compel.run({ birth_date: '1989-08-06T09:00:00' }, schema).birth_date).to \
443
+ eq(DateTime.new(1989, 8, 6, 9))
444
+ end
445
+
446
+ it 'should compel with iso8601 format' do
447
+ schema = Compel.hash.keys({
448
+ birth_date: Compel.datetime.iso8601
449
+ })
450
+
451
+ expect(Compel.run({ birth_date: '1989-08-06T09:00:00' }, schema).birth_date).to \
452
+ eq(DateTime.new(1989, 8, 6, 9))
453
+ end
454
+
455
+ end
456
+
334
457
  end
335
458
 
459
+ context 'Compel methods' do
460
+
461
+ def make_the_call(method, hash)
462
+ schema = Compel.hash.keys({
463
+ first_name: Compel.string.required,
464
+ last_name: Compel.string.required,
465
+ birth_date: Compel.datetime
466
+ })
467
+
468
+ Compel.send(method, hash, schema)
469
+ end
470
+
471
+ context '#run!' do
472
+
473
+ it 'should compel' do
474
+ hash = {
475
+ first_name: 'Joaquim',
476
+ last_name: 'Adráz',
477
+ birth_date: DateTime.new(1988, 12, 24)
478
+ }
479
+
480
+ expect(make_the_call(:run!, hash)).to \
481
+ eq \
482
+ Hashie::Mash.new({
483
+ first_name: 'Joaquim',
484
+ last_name: 'Adráz',
485
+ birth_date: DateTime.new(1988, 12, 24)
486
+ })
487
+ end
488
+
489
+ it 'should raise InvalidHashError exception' do
490
+ hash = {
491
+ first_name: 'Joaquim'
492
+ }
493
+
494
+ expect{ make_the_call(:run!, hash) }.to \
495
+ raise_error Compel::InvalidHashError, 'hash has errors'
496
+ end
497
+
498
+ it 'should raise InvalidHashError exception with errors' do
499
+ hash = {
500
+ first_name: 'Joaquim'
501
+ }
502
+
503
+ expect{ make_the_call(:run!, hash) }.to raise_error do |exception|
504
+ expect(exception.object).to eq \
505
+ Hashie::Mash.new(first_name: 'Joaquim')
506
+
507
+ expect(exception.errors).to eq \
508
+ Hashie::Mash.new(last_name: ['is required'])
509
+ end
510
+ end
511
+
512
+ it 'should raise InvalidHashError exception for missing hash' do
513
+ expect{ make_the_call(:run!, {}) }.to \
514
+ raise_error Compel::InvalidHashError, 'hash has errors'
515
+ end
516
+
517
+ end
518
+
519
+ context '#run?' do
520
+
521
+ it 'should return true' do
522
+ hash = {
523
+ first_name: 'Joaquim',
524
+ last_name: 'Adráz',
525
+ birth_date: '1989-08-06T09:00:00'
526
+ }
527
+
528
+ expect(make_the_call(:run?, hash)).to eq(true)
529
+ end
530
+
531
+ it 'should return false' do
532
+ hash = {
533
+ first_name: 'Joaquim'
534
+ }
535
+
536
+ expect(make_the_call(:run?, hash)).to eq(false)
537
+ end
538
+
539
+ end
540
+
541
+ end
542
+
543
+
336
544
  end
@@ -0,0 +1,73 @@
1
+ describe Compel do
2
+
3
+ context 'Sinatra Integration' do
4
+
5
+ it 'should return 400 for missing params' do
6
+ post('/api/posts') do |response|
7
+ response_json = JSON.parse(response.body)
8
+
9
+ expect(response.status).to eq(400)
10
+ expect(response_json['errors']['post']).to \
11
+ include('is required')
12
+ end
13
+ end
14
+
15
+ it 'should return 400 for missing title' do
16
+ params = {
17
+ post: {
18
+ body: 'Body',
19
+ published: 0
20
+ }
21
+ }
22
+
23
+ post('/api/posts', params) do |response|
24
+ response_json = JSON.parse(response.body)
25
+
26
+ expect(response.status).to eq(400)
27
+ expect(response_json['errors']['post']['title']).to \
28
+ include('is required')
29
+ end
30
+ end
31
+
32
+ it 'should return 400 for invalid boolean' do
33
+ params = {
34
+ post: {
35
+ title: 'Title',
36
+ published: 'falss'
37
+ }
38
+ }
39
+
40
+ post('/api/posts', params) do |response|
41
+ response_json = JSON.parse(response.body)
42
+
43
+ expect(response.status).to eq(400)
44
+ expect(response_json['errors']['post']['published']).to \
45
+ include("'falss' is not a valid Boolean")
46
+ end
47
+ end
48
+
49
+ it 'should return 200' do
50
+ params = {
51
+ post: {
52
+ title: 'Title',
53
+ body: 'Body',
54
+ published: false
55
+ }
56
+ }
57
+
58
+ post('/api/posts', params) do |response|
59
+ response_json = JSON.parse(response.body)
60
+
61
+ expect(response.status).to eq(200)
62
+ expect(response_json['post']).to \
63
+ eq({
64
+ 'title' => 'Title',
65
+ 'body' => 'Body',
66
+ 'published' => false
67
+ })
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ end