grape 1.3.0 → 1.5.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 +90 -0
- data/LICENSE +1 -1
- data/README.md +104 -21
- data/UPGRADING.md +243 -39
- data/lib/grape.rb +4 -5
- data/lib/grape/api.rb +4 -4
- data/lib/grape/api/instance.rb +32 -31
- data/lib/grape/content_types.rb +34 -0
- data/lib/grape/dsl/helpers.rb +2 -1
- data/lib/grape/dsl/inside_route.rb +76 -42
- data/lib/grape/dsl/parameters.rb +4 -4
- data/lib/grape/dsl/routing.rb +8 -8
- data/lib/grape/dsl/validations.rb +18 -1
- data/lib/grape/eager_load.rb +1 -1
- data/lib/grape/endpoint.rb +8 -6
- data/lib/grape/exceptions/base.rb +0 -4
- data/lib/grape/exceptions/validation_errors.rb +11 -12
- data/lib/grape/http/headers.rb +26 -0
- data/lib/grape/middleware/base.rb +3 -4
- data/lib/grape/middleware/error.rb +10 -12
- data/lib/grape/middleware/formatter.rb +3 -3
- data/lib/grape/middleware/stack.rb +19 -5
- data/lib/grape/middleware/versioner/header.rb +4 -4
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
- data/lib/grape/middleware/versioner/path.rb +1 -1
- data/lib/grape/namespace.rb +12 -2
- data/lib/grape/path.rb +13 -3
- data/lib/grape/request.rb +13 -8
- data/lib/grape/router.rb +26 -30
- data/lib/grape/router/attribute_translator.rb +25 -4
- data/lib/grape/router/pattern.rb +17 -16
- data/lib/grape/router/route.rb +5 -24
- data/lib/grape/{serve_file → serve_stream}/file_body.rb +1 -1
- data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +1 -1
- data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +8 -8
- data/lib/grape/util/base_inheritable.rb +15 -8
- data/lib/grape/util/cache.rb +20 -0
- data/lib/grape/util/lazy_object.rb +43 -0
- data/lib/grape/util/lazy_value.rb +1 -0
- data/lib/grape/util/reverse_stackable_values.rb +2 -0
- data/lib/grape/util/stackable_values.rb +7 -20
- data/lib/grape/validations/params_scope.rb +6 -5
- data/lib/grape/validations/types.rb +6 -5
- data/lib/grape/validations/types/array_coercer.rb +14 -5
- data/lib/grape/validations/types/build_coercer.rb +5 -8
- data/lib/grape/validations/types/custom_type_coercer.rb +14 -2
- data/lib/grape/validations/types/dry_type_coercer.rb +36 -1
- data/lib/grape/validations/types/file.rb +15 -12
- data/lib/grape/validations/types/json.rb +40 -36
- data/lib/grape/validations/types/primitive_coercer.rb +15 -6
- data/lib/grape/validations/types/set_coercer.rb +6 -4
- data/lib/grape/validations/types/variant_collection_coercer.rb +1 -1
- data/lib/grape/validations/validators/as.rb +1 -1
- data/lib/grape/validations/validators/base.rb +2 -4
- data/lib/grape/validations/validators/coerce.rb +4 -11
- data/lib/grape/validations/validators/default.rb +3 -5
- data/lib/grape/validations/validators/exactly_one_of.rb +4 -2
- data/lib/grape/validations/validators/except_values.rb +1 -1
- data/lib/grape/validations/validators/regexp.rb +1 -1
- data/lib/grape/validations/validators/values.rb +1 -1
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api/instance_spec.rb +50 -0
- data/spec/grape/api_spec.rb +82 -6
- data/spec/grape/dsl/inside_route_spec.rb +182 -33
- data/spec/grape/endpoint/declared_spec.rb +590 -0
- data/spec/grape/endpoint_spec.rb +0 -521
- data/spec/grape/entity_spec.rb +6 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +2 -2
- data/spec/grape/integration/rack_sendfile_spec.rb +12 -8
- data/spec/grape/middleware/auth/strategies_spec.rb +1 -1
- data/spec/grape/middleware/error_spec.rb +1 -1
- data/spec/grape/middleware/formatter_spec.rb +3 -3
- data/spec/grape/middleware/stack_spec.rb +12 -1
- data/spec/grape/path_spec.rb +4 -4
- data/spec/grape/validations/instance_behaivour_spec.rb +1 -1
- data/spec/grape/validations/params_scope_spec.rb +26 -0
- data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
- data/spec/grape/validations/types/primitive_coercer_spec.rb +135 -0
- data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
- data/spec/grape/validations/types_spec.rb +1 -1
- data/spec/grape/validations/validators/coerce_spec.rb +329 -77
- data/spec/grape/validations/validators/default_spec.rb +170 -0
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +12 -12
- data/spec/grape/validations/validators/except_values_spec.rb +1 -0
- data/spec/grape/validations/validators/values_spec.rb +1 -1
- data/spec/grape/validations_spec.rb +30 -30
- data/spec/integration/eager_load/eager_load_spec.rb +15 -0
- data/spec/spec_helper.rb +3 -10
- data/spec/support/chunks.rb +14 -0
- data/spec/support/eager_load.rb +19 -0
- data/spec/support/versioned_helpers.rb +3 -5
- metadata +121 -105
- data/lib/grape/util/content_types.rb +0 -28
@@ -17,7 +17,7 @@ describe Grape::Validations::Types do
|
|
17
17
|
[
|
18
18
|
Integer, Float, Numeric, BigDecimal,
|
19
19
|
Grape::API::Boolean, String, Symbol,
|
20
|
-
Date, DateTime, Time
|
20
|
+
Date, DateTime, Time
|
21
21
|
].each do |type|
|
22
22
|
it "recognizes #{type} as a primitive" do
|
23
23
|
expect(described_class.primitive?(type)).to be_truthy
|
@@ -154,6 +154,49 @@ describe Grape::Validations::CoerceValidator do
|
|
154
154
|
end
|
155
155
|
|
156
156
|
context 'coerces' do
|
157
|
+
context 'json' do
|
158
|
+
let(:headers) { { 'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json' } }
|
159
|
+
|
160
|
+
it 'BigDecimal' do
|
161
|
+
subject.params do
|
162
|
+
requires :bigdecimal, type: BigDecimal
|
163
|
+
end
|
164
|
+
subject.post '/bigdecimal' do
|
165
|
+
"#{params[:bigdecimal].class} #{params[:bigdecimal].to_f}"
|
166
|
+
end
|
167
|
+
|
168
|
+
post '/bigdecimal', { bigdecimal: 45.1 }.to_json, headers
|
169
|
+
expect(last_response.status).to eq(201)
|
170
|
+
expect(last_response.body).to eq('BigDecimal 45.1')
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'Boolean' do
|
174
|
+
subject.params do
|
175
|
+
requires :boolean, type: Boolean
|
176
|
+
end
|
177
|
+
subject.post '/boolean' do
|
178
|
+
params[:boolean]
|
179
|
+
end
|
180
|
+
|
181
|
+
post '/boolean', { boolean: 'true' }.to_json, headers
|
182
|
+
expect(last_response.status).to eq(201)
|
183
|
+
expect(last_response.body).to eq('true')
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'BigDecimal' do
|
188
|
+
subject.params do
|
189
|
+
requires :bigdecimal, coerce: BigDecimal
|
190
|
+
end
|
191
|
+
subject.get '/bigdecimal' do
|
192
|
+
params[:bigdecimal].class
|
193
|
+
end
|
194
|
+
|
195
|
+
get '/bigdecimal', bigdecimal: '45'
|
196
|
+
expect(last_response.status).to eq(200)
|
197
|
+
expect(last_response.body).to eq('BigDecimal')
|
198
|
+
end
|
199
|
+
|
157
200
|
it 'Integer' do
|
158
201
|
subject.params do
|
159
202
|
requires :int, coerce: Integer
|
@@ -167,6 +210,23 @@ describe Grape::Validations::CoerceValidator do
|
|
167
210
|
expect(last_response.body).to eq(integer_class_name)
|
168
211
|
end
|
169
212
|
|
213
|
+
it 'String' do
|
214
|
+
subject.params do
|
215
|
+
requires :string, coerce: String
|
216
|
+
end
|
217
|
+
subject.get '/string' do
|
218
|
+
params[:string].class
|
219
|
+
end
|
220
|
+
|
221
|
+
get '/string', string: 45
|
222
|
+
expect(last_response.status).to eq(200)
|
223
|
+
expect(last_response.body).to eq('String')
|
224
|
+
|
225
|
+
get '/string', string: nil
|
226
|
+
expect(last_response.status).to eq(200)
|
227
|
+
expect(last_response.body).to eq('NilClass')
|
228
|
+
end
|
229
|
+
|
170
230
|
it 'is a custom type' do
|
171
231
|
subject.params do
|
172
232
|
requires :uri, coerce: SecureURIOnly
|
@@ -281,119 +341,247 @@ describe Grape::Validations::CoerceValidator do
|
|
281
341
|
end
|
282
342
|
end
|
283
343
|
|
284
|
-
it '
|
344
|
+
it 'Boolean' do
|
285
345
|
subject.params do
|
286
|
-
requires :
|
346
|
+
requires :boolean, type: Boolean
|
287
347
|
end
|
288
|
-
subject.get '/
|
289
|
-
params[:
|
348
|
+
subject.get '/boolean' do
|
349
|
+
params[:boolean].class
|
290
350
|
end
|
291
351
|
|
292
|
-
get '/
|
352
|
+
get '/boolean', boolean: 1
|
293
353
|
expect(last_response.status).to eq(200)
|
294
354
|
expect(last_response.body).to eq('TrueClass')
|
355
|
+
end
|
295
356
|
|
296
|
-
|
297
|
-
|
298
|
-
|
357
|
+
context 'File' do
|
358
|
+
let(:file) { Rack::Test::UploadedFile.new(__FILE__) }
|
359
|
+
let(:filename) { File.basename(__FILE__).to_s }
|
299
360
|
|
300
|
-
|
301
|
-
|
302
|
-
|
361
|
+
it 'Rack::Multipart::UploadedFile' do
|
362
|
+
subject.params do
|
363
|
+
requires :file, type: Rack::Multipart::UploadedFile
|
364
|
+
end
|
365
|
+
subject.post '/upload' do
|
366
|
+
params[:file][:filename]
|
367
|
+
end
|
303
368
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
end
|
369
|
+
post '/upload', file: file
|
370
|
+
expect(last_response.status).to eq(201)
|
371
|
+
expect(last_response.body).to eq(filename)
|
308
372
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
end
|
313
|
-
subject.get '/boolean' do
|
314
|
-
params[:boolean].class
|
373
|
+
post '/upload', file: 'not a file'
|
374
|
+
expect(last_response.status).to eq(400)
|
375
|
+
expect(last_response.body).to eq('file is invalid')
|
315
376
|
end
|
316
377
|
|
317
|
-
|
318
|
-
|
319
|
-
|
378
|
+
it 'File' do
|
379
|
+
subject.params do
|
380
|
+
requires :file, coerce: File
|
381
|
+
end
|
382
|
+
subject.post '/upload' do
|
383
|
+
params[:file][:filename]
|
384
|
+
end
|
320
385
|
|
321
|
-
|
322
|
-
|
323
|
-
|
386
|
+
post '/upload', file: file
|
387
|
+
expect(last_response.status).to eq(201)
|
388
|
+
expect(last_response.body).to eq(filename)
|
324
389
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
get '/boolean', boolean: 'true'
|
330
|
-
expect(last_response.status).to eq(200)
|
331
|
-
expect(last_response.body).to eq('TrueClass')
|
390
|
+
post '/upload', file: 'not a file'
|
391
|
+
expect(last_response.status).to eq(400)
|
392
|
+
expect(last_response.body).to eq('file is invalid')
|
332
393
|
|
333
|
-
|
334
|
-
|
335
|
-
|
394
|
+
post '/upload', file: { filename: 'fake file', tempfile: '/etc/passwd' }
|
395
|
+
expect(last_response.status).to eq(400)
|
396
|
+
expect(last_response.body).to eq('file is invalid')
|
397
|
+
end
|
336
398
|
|
337
|
-
|
338
|
-
|
339
|
-
|
399
|
+
it 'collection' do
|
400
|
+
subject.params do
|
401
|
+
requires :files, type: Array[File]
|
402
|
+
end
|
403
|
+
subject.post '/upload' do
|
404
|
+
params[:files].first[:filename]
|
405
|
+
end
|
340
406
|
|
341
|
-
|
342
|
-
|
343
|
-
|
407
|
+
post '/upload', files: [file]
|
408
|
+
expect(last_response.status).to eq(201)
|
409
|
+
expect(last_response.body).to eq(filename)
|
410
|
+
end
|
344
411
|
end
|
345
412
|
|
346
|
-
it '
|
413
|
+
it 'Nests integers' do
|
347
414
|
subject.params do
|
348
|
-
requires :
|
415
|
+
requires :integers, type: Hash do
|
416
|
+
requires :int, coerce: Integer
|
417
|
+
end
|
349
418
|
end
|
350
|
-
subject.
|
351
|
-
params[:
|
419
|
+
subject.get '/int' do
|
420
|
+
params[:integers][:int].class
|
352
421
|
end
|
353
422
|
|
354
|
-
|
355
|
-
expect(last_response.status).to eq(
|
356
|
-
expect(last_response.body).to eq(
|
357
|
-
|
358
|
-
post '/upload', file: 'not a file'
|
359
|
-
expect(last_response.status).to eq(400)
|
360
|
-
expect(last_response.body).to eq('file is invalid')
|
423
|
+
get '/int', integers: { int: '45' }
|
424
|
+
expect(last_response.status).to eq(200)
|
425
|
+
expect(last_response.body).to eq(integer_class_name)
|
361
426
|
end
|
362
427
|
|
363
|
-
|
364
|
-
|
365
|
-
|
428
|
+
context 'nil values' do
|
429
|
+
context 'primitive types' do
|
430
|
+
Grape::Validations::Types::PRIMITIVES.each do |type|
|
431
|
+
it 'respects the nil value' do
|
432
|
+
subject.params do
|
433
|
+
requires :param, type: type
|
434
|
+
end
|
435
|
+
subject.get '/nil_value' do
|
436
|
+
params[:param].class
|
437
|
+
end
|
438
|
+
|
439
|
+
get '/nil_value', param: nil
|
440
|
+
expect(last_response.status).to eq(200)
|
441
|
+
expect(last_response.body).to eq('NilClass')
|
442
|
+
end
|
443
|
+
end
|
366
444
|
end
|
367
|
-
|
368
|
-
|
445
|
+
|
446
|
+
context 'structures types' do
|
447
|
+
Grape::Validations::Types::STRUCTURES.each do |type|
|
448
|
+
it 'respects the nil value' do
|
449
|
+
subject.params do
|
450
|
+
requires :param, type: type
|
451
|
+
end
|
452
|
+
subject.get '/nil_value' do
|
453
|
+
params[:param].class
|
454
|
+
end
|
455
|
+
|
456
|
+
get '/nil_value', param: nil
|
457
|
+
expect(last_response.status).to eq(200)
|
458
|
+
expect(last_response.body).to eq('NilClass')
|
459
|
+
end
|
460
|
+
end
|
369
461
|
end
|
370
462
|
|
371
|
-
|
372
|
-
|
373
|
-
|
463
|
+
context 'special types' do
|
464
|
+
Grape::Validations::Types::SPECIAL.each_key do |type|
|
465
|
+
it 'respects the nil value' do
|
466
|
+
subject.params do
|
467
|
+
requires :param, type: type
|
468
|
+
end
|
469
|
+
subject.get '/nil_value' do
|
470
|
+
params[:param].class
|
471
|
+
end
|
374
472
|
|
375
|
-
|
376
|
-
|
377
|
-
|
473
|
+
get '/nil_value', param: nil
|
474
|
+
expect(last_response.status).to eq(200)
|
475
|
+
expect(last_response.body).to eq('NilClass')
|
476
|
+
end
|
477
|
+
end
|
378
478
|
|
379
|
-
|
380
|
-
|
381
|
-
|
479
|
+
context 'variant-member-type collections' do
|
480
|
+
[
|
481
|
+
Array[Integer, String],
|
482
|
+
[Integer, String, Array[Integer, String]]
|
483
|
+
].each do |type|
|
484
|
+
it 'respects the nil value' do
|
485
|
+
subject.params do
|
486
|
+
requires :param, type: type
|
487
|
+
end
|
488
|
+
subject.get '/nil_value' do
|
489
|
+
params[:param].class
|
490
|
+
end
|
491
|
+
|
492
|
+
get '/nil_value', param: nil
|
493
|
+
expect(last_response.status).to eq(200)
|
494
|
+
expect(last_response.body).to eq('NilClass')
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|
382
499
|
end
|
383
500
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
501
|
+
context 'empty string' do
|
502
|
+
context 'primitive types' do
|
503
|
+
(Grape::Validations::Types::PRIMITIVES - [String]).each do |type|
|
504
|
+
it "is coerced to nil for type #{type}" do
|
505
|
+
subject.params do
|
506
|
+
requires :param, type: type
|
507
|
+
end
|
508
|
+
subject.get '/empty_string' do
|
509
|
+
params[:param].class
|
510
|
+
end
|
511
|
+
|
512
|
+
get '/empty_string', param: ''
|
513
|
+
expect(last_response.status).to eq(200)
|
514
|
+
expect(last_response.body).to eq('NilClass')
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
it 'is not coerced to nil for type String' do
|
519
|
+
subject.params do
|
520
|
+
requires :param, type: String
|
521
|
+
end
|
522
|
+
subject.get '/empty_string' do
|
523
|
+
params[:param].class
|
524
|
+
end
|
525
|
+
|
526
|
+
get '/empty_string', param: ''
|
527
|
+
expect(last_response.status).to eq(200)
|
528
|
+
expect(last_response.body).to eq('String')
|
388
529
|
end
|
389
530
|
end
|
390
|
-
|
391
|
-
|
531
|
+
|
532
|
+
context 'structures types' do
|
533
|
+
(Grape::Validations::Types::STRUCTURES - [Hash]).each do |type|
|
534
|
+
it "is coerced to nil for type #{type}" do
|
535
|
+
subject.params do
|
536
|
+
requires :param, type: type
|
537
|
+
end
|
538
|
+
subject.get '/empty_string' do
|
539
|
+
params[:param].class
|
540
|
+
end
|
541
|
+
|
542
|
+
get '/empty_string', param: ''
|
543
|
+
expect(last_response.status).to eq(200)
|
544
|
+
expect(last_response.body).to eq('NilClass')
|
545
|
+
end
|
546
|
+
end
|
392
547
|
end
|
393
548
|
|
394
|
-
|
395
|
-
|
396
|
-
|
549
|
+
context 'special types' do
|
550
|
+
(Grape::Validations::Types::SPECIAL.keys - [File, Rack::Multipart::UploadedFile]).each do |type|
|
551
|
+
it "is coerced to nil for type #{type}" do
|
552
|
+
subject.params do
|
553
|
+
requires :param, type: type
|
554
|
+
end
|
555
|
+
subject.get '/empty_string' do
|
556
|
+
params[:param].class
|
557
|
+
end
|
558
|
+
|
559
|
+
get '/empty_string', param: ''
|
560
|
+
expect(last_response.status).to eq(200)
|
561
|
+
expect(last_response.body).to eq('NilClass')
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
context 'variant-member-type collections' do
|
566
|
+
[
|
567
|
+
Array[Integer, String],
|
568
|
+
[Integer, String, Array[Integer, String]]
|
569
|
+
].each do |type|
|
570
|
+
it "is coerced to nil for type #{type}" do
|
571
|
+
subject.params do
|
572
|
+
requires :param, type: type
|
573
|
+
end
|
574
|
+
subject.get '/empty_string' do
|
575
|
+
params[:param].class
|
576
|
+
end
|
577
|
+
|
578
|
+
get '/empty_string', param: ''
|
579
|
+
expect(last_response.status).to eq(200)
|
580
|
+
expect(last_response.body).to eq('NilClass')
|
581
|
+
end
|
582
|
+
end
|
583
|
+
end
|
584
|
+
end
|
397
585
|
end
|
398
586
|
end
|
399
587
|
|
@@ -432,6 +620,30 @@ describe Grape::Validations::CoerceValidator do
|
|
432
620
|
expect(JSON.parse(last_response.body)).to eq(%w[a b c d])
|
433
621
|
end
|
434
622
|
|
623
|
+
it 'parses parameters with Array[Array[String]] type and coerce_with' do
|
624
|
+
subject.params do
|
625
|
+
requires :values, type: Array[Array[String]], coerce_with: ->(val) { val.is_a?(String) ? [val.split(/,/).map(&:strip)] : val }
|
626
|
+
end
|
627
|
+
subject.post '/coerce_nested_strings' do
|
628
|
+
params[:values]
|
629
|
+
end
|
630
|
+
|
631
|
+
post '/coerce_nested_strings', ::Grape::Json.dump(values: 'a,b,c,d'), 'CONTENT_TYPE' => 'application/json'
|
632
|
+
expect(last_response.status).to eq(201)
|
633
|
+
expect(JSON.parse(last_response.body)).to eq([%w[a b c d]])
|
634
|
+
|
635
|
+
post '/coerce_nested_strings', ::Grape::Json.dump(values: [%w[a c], %w[b]]), 'CONTENT_TYPE' => 'application/json'
|
636
|
+
expect(last_response.status).to eq(201)
|
637
|
+
expect(JSON.parse(last_response.body)).to eq([%w[a c], %w[b]])
|
638
|
+
|
639
|
+
post '/coerce_nested_strings', ::Grape::Json.dump(values: [[]]), 'CONTENT_TYPE' => 'application/json'
|
640
|
+
expect(last_response.status).to eq(201)
|
641
|
+
expect(JSON.parse(last_response.body)).to eq([[]])
|
642
|
+
|
643
|
+
post '/coerce_nested_strings', ::Grape::Json.dump(values: [['a', { bar: 0 }], ['b']]), 'CONTENT_TYPE' => 'application/json'
|
644
|
+
expect(last_response.status).to eq(400)
|
645
|
+
end
|
646
|
+
|
435
647
|
it 'parses parameters with Array[Integer] type' do
|
436
648
|
subject.params do
|
437
649
|
requires :values, type: Array[Integer], coerce_with: ->(val) { val.split(/\s+/).map(&:to_i) }
|
@@ -514,6 +726,46 @@ describe Grape::Validations::CoerceValidator do
|
|
514
726
|
expect(last_response.body).to eq('3')
|
515
727
|
end
|
516
728
|
|
729
|
+
context 'Integer type and coerce_with potentially returning nil' do
|
730
|
+
before do
|
731
|
+
subject.params do
|
732
|
+
requires :int, type: Integer, coerce_with: (lambda do |val|
|
733
|
+
if val == '0'
|
734
|
+
nil
|
735
|
+
elsif val.match?(/^-?\d+$/)
|
736
|
+
val.to_i
|
737
|
+
else
|
738
|
+
val
|
739
|
+
end
|
740
|
+
end)
|
741
|
+
end
|
742
|
+
subject.get '/' do
|
743
|
+
params[:int].class.to_s
|
744
|
+
end
|
745
|
+
end
|
746
|
+
|
747
|
+
it 'accepts value that coerces to nil' do
|
748
|
+
get '/', int: '0'
|
749
|
+
|
750
|
+
expect(last_response.status).to eq(200)
|
751
|
+
expect(last_response.body).to eq('NilClass')
|
752
|
+
end
|
753
|
+
|
754
|
+
it 'coerces to Integer' do
|
755
|
+
get '/', int: '1'
|
756
|
+
|
757
|
+
expect(last_response.status).to eq(200)
|
758
|
+
expect(last_response.body).to eq('Integer')
|
759
|
+
end
|
760
|
+
|
761
|
+
it 'returns invalid value if coercion returns a wrong type' do
|
762
|
+
get '/', int: 'lol'
|
763
|
+
|
764
|
+
expect(last_response.status).to eq(400)
|
765
|
+
expect(last_response.body).to eq('int is invalid')
|
766
|
+
end
|
767
|
+
end
|
768
|
+
|
517
769
|
it 'must be supplied with :type or :coerce' do
|
518
770
|
expect do
|
519
771
|
subject.params do
|