grape 1.3.1 → 1.3.3

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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/LICENSE +1 -1
  4. data/README.md +19 -6
  5. data/UPGRADING.md +120 -16
  6. data/lib/grape/api/instance.rb +12 -7
  7. data/lib/grape/dsl/inside_route.rb +37 -14
  8. data/lib/grape/http/headers.rb +1 -0
  9. data/lib/grape/middleware/versioner/header.rb +1 -1
  10. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  11. data/lib/grape/path.rb +2 -2
  12. data/lib/grape/router/attribute_translator.rb +23 -2
  13. data/lib/grape/router/route.rb +3 -22
  14. data/lib/grape/router.rb +6 -14
  15. data/lib/grape/util/base_inheritable.rb +9 -6
  16. data/lib/grape/util/reverse_stackable_values.rb +3 -1
  17. data/lib/grape/util/stackable_values.rb +3 -1
  18. data/lib/grape/validations/types/array_coercer.rb +14 -5
  19. data/lib/grape/validations/types/build_coercer.rb +5 -8
  20. data/lib/grape/validations/types/custom_type_coercer.rb +1 -1
  21. data/lib/grape/validations/types/dry_type_coercer.rb +36 -1
  22. data/lib/grape/validations/types/file.rb +15 -13
  23. data/lib/grape/validations/types/json.rb +40 -36
  24. data/lib/grape/validations/types/primitive_coercer.rb +11 -4
  25. data/lib/grape/validations/types/set_coercer.rb +6 -4
  26. data/lib/grape/validations/types/variant_collection_coercer.rb +1 -1
  27. data/lib/grape/validations/types.rb +6 -5
  28. data/lib/grape/validations/validators/coerce.rb +3 -10
  29. data/lib/grape/validations/validators/default.rb +0 -1
  30. data/lib/grape/validations/validators/regexp.rb +1 -1
  31. data/lib/grape/version.rb +1 -1
  32. data/spec/grape/api/instance_spec.rb +50 -0
  33. data/spec/grape/endpoint_spec.rb +18 -5
  34. data/spec/grape/path_spec.rb +4 -4
  35. data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
  36. data/spec/grape/validations/types/primitive_coercer_spec.rb +5 -1
  37. data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
  38. data/spec/grape/validations/types_spec.rb +1 -1
  39. data/spec/grape/validations/validators/coerce_spec.rb +207 -29
  40. data/spec/grape/validations/validators/default_spec.rb +121 -0
  41. data/spec/grape/validations/validators/values_spec.rb +1 -1
  42. data/spec/grape/validations_spec.rb +5 -5
  43. metadata +9 -5
@@ -7,7 +7,7 @@ describe Grape::Validations::Types::PrimitiveCoercer do
7
7
 
8
8
  subject { described_class.new(type, strict) }
9
9
 
10
- describe '.call' do
10
+ describe '#call' do
11
11
  context 'Boolean' do
12
12
  let(:type) { Grape::API::Boolean }
13
13
 
@@ -26,6 +26,10 @@ describe Grape::Validations::Types::PrimitiveCoercer do
26
26
  it 'returns an error when the given value cannot be coerced' do
27
27
  expect(subject.call(123)).to be_instance_of(Grape::Validations::Types::InvalidValue)
28
28
  end
29
+
30
+ it 'coerces an empty string to nil' do
31
+ expect(subject.call('')).to be_nil
32
+ end
29
33
  end
30
34
 
31
35
  context 'String' do
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Grape::Validations::Types::SetCoercer do
6
+ subject { described_class.new(type) }
7
+
8
+ describe '#call' do
9
+ context 'a set of primitives' do
10
+ let(:type) { Set[String] }
11
+
12
+ it 'coerces elements to the set' do
13
+ expect(subject.call([10, 20])).to eq(Set['10', '20'])
14
+ end
15
+ end
16
+
17
+ context 'a set of sets' do
18
+ let(:type) { Set[Set[Integer]] }
19
+
20
+ it 'coerces elements in the nested set' do
21
+ expect(subject.call([%w[10 20]])).to eq(Set[Set[10, 20]])
22
+ expect(subject.call([['10'], ['20']])).to eq(Set[Set[10], Set[20]])
23
+ end
24
+ end
25
+
26
+ context 'a set of sets of arrays' do
27
+ let(:type) { Set[Set[Array[Integer]]] }
28
+
29
+ it 'coerces elements in the nested set' do
30
+ expect(subject.call([[['10'], ['20']]])).to eq(Set[Set[Array[10], Array[20]]])
31
+ end
32
+ end
33
+ end
34
+ end
@@ -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, Rack::Multipart::UploadedFile
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,36 @@ 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
+
157
187
  it 'BigDecimal' do
158
188
  subject.params do
159
189
  requires :bigdecimal, coerce: BigDecimal
