grape 1.3.0 → 1.5.2

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +119 -1
  3. data/LICENSE +1 -1
  4. data/README.md +123 -29
  5. data/UPGRADING.md +265 -39
  6. data/lib/grape/api/instance.rb +32 -31
  7. data/lib/grape/api.rb +5 -5
  8. data/lib/grape/content_types.rb +34 -0
  9. data/lib/grape/dsl/callbacks.rb +1 -1
  10. data/lib/grape/dsl/helpers.rb +2 -1
  11. data/lib/grape/dsl/inside_route.rb +77 -43
  12. data/lib/grape/dsl/parameters.rb +12 -8
  13. data/lib/grape/dsl/routing.rb +12 -11
  14. data/lib/grape/dsl/validations.rb +18 -1
  15. data/lib/grape/eager_load.rb +1 -1
  16. data/lib/grape/endpoint.rb +8 -6
  17. data/lib/grape/exceptions/base.rb +0 -4
  18. data/lib/grape/exceptions/validation.rb +1 -1
  19. data/lib/grape/exceptions/validation_errors.rb +12 -13
  20. data/lib/grape/http/headers.rb +26 -0
  21. data/lib/grape/middleware/auth/base.rb +3 -3
  22. data/lib/grape/middleware/base.rb +4 -5
  23. data/lib/grape/middleware/error.rb +11 -13
  24. data/lib/grape/middleware/formatter.rb +3 -3
  25. data/lib/grape/middleware/stack.rb +10 -2
  26. data/lib/grape/middleware/versioner/header.rb +4 -4
  27. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  28. data/lib/grape/middleware/versioner/path.rb +1 -1
  29. data/lib/grape/namespace.rb +12 -2
  30. data/lib/grape/path.rb +13 -3
  31. data/lib/grape/request.rb +13 -8
  32. data/lib/grape/router/attribute_translator.rb +26 -5
  33. data/lib/grape/router/pattern.rb +17 -16
  34. data/lib/grape/router/route.rb +5 -24
  35. data/lib/grape/router.rb +26 -30
  36. data/lib/grape/{serve_file → serve_stream}/file_body.rb +1 -1
  37. data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +1 -1
  38. data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +8 -8
  39. data/lib/grape/util/base_inheritable.rb +15 -8
  40. data/lib/grape/util/cache.rb +20 -0
  41. data/lib/grape/util/lazy_object.rb +43 -0
  42. data/lib/grape/util/lazy_value.rb +1 -0
  43. data/lib/grape/util/reverse_stackable_values.rb +2 -0
  44. data/lib/grape/util/stackable_values.rb +7 -20
  45. data/lib/grape/validations/attributes_iterator.rb +8 -0
  46. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  47. data/lib/grape/validations/params_scope.rb +10 -8
  48. data/lib/grape/validations/single_attribute_iterator.rb +1 -1
  49. data/lib/grape/validations/types/array_coercer.rb +14 -5
  50. data/lib/grape/validations/types/build_coercer.rb +5 -8
  51. data/lib/grape/validations/types/custom_type_coercer.rb +16 -2
  52. data/lib/grape/validations/types/dry_type_coercer.rb +36 -1
  53. data/lib/grape/validations/types/file.rb +15 -12
  54. data/lib/grape/validations/types/invalid_value.rb +24 -0
  55. data/lib/grape/validations/types/json.rb +40 -36
  56. data/lib/grape/validations/types/primitive_coercer.rb +15 -6
  57. data/lib/grape/validations/types/set_coercer.rb +6 -4
  58. data/lib/grape/validations/types/variant_collection_coercer.rb +1 -1
  59. data/lib/grape/validations/types.rb +7 -9
  60. data/lib/grape/validations/validator_factory.rb +1 -1
  61. data/lib/grape/validations/validators/as.rb +1 -1
  62. data/lib/grape/validations/validators/base.rb +8 -8
  63. data/lib/grape/validations/validators/coerce.rb +11 -15
  64. data/lib/grape/validations/validators/default.rb +3 -5
  65. data/lib/grape/validations/validators/exactly_one_of.rb +4 -2
  66. data/lib/grape/validations/validators/except_values.rb +1 -1
  67. data/lib/grape/validations/validators/multiple_params_base.rb +2 -1
  68. data/lib/grape/validations/validators/regexp.rb +1 -1
  69. data/lib/grape/validations/validators/values.rb +1 -1
  70. data/lib/grape/version.rb +1 -1
  71. data/lib/grape.rb +5 -5
  72. data/spec/grape/api/instance_spec.rb +50 -0
  73. data/spec/grape/api_remount_spec.rb +9 -4
  74. data/spec/grape/api_spec.rb +82 -6
  75. data/spec/grape/dsl/inside_route_spec.rb +182 -33
  76. data/spec/grape/endpoint/declared_spec.rb +601 -0
  77. data/spec/grape/endpoint_spec.rb +0 -521
  78. data/spec/grape/entity_spec.rb +7 -1
  79. data/spec/grape/exceptions/validation_errors_spec.rb +2 -2
  80. data/spec/grape/integration/rack_sendfile_spec.rb +12 -8
  81. data/spec/grape/middleware/auth/strategies_spec.rb +1 -1
  82. data/spec/grape/middleware/error_spec.rb +1 -1
  83. data/spec/grape/middleware/formatter_spec.rb +3 -3
  84. data/spec/grape/middleware/stack_spec.rb +10 -0
  85. data/spec/grape/path_spec.rb +4 -4
  86. data/spec/grape/request_spec.rb +1 -1
  87. data/spec/grape/validations/instance_behaivour_spec.rb +1 -1
  88. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +13 -3
  89. data/spec/grape/validations/params_scope_spec.rb +26 -0
  90. data/spec/grape/validations/single_attribute_iterator_spec.rb +17 -6
  91. data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
  92. data/spec/grape/validations/types/primitive_coercer_spec.rb +135 -0
  93. data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
  94. data/spec/grape/validations/types_spec.rb +1 -1
  95. data/spec/grape/validations/validators/coerce_spec.rb +366 -86
  96. data/spec/grape/validations/validators/default_spec.rb +170 -0
  97. data/spec/grape/validations/validators/exactly_one_of_spec.rb +12 -12
  98. data/spec/grape/validations/validators/except_values_spec.rb +1 -0
  99. data/spec/grape/validations/validators/values_spec.rb +1 -1
  100. data/spec/grape/validations_spec.rb +298 -30
  101. data/spec/integration/eager_load/eager_load_spec.rb +15 -0
  102. data/spec/shared/versioning_examples.rb +20 -20
  103. data/spec/spec_helper.rb +3 -10
  104. data/spec/support/chunks.rb +14 -0
  105. data/spec/support/eager_load.rb +19 -0
  106. data/spec/support/versioned_helpers.rb +4 -6
  107. metadata +27 -10
  108. data/lib/grape/util/content_types.rb +0 -28
