grape 1.3.1 → 1.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -0
- data/LICENSE +1 -1
- data/README.md +19 -6
- data/UPGRADING.md +120 -16
- data/lib/grape/api/instance.rb +12 -7
- data/lib/grape/dsl/inside_route.rb +37 -14
- data/lib/grape/http/headers.rb +1 -0
- data/lib/grape/middleware/versioner/header.rb +1 -1
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
- data/lib/grape/path.rb +2 -2
- data/lib/grape/router/attribute_translator.rb +23 -2
- data/lib/grape/router/route.rb +3 -22
- data/lib/grape/router.rb +6 -14
- data/lib/grape/util/base_inheritable.rb +9 -6
- data/lib/grape/util/reverse_stackable_values.rb +3 -1
- data/lib/grape/util/stackable_values.rb +3 -1
- 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 +1 -1
- data/lib/grape/validations/types/dry_type_coercer.rb +36 -1
- data/lib/grape/validations/types/file.rb +15 -13
- data/lib/grape/validations/types/json.rb +40 -36
- data/lib/grape/validations/types/primitive_coercer.rb +11 -4
- 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/types.rb +6 -5
- data/lib/grape/validations/validators/coerce.rb +3 -10
- data/lib/grape/validations/validators/default.rb +0 -1
- data/lib/grape/validations/validators/regexp.rb +1 -1
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api/instance_spec.rb +50 -0
- data/spec/grape/endpoint_spec.rb +18 -5
- data/spec/grape/path_spec.rb +4 -4
- data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
- data/spec/grape/validations/types/primitive_coercer_spec.rb +5 -1
- 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 +207 -29
- data/spec/grape/validations/validators/default_spec.rb +121 -0
- data/spec/grape/validations/validators/values_spec.rb +1 -1
- data/spec/grape/validations_spec.rb +5 -5
- 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 '
|
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
|
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
|
-
|
311
|
-
|
312
|
-
|
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
|
-
|
319
|
-
|
320
|
-
|
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
|
-
|
323
|
-
|
324
|
-
|
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
|
-
|
328
|
-
|
329
|
-
|
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
|
-
|
336
|
-
|
337
|
-
|
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
|
-
|
340
|
-
|
341
|
-
|
386
|
+
post '/upload', file: file
|
387
|
+
expect(last_response.status).to eq(201)
|
388
|
+
expect(last_response.body).to eq(filename)
|
342
389
|
|
343
|
-
|
344
|
-
|
345
|
-
|
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 '
|
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.
|
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-
|
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.
|
368
|
-
documentation_uri: https://www.rubydoc.info/gems/grape/1.3.
|
369
|
-
source_code_uri: https://github.com/ruby-grape/grape/tree/v1.3.
|
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
|