@@ -180,6 +210,23 @@ describe Grape::Validations::CoerceValidator do
180
210
  expect(last_response.body).to eq(integer_class_name)
181
211
  end
182
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
+
183
230
  it 'is a custom type' do
184
231
  subject.params do
185
232
  requires :uri, coerce: SecureURIOnly
@@ -307,42 +354,60 @@ describe Grape::Validations::CoerceValidator do
307
354
  expect(last_response.body).to eq('TrueClass')
308
355
  end
309
356
 
310
- it 'Rack::Multipart::UploadedFile' do
311
- subject.params do
312
- requires :file, type: Rack::Multipart::UploadedFile
313
- end
314
- subject.post '/upload' do
315
- params[:file][:filename]
316
- end
357
+ context 'File' do
358
+ let(:file) { Rack::Test::UploadedFile.new(__FILE__) }
359
+ let(:filename) { File.basename(__FILE__).to_s }
317
360
 
318
- post '/upload', file: Rack::Test::UploadedFile.new(__FILE__)
319
- expect(last_response.status).to eq(201)
320
- expect(last_response.body).to eq(File.basename(__FILE__).to_s)
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
321
368
 
322
- post '/upload', file: 'not a file'
323
- expect(last_response.status).to eq(400)
324
- expect(last_response.body).to eq('file is invalid')
325
- end
369
+ post '/upload', file: file
370
+ expect(last_response.status).to eq(201)
371
+ expect(last_response.body).to eq(filename)
326
372
 
327
- it 'File' do
328
- subject.params do
329
- requires :file, coerce: File
330
- end
331
- subject.post '/upload' do
332
- params[:file][:filename]
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')
333
376
  end
334
377
 
335
- post '/upload', file: Rack::Test::UploadedFile.new(__FILE__)
336
- expect(last_response.status).to eq(201)
337
- expect(last_response.body).to eq(File.basename(__FILE__).to_s)
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
338
385
 
339
- post '/upload', file: 'not a file'
340
- expect(last_response.status).to eq(400)
341
- expect(last_response.body).to eq('file is invalid')
386
+ post '/upload', file: file
387
+ expect(last_response.status).to eq(201)
388
+ expect(last_response.body).to eq(filename)
342
389
 
343
- post '/upload', file: { filename: 'fake file', tempfile: '/etc/passwd' }
344
- expect(last_response.status).to eq(400)
345
- expect(last_response.body).to eq('file is invalid')
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')
393
+
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
398
+
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
406
+
407
+ post '/upload', files: [file]
408
+ expect(last_response.status).to eq(201)
409
+ expect(last_response.body).to eq(filename)
410
+ end
346
411
  end
347
412
 
348
413
  it 'Nests integers' do
@@ -359,6 +424,79 @@ describe Grape::Validations::CoerceValidator do
359
424
  expect(last_response.status).to eq(200)
360
425
  expect(last_response.body).to eq(integer_class_name)
361
426
  end
427
+
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
444
+ end
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
461
+ end
462
+
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
472
+
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
478
+
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
499
+ end
362
500
  end
363
501
 
364
502
  context 'using coerce_with' do
@@ -478,6 +616,46 @@ describe Grape::Validations::CoerceValidator do
478
616
  expect(last_response.body).to eq('3')
479
617
  end
480
618
 
619
+ context 'Integer type and coerce_with potentially returning nil' do
620
+ before do
621
+ subject.params do
622
+ requires :int, type: Integer, coerce_with: (lambda do |val|
623
+ if val == '0'
624
+ nil
625
+ elsif val.match?(/^-?\d+$/)
626
+ val.to_i
627
+ else
628
+ val
629
+ end
630
+ end)
631
+ end
632
+ subject.get '/' do
633
+ params[:int].class.to_s
634
+ end
635
+ end
636
+
637
+ it 'accepts value that coerces to nil' do
638
+ get '/', int: '0'
639
+
640
+ expect(last_response.status).to eq(200)
641
+ expect(last_response.body).to eq('NilClass')
642
+ end
643
+
644
+ it 'coerces to Integer' do
645
+ get '/', int: '1'
646
+
647
+ expect(last_response.status).to eq(200)
648
+ expect(last_response.body).to eq('Integer')
649
+ end
650
+
651
+ it 'returns invalid value if coercion returns a wrong type' do
652
+ get '/', int: 'lol'
653
+
654
+ expect(last_response.status).to eq(400)
655
+ expect(last_response.body).to eq('int is invalid')
656
+ end
657
+ end
658
+
481
659
  it 'must be supplied with :type or :coerce' do
482
660
  expect do
483
661
  subject.params do
@@ -298,4 +298,125 @@ describe Grape::Validations::DefaultValidator do
298
298
  end
299
299
  end