@@ -280,527 +280,6 @@ describe Grape::Endpoint do
280
280
  end
281
281
  end
282
282
 
283
- describe '#declared' do
284
- before do
285
- subject.format :json
286
- subject.params do
287
- requires :first
288
- optional :second
289
- optional :third, default: 'third-default'
290
- optional :nested, type: Hash do
291
- optional :fourth
292
- optional :fifth
293
- optional :nested_two, type: Hash do
294
- optional :sixth
295
- optional :nested_three, type: Hash do
296
- optional :seventh
297
- end
298
- end
299
- end
300
- optional :nested_arr, type: Array do
301
- optional :eighth
302
- end
303
- end
304
- end
305
-
306
- context 'when params are not built with default class' do
307
- it 'returns an object that corresponds with the params class - hash with indifferent access' do
308
- subject.params do
309
- build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder
310
- end
311
- subject.get '/declared' do
312
- d = declared(params, include_missing: true)
313
- { declared_class: d.class.to_s }
314
- end
315
-
316
- get '/declared?first=present'
317
- expect(JSON.parse(last_response.body)['declared_class']).to eq('ActiveSupport::HashWithIndifferentAccess')
318
- end
319
-
320
- it 'returns an object that corresponds with the params class - hashie mash' do
321
- subject.params do
322
- build_with Grape::Extensions::Hashie::Mash::ParamBuilder
323
- end
324
- subject.get '/declared' do
325
- d = declared(params, include_missing: true)
326
- { declared_class: d.class.to_s }
327
- end
328
-
329
- get '/declared?first=present'
330
- expect(JSON.parse(last_response.body)['declared_class']).to eq('Hashie::Mash')
331
- end
332
-
333
- it 'returns an object that corresponds with the params class - hash' do
334
- subject.params do
335
- build_with Grape::Extensions::Hash::ParamBuilder
336
- end
337
- subject.get '/declared' do
338
- d = declared(params, include_missing: true)
339
- { declared_class: d.class.to_s }
340
- end
341
-
342
- get '/declared?first=present'
343
- expect(JSON.parse(last_response.body)['declared_class']).to eq('Hash')
344
- end
345
- end
346
-
347
- it 'should show nil for nested params if include_missing is true' do
348
- subject.get '/declared' do
349
- declared(params, include_missing: true)
350
- end
351
-
352
- get '/declared?first=present'
353
- expect(last_response.status).to eq(200)
354
- expect(JSON.parse(last_response.body)['nested']['fourth']).to be_nil
355
- end
356
-
357
- it 'does not work in a before filter' do
358
- subject.before do
359
- declared(params)
360
- end
361
- subject.get('/declared') { declared(params) }
362
-
363
- expect { get('/declared') }.to raise_error(
364
- Grape::DSL::InsideRoute::MethodNotYetAvailable
365
- )
366
- end
367
-
368
- it 'has as many keys as there are declared params' do
369
- subject.get '/declared' do
370
- declared(params)
371
- end
372
- get '/declared?first=present'
373
- expect(last_response.status).to eq(200)
374
- expect(JSON.parse(last_response.body).keys.size).to eq(5)
375
- end
376
-
377
- it 'has a optional param with default value all the time' do
378
- subject.get '/declared' do
379
- declared(params)
380
- end
381
- get '/declared?first=one'
382
- expect(last_response.status).to eq(200)
383
- expect(JSON.parse(last_response.body)['third']).to eql('third-default')
384
- end
385
-
386
- it 'builds nested params' do
387
- subject.get '/declared' do
388
- declared(params)
389
- end
390
-
391
- get '/declared?first=present&nested[fourth]=1'
392
- expect(last_response.status).to eq(200)
393
- expect(JSON.parse(last_response.body)['nested'].keys.size).to eq 3
394
- end
395
-
396
- it 'builds nested params when given array' do
397
- subject.get '/dummy' do
398
- end
399
- subject.params do
400
- requires :first
401
- optional :second
402
- optional :third, default: 'third-default'
403
- optional :nested, type: Array do
404
- optional :fourth
405
- end
406
- end
407
- subject.get '/declared' do
408
- declared(params)
409
- end
410
-
411
- get '/declared?first=present&nested[][fourth]=1&nested[][fourth]=2'
412
- expect(last_response.status).to eq(200)
413
- expect(JSON.parse(last_response.body)['nested'].size).to eq 2
414
- end
415
-
416
- context 'sets nested objects when the param is missing' do
417
- it 'to be a hash when include_missing is true' do
418
- subject.get '/declared' do
419
- declared(params, include_missing: true)
420
- end
421
-
422
- get '/declared?first=present'
423
- expect(last_response.status).to eq(200)
424
- expect(JSON.parse(last_response.body)['nested']).to be_a(Hash)
425
- end
426
-
427
- it 'to be an array when include_missing is true' do
428
- subject.get '/declared' do
429
- declared(params, include_missing: true)
430
- end
431
-
432
- get '/declared?first=present'
433
- expect(last_response.status).to eq(200)
434
- expect(JSON.parse(last_response.body)['nested_arr']).to be_a(Array)
435
- end
436
-
437
- it 'to be nil when include_missing is false' do
438
- subject.get '/declared' do
439
- declared(params, include_missing: false)
440
- end
441
-
442
- get '/declared?first=present'
443
- expect(last_response.status).to eq(200)
444
- expect(JSON.parse(last_response.body)['nested']).to be_nil
445
- end
446
- end
447
-
448
- it 'filters out any additional params that are given' do
449
- subject.get '/declared' do
450
- declared(params)
451
- end
452
- get '/declared?first=one&other=two'
453
- expect(last_response.status).to eq(200)
454
- expect(JSON.parse(last_response.body).key?(:other)).to eq false
455
- end
456
-
457
- it 'stringifies if that option is passed' do
458
- subject.get '/declared' do
459
- declared(params, stringify: true)
460
- end
461
-
462
- get '/declared?first=one&other=two'
463
- expect(last_response.status).to eq(200)
464
- expect(JSON.parse(last_response.body)['first']).to eq 'one'
465
- end
466
-
467
- it 'does not include missing attributes if that option is passed' do
468
- subject.get '/declared' do
469
- error! 'expected nil', 400 if declared(params, include_missing: false).key?(:second)
470
- ''
471
- end
472
-
473
- get '/declared?first=one&other=two'
474
- expect(last_response.status).to eq(200)
475
- end
476
-
477
- it 'does not include renamed missing attributes if that option is passed' do
478
- subject.params do
479
- optional :renamed_original, as: :renamed
480
- end
481
- subject.get '/declared' do
482
- error! 'expected nil', 400 if declared(params, include_missing: false).key?(:renamed)
483
- ''
484
- end
485
-
486
- get '/declared?first=one&other=two'
487
- expect(last_response.status).to eq(200)
488
- end
489
-
490
- it 'includes attributes with value that evaluates to false' do
491
- subject.params do
492
- requires :first
493
- optional :boolean
494
- end
495
-
496
- subject.post '/declared' do
497
- error!('expected false', 400) if declared(params, include_missing: false)[:boolean] != false
498
- ''
499
- end
500
-
501
- post '/declared', ::Grape::Json.dump(first: 'one', boolean: false), 'CONTENT_TYPE' => 'application/json'
502
- expect(last_response.status).to eq(201)
503
- end
504
-
505
- it 'includes attributes with value that evaluates to nil' do
506
- subject.params do
507
- requires :first
508
- optional :second
509
- end
510
-
511
- subject.post '/declared' do
512
- error!('expected nil', 400) unless declared(params, include_missing: false)[:second].nil?
513
- ''
514
- end
515
-
516
- post '/declared', ::Grape::Json.dump(first: 'one', second: nil), 'CONTENT_TYPE' => 'application/json'
517
- expect(last_response.status).to eq(201)
518
- end
519
-
520
- it 'includes missing attributes with defaults when there are nested hashes' do
521
- subject.get '/dummy' do
522
- end
523
-
524
- subject.params do
525
- requires :first
526
- optional :second
527
- optional :third, default: nil
528
- optional :nested, type: Hash do
529
- optional :fourth, default: nil
530
- optional :fifth, default: nil
531
- requires :nested_nested, type: Hash do
532
- optional :sixth, default: 'sixth-default'
533
- optional :seven, default: nil
534
- end
535
- end
536
- end
537
-
538
- subject.get '/declared' do
539
- declared(params, include_missing: false)
540
- end
541
-
542
- get '/declared?first=present&nested[fourth]=&nested[nested_nested][sixth]=sixth'
543
- json = JSON.parse(last_response.body)
544
- expect(last_response.status).to eq(200)
545
- expect(json['first']).to eq 'present'
546
- expect(json['nested'].keys).to eq %w[fourth fifth nested_nested]
547
- expect(json['nested']['fourth']).to eq ''
548
- expect(json['nested']['nested_nested'].keys).to eq %w[sixth seven]
549
- expect(json['nested']['nested_nested']['sixth']).to eq 'sixth'
550
- end
551
-
552
- it 'does not include missing attributes when there are nested hashes' do
553
- subject.get '/dummy' do
554
- end
555
-
556
- subject.params do
557
- requires :first
558
- optional :second
559
- optional :third
560
- optional :nested, type: Hash do
561
- optional :fourth
562
- optional :fifth
563
- end
564
- end
565
-
566
- subject.get '/declared' do
567
- declared(params, include_missing: false)
568
- end
569
-
570
- get '/declared?first=present&nested[fourth]=4'
571
- json = JSON.parse(last_response.body)
572
- expect(last_response.status).to eq(200)
573
- expect(json['first']).to eq 'present'
574
- expect(json['nested'].keys).to eq %w[fourth]
575
- expect(json['nested']['fourth']).to eq '4'
576
- end
577
- end
578
-
579
- describe '#declared; call from child namespace' do
580
- before do
581
- subject.format :json
582
- subject.namespace :parent do
583
- params do
584
- requires :parent_name, type: String
585
- end
586
-
587
- namespace ':parent_name' do
588
- params do
589
- requires :child_name, type: String
590
- requires :child_age, type: Integer
591
- end
592
-
593
- namespace ':child_name' do
594
- params do
595
- requires :grandchild_name, type: String
596
- end
597
-
598
- get ':grandchild_name' do
599
- {
600
- 'params' => params,
601
- 'without_parent_namespaces' => declared(params, include_parent_namespaces: false),
602
- 'with_parent_namespaces' => declared(params, include_parent_namespaces: true)
603
- }
604
- end
605
- end
606
- end
607
- end
608
-
609
- get '/parent/foo/bar/baz', child_age: 5, extra: 'hello'
610
- end
611
-
612
- let(:parsed_response) { JSON.parse(last_response.body, symbolize_names: true) }
613
-
614
- it { expect(last_response.status).to eq 200 }
615
-
616
- context 'with include_parent_namespaces: false' do
617
- it 'returns declared parameters only from current namespace' do
618
- expect(parsed_response[:without_parent_namespaces]).to eq(
619
- grandchild_name: 'baz'
620
- )
621
- end
622
- end
623
-
624
- context 'with include_parent_namespaces: true' do
625
- it 'returns declared parameters from every parent namespace' do
626
- expect(parsed_response[:with_parent_namespaces]).to eq(
627
- parent_name: 'foo',
628
- child_name: 'bar',
629
- grandchild_name: 'baz',
630
- child_age: 5
631
- )
632
- end
633
- end
634
-
635
- context 'without declaration' do
636
- it 'returns all requested parameters' do
637
- expect(parsed_response[:params]).to eq(
638
- parent_name: 'foo',
639
- child_name: 'bar',
640
- grandchild_name: 'baz',
641
- child_age: 5,
642
- extra: 'hello'
643
- )
644
- end
645
- end
646
- end
647
-
648
- describe '#declared; from a nested mounted endpoint' do
649
- before do
650
- doubly_mounted = Class.new(Grape::API)
651
- doubly_mounted.namespace :more do
652
- params do
653
- requires :y, type: Integer
654
- end
655
- route_param :y do
656
- get do
657
- {
658
- params: params,
659
- declared_params: declared(params)
660
- }
661
- end
662
- end
663
- end
664
-
665
- mounted = Class.new(Grape::API)
666
- mounted.namespace :another do
667
- params do
668
- requires :mount_space, type: Integer
669
- end
670
- route_param :mount_space do
671
- mount doubly_mounted
672
- end
673
- end
674
-
675
- subject.format :json
676
- subject.namespace :something do
677
- params do
678
- requires :id, type: Integer
679
- end
680
- resource ':id' do
681
- mount mounted
682
- end
683
- end
684
- end
685
-
686
- it 'can access parent attributes' do
687
- get '/something/123/another/456/more/789'
688
- expect(last_response.status).to eq 200
689
- json = JSON.parse(last_response.body, symbolize_names: true)
690
-
691
- # test all three levels of params
692
- expect(json[:declared_params][:y]).to eq 789
693
- expect(json[:declared_params][:mount_space]).to eq 456
694
- expect(json[:declared_params][:id]).to eq 123
695
- end
696
- end
697
-
698
- describe '#declared; mixed nesting' do
699
- before do
700
- subject.format :json
701
- subject.resource :users do
702
- route_param :id, type: Integer, desc: 'ID desc' do
703
- # Adding this causes route_setting(:declared_params) to be nil for the
704
- # get block in namespace 'foo' below
705
- get do
706
- end
707
-
708
- namespace 'foo' do
709
- get do
710
- {
711
- params: params,
712
- declared_params: declared(params),
713
- declared_params_no_parent: declared(params, include_parent_namespaces: false)
714
- }
715
- end
716
- end
717
- end
718
- end
719
- end
720
-
721
- it 'can access parent route_param' do
722
- get '/users/123/foo', bar: 'bar'
723
- expect(last_response.status).to eq 200
724
- json = JSON.parse(last_response.body, symbolize_names: true)
725
-
726
- expect(json[:declared_params][:id]).to eq 123
727
- expect(json[:declared_params_no_parent][:id]).to eq nil
728
- end
729
- end
730
-
731
- describe '#declared; with multiple route_param' do
732
- before do
733
- mounted = Class.new(Grape::API)
734
- mounted.namespace :albums do
735
- get do
736
- declared(params)
737
- end
738
- end
739
-
740
- subject.format :json
741
- subject.namespace :artists do
742
- route_param :id, type: Integer do
743
- get do
744
- declared(params)
745
- end
746
-
747
- params do
748
- requires :filter, type: String
749
- end
750
- get :some_route do
751
- declared(params)
752
- end
753
- end
754
-
755
- route_param :artist_id, type: Integer do
756
- namespace :compositions do
757
- get do
758
- declared(params)
759
- end
760
- end
761
- end
762
-
763
- route_param :compositor_id, type: Integer do
764
- mount mounted
765
- end
766
- end
767
- end
768
-
769
- it 'return only :id without :artist_id' do
770
- get '/artists/1'
771
- json = JSON.parse(last_response.body, symbolize_names: true)
772
-
773
- expect(json.key?(:id)).to be_truthy
774
- expect(json.key?(:artist_id)).not_to be_truthy
775
- end
776
-
777
- it 'return only :artist_id without :id' do
778
- get '/artists/1/compositions'
779
- json = JSON.parse(last_response.body, symbolize_names: true)
780
-
781
- expect(json.key?(:artist_id)).to be_truthy
782
- expect(json.key?(:id)).not_to be_truthy
783
- end
784
-
785
- it 'return :filter and :id parameters in declared for second enpoint inside route_param' do
786
- get '/artists/1/some_route', filter: 'some_filter'
787
- json = JSON.parse(last_response.body, symbolize_names: true)
788
-
789
- expect(json.key?(:filter)).to be_truthy
790
- expect(json.key?(:id)).to be_truthy
791
- expect(json.key?(:artist_id)).not_to be_truthy
792
- end
793
-
794
- it 'return :compositor_id for mounter in route_param' do
795
- get '/artists/1/albums'
796
- json = JSON.parse(last_response.body, symbolize_names: true)
797
-
798
- expect(json.key?(:compositor_id)).to be_truthy
799
- expect(json.key?(:id)).not_to be_truthy
800
- expect(json.key?(:artist_id)).not_to be_truthy
801
- end
802
- end
803
-
804
283
  describe '#params' do
805
284
  it 'is available to the caller' do
806
285
  subject.get('/hey') do
@@ -116,7 +116,7 @@ describe Grape::Entity do
116
116
  expect(last_response.body).to eq('Auto-detect!')
117
117
  end
118
118
 
119
- it 'does not run autodetection for Entity when explicitely provided' do
119
+ it 'does not run autodetection for Entity when explicitly provided' do
120
120
  entity = Class.new(Grape::Entity)
121
121
  some_array = []
122
122
 
@@ -181,6 +181,7 @@ describe Grape::Entity do
181
181
  subject.get '/example' do
182
182
  c = Class.new do
183
183
  attr_reader :id
184
+
184
185
  def initialize(id)
185
186
  @id = id
186
187
  end
@@ -202,6 +203,7 @@ describe Grape::Entity do
202
203
  subject.get '/examples' do
203
204
  c = Class.new do
204
205
  attr_reader :id
206
+
205
207
  def initialize(id)
206
208
  @id = id
207
209
  end
@@ -226,6 +228,7 @@ describe Grape::Entity do
226
228
  subject.get '/example' do
227
229
  c = Class.new do
228
230
  attr_reader :name
231
+
229
232
  def initialize(args)
230
233
  @name = args[:name] || 'no name set'
231
234
  end