300
300
  end
301
+
302
+ context 'optional with nil as value' do
303
+ subject do
304
+ Class.new(Grape::API) do
305
+ default_format :json
306
+ end
307
+ end
308
+
309
+ def app
310
+ subject
311
+ end
312
+
313
+ context 'primitive types' do
314
+ [
315
+ [Integer, 0],
316
+ [Integer, 42],
317
+ [Float, 0.0],
318
+ [Float, 4.2],
319
+ [BigDecimal, 0.0],
320
+ [BigDecimal, 4.2],
321
+ [Numeric, 0],
322
+ [Numeric, 42],
323
+ [Date, Date.today],
324
+ [DateTime, DateTime.now],
325
+ [Time, Time.now],
326
+ [Time, Time.at(0)],
327
+ [Grape::API::Boolean, false],
328
+ [String, ''],
329
+ [String, 'non-empty-string'],
330
+ [Symbol, :symbol],
331
+ [TrueClass, true],
332
+ [FalseClass, false]
333
+ ].each do |type, default|
334
+ it 'respects the default value' do
335
+ subject.params do
336
+ optional :param, type: type, default: default
337
+ end
338
+ subject.get '/default_value' do
339
+ params[:param]
340
+ end
341
+
342
+ get '/default_value', param: nil
343
+ expect(last_response.status).to eq(200)
344
+ expect(last_response.body).to eq(default.to_json)
345
+ end
346
+ end
347
+ end
348
+
349
+ context 'structures types' do
350
+ [
351
+ [Hash, {}],
352
+ [Hash, { test: 'non-empty' }],
353
+ [Array, []],
354
+ [Array, ['non-empty']],
355
+ [Array[Integer], []],
356
+ [Set, []],
357
+ [Set, [1]]
358
+ ].each do |type, default|
359
+ it 'respects the default value' do
360
+ subject.params do
361
+ optional :param, type: type, default: default
362
+ end
363
+ subject.get '/default_value' do
364
+ params[:param]
365
+ end
366
+
367
+ get '/default_value', param: nil
368
+ expect(last_response.status).to eq(200)
369
+ expect(last_response.body).to eq(default.to_json)
370
+ end
371
+ end
372
+ end
373
+
374
+ context 'special types' do
375
+ [
376
+ [JSON, ''],
377
+ [JSON, { test: 'non-empty-string' }.to_json],
378
+ [Array[JSON], []],
379
+ [Array[JSON], [{ test: 'non-empty-string' }.to_json]],
380
+ [::File, ''],
381
+ [::File, { test: 'non-empty-string' }.to_json],
382
+ [Rack::Multipart::UploadedFile, ''],
383
+ [Rack::Multipart::UploadedFile, { test: 'non-empty-string' }.to_json]
384
+ ].each do |type, default|
385
+ it 'respects the default value' do
386
+ subject.params do
387
+ optional :param, type: type, default: default
388
+ end
389
+ subject.get '/default_value' do
390
+ params[:param]
391
+ end
392
+
393
+ get '/default_value', param: nil
394
+ expect(last_response.status).to eq(200)
395
+ expect(last_response.body).to eq(default.to_json)
396
+ end
397
+ end
398
+ end
399
+
400
+ context 'variant-member-type collections' do
401
+ [
402
+ [Array[Integer, String], [0, '']],
403
+ [Array[Integer, String], [42, 'non-empty-string']],
404
+ [[Integer, String, Array[Integer, String]], [0, '', [0, '']]],
405
+ [[Integer, String, Array[Integer, String]], [42, 'non-empty-string', [42, 'non-empty-string']]]
406
+ ].each do |type, default|
407
+ it 'respects the default value' do
408
+ subject.params do
409
+ optional :param, type: type, default: default
410
+ end
411
+ subject.get '/default_value' do
412
+ params[:param]
413
+ end
414
+
415
+ get '/default_value', param: nil
416
+ expect(last_response.status).to eq(200)
417
+ expect(last_response.body).to eq(default.to_json)
418
+ end
419
+ end
420
+ end
421
+ end
301
422
  end
@@ -319,7 +319,7 @@ describe Grape::Validations::ValuesValidator do
319
319
  expect(last_response.status).to eq 200
320
320
  end
321
321
 
322
- it 'allows for an optional param with a list of values' do
322
+ it 'accepts for an optional param with a list of values' do
323
323
  put('/optional_with_array_of_string_values', optional: nil)
324
324
  expect(last_response.status).to eq 200
325
325
  end
@@ -574,7 +574,7 @@ describe Grape::Validations do
574
574
  # NOTE: with body parameters in json or XML or similar this
575
575
  # should actually fail with: children[parents][name] is missing.
576
576
  expect(last_response.status).to eq(400)