@@ -255,6 +258,7 @@ XML
255
258
  subject.get '/example' do
256
259
  c = Class.new do
257
260
  attr_reader :name
261
+
258
262
  def initialize(args)
259
263
  @name = args[:name] || 'no name set'
260
264
  end
@@ -284,6 +288,7 @@ XML
284
288
  subject.get '/example' do
285
289
  c = Class.new do
286
290
  attr_reader :name
291
+
287
292
  def initialize(args)
288
293
  @name = args[:name] || 'no name set'
289
294
  end
@@ -302,6 +307,7 @@ XML
302
307
  it 'present with multiple entities using optional symbol' do
303
308
  user = Class.new do
304
309
  attr_reader :name
310
+
305
311
  def initialize(args)
306
312
  @name = args[:name] || 'no name set'
307
313
  end
@@ -81,8 +81,8 @@ describe Grape::Exceptions::ValidationErrors do
81
81
  expect(last_response.status).to eq(400)
82
82
  expect(JSON.parse(last_response.body)).to eq(
83
83
  [
84
- 'params' => %w[beer wine juice],
85
- 'messages' => ['are missing, exactly one parameter must be provided']
84
+ 'params' => %w[beer wine],
85
+ 'messages' => ['are mutually exclusive']
86
86
  ]
87
87
  )
88
88
  end
@@ -4,12 +4,16 @@ require 'spec_helper'
4
4
 
5
5
  describe Rack::Sendfile do
6
6
  subject do
7
- send_file = file_streamer
7
+ content_object = file_object
8
8
  app = Class.new(Grape::API) do
9
9
  use Rack::Sendfile
10
10
  format :json
11
11
  get do
12
- file send_file
12
+ if content_object.is_a?(String)
13
+ sendfile content_object
14
+ else
15
+ stream content_object
16
+ end
13
17
  end
14
18
  end
15
19
 
@@ -22,9 +26,9 @@ describe Rack::Sendfile do
22
26
  app.call(env)
23
27
  end
24
28
 
25
- context do
26
- let(:file_streamer) do
27
- double(:file_streamer, to_path: '/accel/mapping/some/path')
29
+ context 'when calling sendfile' do
30
+ let(:file_object) do
31
+ '/accel/mapping/some/path'
28
32
  end
29
33
 
30
34
  it 'contains Sendfile headers' do
@@ -33,9 +37,9 @@ describe Rack::Sendfile do
33
37
  end
34
38
  end
35
39
 
36
- context do
37
- let(:file_streamer) do
38
- double(:file_streamer)
40
+ context 'when streaming non file content' do
41
+ let(:file_object) do
42
+ double(:file_object, each: nil)
39
43
  end