577
- expect(last_response.body).to eq('children[1][parents] is missing')
577
+ expect(last_response.body).to eq('children[1][parents] is missing, children[0][parents][1][name] is missing, children[0][parents][1][name] is empty')
578
578
  end
579
579
 
580
580
  it 'errors when a parameter is not present in array within array' do
@@ -615,7 +615,7 @@ describe Grape::Validations do
615
615
 
616
616
  get '/within_array', children: [name: 'Jay']
617
617
  expect(last_response.status).to eq(400)
618
- expect(last_response.body).to eq('children[0][parents] is missing')
618
+ expect(last_response.body).to eq('children[0][parents] is missing, children[0][parents][0][name] is missing, children[0][parents][0][name] is empty')
619
619
  end
620
620
 
621
621
  it 'errors when param is not an Array' do
@@ -763,7 +763,7 @@ describe Grape::Validations do
763
763
  expect(last_response.status).to eq(200)
764
764
  put_with_json '/within_array', children: [name: 'Jay']
765
765
  expect(last_response.status).to eq(400)
766
- expect(last_response.body).to eq('children[0][parents] is missing')
766
+ expect(last_response.body).to eq('children[0][parents] is missing, children[0][parents][0][name] is missing')
767
767
  end
768
768
  end
769
769
 
@@ -838,7 +838,7 @@ describe Grape::Validations do
838
838
  it 'does internal validations if the outer group is present' do
839
839
  get '/nested_optional_group', items: [{ key: 'foo' }]
840
840
  expect(last_response.status).to eq(400)
841
- expect(last_response.body).to eq('items[0][required_subitems] is missing')
841
+ expect(last_response.body).to eq('items[0][required_subitems] is missing, items[0][required_subitems][0][value] is missing')
842
842
 
843
843
  get '/nested_optional_group', items: [{ key: 'foo', required_subitems: [{ value: 'bar' }] }]
844
844
  expect(last_response.status).to eq(200)
@@ -858,7 +858,7 @@ describe Grape::Validations do
858
858
  it 'handles validation within arrays' do
859
859
  get '/nested_optional_group', items: [{ key: 'foo' }]
860
860
  expect(last_response.status).to eq(400)
861
- expect(last_response.body).to eq('items[0][required_subitems] is missing')
861
+ expect(last_response.body).to eq('items[0][required_subitems] is missing, items[0][required_subitems][0][value] is missing')
862
862
 
863
863
  get '/nested_optional_group', items: [{ key: 'foo', required_subitems: [{ value: 'bar' }] }]
864
864
  expect(last_response.status).to eq(200)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bleigh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-11 00:00:00.000000000 Z
11
+ date: 2020-05-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -332,7 +332,9 @@ files:
332
332
  - spec/grape/validations/multiple_attributes_iterator_spec.rb
333
333
  - spec/grape/validations/params_scope_spec.rb
334
334
  - spec/grape/validations/single_attribute_iterator_spec.rb
335
+ - spec/grape/validations/types/array_coercer_spec.rb
335
336
  - spec/grape/validations/types/primitive_coercer_spec.rb
337
+ - spec/grape/validations/types/set_coercer_spec.rb
336
338
  - spec/grape/validations/types_spec.rb
337
339
  - spec/grape/validations/validators/all_or_none_spec.rb
338
340
  - spec/grape/validations/validators/allow_blank_spec.rb
@@ -364,9 +366,9 @@ licenses:
364
366
  - MIT
365
367
  metadata:
366
368
  bug_tracker_uri: https://github.com/ruby-grape/grape/issues
367
- changelog_uri: https://github.com/ruby-grape/grape/blob/v1.3.1/CHANGELOG.md
368
- documentation_uri: https://www.rubydoc.info/gems/grape/1.3.1
369
- source_code_uri: https://github.com/ruby-grape/grape/tree/v1.3.1
369
+ changelog_uri: https://github.com/ruby-grape/grape/blob/v1.3.3/CHANGELOG.md
370
+ documentation_uri: https://www.rubydoc.info/gems/grape/1.3.3
371
+ source_code_uri: https://github.com/ruby-grape/grape/tree/v1.3.3
370
372
  post_install_message:
371
373
  rdoc_options: []
372
374
  require_paths:
@@ -415,6 +417,8 @@ test_files:
415
417
  - spec/grape/api_remount_spec.rb
416
418
  - spec/grape/validations/types_spec.rb
417
419
  - spec/grape/validations/attributes_iterator_spec.rb
420
+ - spec/grape/validations/types/array_coercer_spec.rb
421
+ - spec/grape/validations/types/set_coercer_spec.rb
418
422
  - spec/grape/validations/types/primitive_coercer_spec.rb
419
423
  - spec/grape/validations/validators/regexp_spec.rb
420
424
  - spec/grape/validations/validators/default_spec.rb