40
44
 
41
45
  it 'not contains Sendfile headers' do
@@ -36,7 +36,7 @@ describe Grape::Middleware::Auth::Strategies do
36
36
  RSpec::Matchers.define :be_challenge do
37
37
  match do |actual_response|
38
38
  actual_response.status == 401 &&
39
- actual_response['WWW-Authenticate'] =~ /^Digest / &&
39
+ actual_response['WWW-Authenticate'].start_with?('Digest ') &&
40
40
  actual_response.body.empty?
41
41
  end
42
42
  end
@@ -30,7 +30,7 @@ describe Grape::Middleware::Error do
30
30
  opts = options
31
31
  Rack::Builder.app do
32
32
  use Spec::Support::EndpointFaker
33
- use Grape::Middleware::Error, opts
33
+ use Grape::Middleware::Error, **opts
34
34
  run ErrorSpec::ErrApp
35
35
  end
36
36
  end
@@ -380,7 +380,7 @@ describe Grape::Middleware::Formatter do
380
380
 
381
381
  context 'send file' do
382
382
  let(:file) { double(File) }
383
- let(:file_body) { Grape::ServeFile::FileResponse.new(file) }
383
+ let(:file_body) { Grape::ServeStream::StreamResponse.new(file) }
384
384
  let(:app) { ->(_env) { [200, {}, file_body] } }
385
385
 
386
386
  it 'returns a file response' do
@@ -402,10 +402,10 @@ describe Grape::Middleware::Formatter do
402
402
  let(:app) { ->(_env) { [200, {}, ['']] } }
403
403
  before do
404
404
  Grape::Formatter.register :invalid, InvalidFormatter
405
- Grape::ContentTypes::CONTENT_TYPES[:invalid] = 'application/x-invalid'
405
+ Grape::ContentTypes.register :invalid, 'application/x-invalid'
406
406
  end
407
407
  after do
408
- Grape::ContentTypes::CONTENT_TYPES.delete(:invalid)
408
+ Grape::ContentTypes.default_elements.delete(:invalid)
409
409
  Grape::Formatter.default_elements.delete(:invalid)
410
410
  end
411
411
 
@@ -8,6 +8,7 @@ describe Grape::Middleware::Stack do
8
8
  class BarMiddleware; end
9
9
  class BlockMiddleware
10
10
  attr_reader :block
11
+
11
12
  def initialize(&block)
12
13
  @block = block
13
14
  end
@@ -111,6 +112,15 @@ describe Grape::Middleware::Stack do
111
112
  expect(subject[1]).to eq(StackSpec::BlockMiddleware)
112
113
  expect(subject[2]).to eq(StackSpec::BarMiddleware)
113
114
  end
115
+
116
+ context 'middleware spec with proc declaration exists' do
117
+ let(:middleware_spec_with_proc) { [:use, StackSpec::FooMiddleware, proc] }
118
+
119
+ it 'properly forwards spec arguments' do
120
+ expect(subject).to receive(:use).with(StackSpec::FooMiddleware)
121
+ subject.merge_with([middleware_spec_with_proc])
122
+ end
123
+ end
114
124
  end
115
125
 
116
126
  describe '#build' do