grape 1.5.3 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +23 -3
  4. data/UPGRADING.md +43 -1
  5. data/grape.gemspec +5 -5
  6. data/lib/grape/api/instance.rb +13 -17
  7. data/lib/grape/api.rb +5 -12
  8. data/lib/grape/cookies.rb +2 -0
  9. data/lib/grape/dsl/desc.rb +3 -5
  10. data/lib/grape/dsl/helpers.rb +6 -4
  11. data/lib/grape/dsl/inside_route.rb +17 -8
  12. data/lib/grape/dsl/middleware.rb +4 -4
  13. data/lib/grape/dsl/parameters.rb +3 -3
  14. data/lib/grape/dsl/request_response.rb +9 -6
  15. data/lib/grape/dsl/routing.rb +2 -2
  16. data/lib/grape/dsl/settings.rb +5 -5
  17. data/lib/grape/endpoint.rb +20 -35
  18. data/lib/grape/error_formatter/json.rb +2 -6
  19. data/lib/grape/error_formatter/xml.rb +2 -6
  20. data/lib/grape/exceptions/validation.rb +1 -2
  21. data/lib/grape/formatter/json.rb +1 -0
  22. data/lib/grape/formatter/serializable_hash.rb +2 -1
  23. data/lib/grape/formatter/xml.rb +1 -0
  24. data/lib/grape/middleware/base.rb +2 -0
  25. data/lib/grape/middleware/formatter.rb +4 -4
  26. data/lib/grape/middleware/stack.rb +2 -2
  27. data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
  28. data/lib/grape/middleware/versioner/header.rb +6 -4
  29. data/lib/grape/middleware/versioner/param.rb +1 -0
  30. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  31. data/lib/grape/middleware/versioner/path.rb +2 -0
  32. data/lib/grape/path.rb +1 -0
  33. data/lib/grape/request.rb +1 -0
  34. data/lib/grape/router/pattern.rb +1 -1
  35. data/lib/grape/router/route.rb +2 -2
  36. data/lib/grape/router.rb +6 -0
  37. data/lib/grape/util/inheritable_setting.rb +1 -3
  38. data/lib/grape/util/lazy_value.rb +3 -2
  39. data/lib/grape/validations/params_scope.rb +88 -55
  40. data/lib/grape/validations/types/custom_type_coercer.rb +1 -0
  41. data/lib/grape/validations/types/dry_type_coercer.rb +1 -1
  42. data/lib/grape/validations/types/json.rb +2 -1
  43. data/lib/grape/validations/types/primitive_coercer.rb +3 -3
  44. data/lib/grape/validations/validators/all_or_none.rb +1 -0
  45. data/lib/grape/validations/validators/as.rb +4 -8
  46. data/lib/grape/validations/validators/at_least_one_of.rb +1 -0
  47. data/lib/grape/validations/validators/base.rb +4 -1
  48. data/lib/grape/validations/validators/coerce.rb +1 -5
  49. data/lib/grape/validations/validators/default.rb +1 -0
  50. data/lib/grape/validations/validators/exactly_one_of.rb +1 -0
  51. data/lib/grape/validations/validators/multiple_params_base.rb +2 -0
  52. data/lib/grape/validations/validators/mutual_exclusion.rb +1 -0
  53. data/lib/grape/validations/validators/presence.rb +1 -0
  54. data/lib/grape/validations/validators/regexp.rb +1 -0
  55. data/lib/grape/validations/validators/same_as.rb +1 -0
  56. data/lib/grape/validations/validators/values.rb +3 -0
  57. data/lib/grape/version.rb +1 -1
  58. data/lib/grape.rb +1 -1
  59. data/spec/grape/api/custom_validations_spec.rb +1 -0
  60. data/spec/grape/api/routes_with_requirements_spec.rb +8 -8
  61. data/spec/grape/api_spec.rb +126 -37
  62. data/spec/grape/dsl/callbacks_spec.rb +1 -1
  63. data/spec/grape/dsl/middleware_spec.rb +1 -1
  64. data/spec/grape/dsl/parameters_spec.rb +1 -0
  65. data/spec/grape/dsl/routing_spec.rb +1 -1
  66. data/spec/grape/endpoint/declared_spec.rb +247 -0
  67. data/spec/grape/endpoint_spec.rb +5 -5
  68. data/spec/grape/entity_spec.rb +9 -9
  69. data/spec/grape/middleware/auth/dsl_spec.rb +1 -1
  70. data/spec/grape/middleware/error_spec.rb +1 -2
  71. data/spec/grape/middleware/formatter_spec.rb +2 -2
  72. data/spec/grape/middleware/stack_spec.rb +3 -1
  73. data/spec/grape/validations/params_scope_spec.rb +37 -3
  74. data/spec/grape/validations/single_attribute_iterator_spec.rb +1 -1
  75. data/spec/grape/validations/types/primitive_coercer_spec.rb +2 -2
  76. data/spec/grape/validations/validators/coerce_spec.rb +13 -10
  77. data/spec/grape/validations/validators/except_values_spec.rb +2 -2
  78. data/spec/grape/validations/validators/values_spec.rb +15 -11
  79. data/spec/grape/validations_spec.rb +54 -42
  80. data/spec/shared/versioning_examples.rb +2 -2
  81. data/spec/spec_helper.rb +1 -1
  82. data/spec/support/basic_auth_encode_helpers.rb +1 -1
  83. metadata +6 -6
@@ -610,6 +610,7 @@ describe Grape::API do
610
610
  subject.namespace :example do
611
611
  before do
612
612
  raise 'before filter ran twice' if already_run
613
+
613
614
  already_run = true
614
615
  header 'X-Custom-Header', 'foo'
615
616
  end
@@ -650,12 +651,12 @@ describe Grape::API do
650
651
 
651
652
  put '/example'
652
653
  expect(last_response.status).to eql 405
653
- expect(last_response.body).to eq <<-XML
654
- <?xml version="1.0" encoding="UTF-8"?>
655
- <error>
656
- <message>405 Not Allowed</message>
657
- </error>
658
- XML
654
+ expect(last_response.body).to eq <<~XML
655
+ <?xml version="1.0" encoding="UTF-8"?>
656
+ <error>
657
+ <message>405 Not Allowed</message>
658
+ </error>
659
+ XML
659
660
  end
660
661
  end
661
662
 
@@ -749,6 +750,47 @@ XML
749
750
  end
750
751
  end
751
752
 
753
+ describe 'when a resource routes by POST, GET, PATCH, PUT, and DELETE' do
754
+ before do
755
+ subject.namespace :example do
756
+ get do
757
+ 'example'
758
+ end
759
+
760
+ patch do
761
+ 'example'
762
+ end
763
+
764
+ post do
765
+ 'example'
766
+ end
767
+
768
+ delete do
769
+ 'example'
770
+ end
771
+
772
+ put do
773
+ 'example'
774
+ end
775
+ end
776
+ options '/example'
777
+ end
778
+
779
+ describe 'it adds an OPTIONS route for namespaced endpoints that' do
780
+ it 'returns a 204' do
781
+ expect(last_response.status).to eql 204
782
+ end
783
+
784
+ it 'has an empty body' do
785
+ expect(last_response.body).to be_blank
786
+ end
787
+
788
+ it 'has an Allow header' do
789
+ expect(last_response.headers['Allow']).to eql 'OPTIONS, GET, PATCH, POST, DELETE, PUT, HEAD'
790
+ end
791
+ end
792
+ end
793
+
752
794
  describe 'adds an OPTIONS route for namespaced endpoints that' do
753
795
  before do
754
796
  subject.before { header 'X-Custom-Header', 'foo' }
@@ -2106,7 +2148,9 @@ XML
2106
2148
  context 'custom errors' do
2107
2149
  before do
2108
2150
  class ConnectionError < RuntimeError; end
2151
+
2109
2152
  class DatabaseError < RuntimeError; end
2153
+
2110
2154
  class CommunicationError < StandardError; end
2111
2155
  end
2112
2156
 
@@ -2262,6 +2306,7 @@ XML
2262
2306
  module ApiSpec
2263
2307
  module APIErrors
2264
2308
  class ParentError < StandardError; end
2309
+
2265
2310
  class ChildError < ParentError; end
2266
2311
  end
2267
2312
  end
@@ -3119,10 +3164,10 @@ XML
3119
3164
  subject.get 'method'
3120
3165
 
3121
3166
  expect(subject.routes.map(&:params)).to eq [{
3122
- 'group1' => { required: true, type: 'Array' },
3167
+ 'group1' => { required: true, type: 'Array' },
3123
3168
  'group1[param1]' => { required: false, desc: 'group1 param1 desc' },
3124
3169
  'group1[param2]' => { required: true, desc: 'group1 param2 desc' },
3125
- 'group2' => { required: true, type: 'Array' },
3170
+ 'group2' => { required: true, type: 'Array' },
3126
3171
  'group2[param1]' => { required: false, desc: 'group2 param1 desc' },
3127
3172
  'group2[param2]' => { required: true, desc: 'group2 param2 desc' }
3128
3173
  }]
@@ -3335,8 +3380,8 @@ XML
3335
3380
  mount app
3336
3381
  end
3337
3382
  expect(subject.routes.size).to eq(2)
3338
- expect(subject.routes.first.path).to match(%r{\/cool\/awesome})
3339
- expect(subject.routes.last.path).to match(%r{\/cool\/sauce})
3383
+ expect(subject.routes.first.path).to match(%r{/cool/awesome})
3384
+ expect(subject.routes.last.path).to match(%r{/cool/sauce})
3340
3385
  end
3341
3386
 
3342
3387
  it 'mounts on a path' do
@@ -3358,7 +3403,7 @@ XML
3358
3403
  APP2.get '/nice' do
3359
3404
  'play'
3360
3405
  end
3361
- # note that the reverse won't work, mount from outside-in
3406
+ # NOTE: that the reverse won't work, mount from outside-in
3362
3407
  APP3 = subject
3363
3408
  APP3.mount APP1 => '/app1'
3364
3409
  APP1.mount APP2 => '/app2'
@@ -3549,6 +3594,7 @@ XML
3549
3594
  def self.included(base)
3550
3595
  base.extend(ClassMethods)
3551
3596
  end
3597
+
3552
3598
  module ClassMethods
3553
3599
  def my_method
3554
3600
  @test = true
@@ -3793,12 +3839,12 @@ XML
3793
3839
  end
3794
3840
  get '/example'
3795
3841
  expect(last_response.status).to eq(500)
3796
- expect(last_response.body).to eq <<-XML
3797
- <?xml version="1.0" encoding="UTF-8"?>
3798
- <error>
3799
- <message>cannot convert String to xml</message>
3800
- </error>
3801
- XML
3842
+ expect(last_response.body).to eq <<~XML
3843
+ <?xml version="1.0" encoding="UTF-8"?>
3844
+ <error>
3845
+ <message>cannot convert String to xml</message>
3846
+ </error>
3847
+ XML
3802
3848
  end
3803
3849
  it 'hash' do
3804
3850
  subject.get '/example' do
@@ -3809,13 +3855,13 @@ XML
3809
3855
  end
3810
3856
  get '/example'
3811
3857
  expect(last_response.status).to eq(200)
3812
- expect(last_response.body).to eq <<-XML
3813
- <?xml version="1.0" encoding="UTF-8"?>
3814
- <hash>
3815
- <example1>example1</example1>
3816
- <example2>example2</example2>
3817
- </hash>
3818
- XML
3858
+ expect(last_response.body).to eq <<~XML
3859
+ <?xml version="1.0" encoding="UTF-8"?>
3860
+ <hash>
3861
+ <example1>example1</example1>
3862
+ <example2>example2</example2>
3863
+ </hash>
3864
+ XML
3819
3865
  end
3820
3866
  it 'array' do
3821
3867
  subject.get '/example' do
@@ -3823,13 +3869,13 @@ XML
3823
3869
  end
3824
3870
  get '/example'
3825
3871
  expect(last_response.status).to eq(200)
3826
- expect(last_response.body).to eq <<-XML
3827
- <?xml version="1.0" encoding="UTF-8"?>
3828
- <strings type="array">
3829
- <string>example1</string>
3830
- <string>example2</string>
3831
- </strings>
3832
- XML
3872
+ expect(last_response.body).to eq <<~XML
3873
+ <?xml version="1.0" encoding="UTF-8"?>
3874
+ <strings type="array">
3875
+ <string>example1</string>
3876
+ <string>example2</string>
3877
+ </strings>
3878
+ XML
3833
3879
  end
3834
3880
  it 'raised :error from middleware' do
3835
3881
  middleware = Class.new(Grape::Middleware::Base) do
@@ -3842,12 +3888,12 @@ XML
3842
3888
  end
3843
3889
  get '/'
3844
3890
  expect(last_response.status).to eq(42)
3845
- expect(last_response.body).to eq <<-XML
3846
- <?xml version="1.0" encoding="UTF-8"?>
3847
- <error>
3848
- <message>Unauthorized</message>
3849
- </error>
3850
- XML
3891
+ expect(last_response.body).to eq <<~XML
3892
+ <?xml version="1.0" encoding="UTF-8"?>
3893
+ <error>
3894
+ <message>Unauthorized</message>
3895
+ </error>
3896
+ XML
3851
3897
  end
3852
3898
  end
3853
3899
  end
@@ -4040,6 +4086,49 @@ XML
4040
4086
  end
4041
4087
  end
4042
4088
 
4089
+ describe '.inherited' do
4090
+ context 'overriding within class' do
4091
+ let(:root_api) do
4092
+ Class.new(Grape::API) do
4093
+ @bar = 'Hello, world'
4094
+
4095
+ def self.inherited(child_api)
4096
+ super
4097
+ child_api.instance_variable_set(:@foo, @bar.dup)
4098
+ end
4099
+ end
4100
+ end
4101
+
4102
+ let(:child_api) { Class.new(root_api) }
4103
+
4104
+ it 'allows overriding the hook' do
4105
+ expect(child_api.instance_variable_get(:@foo)).to eq('Hello, world')
4106
+ end
4107
+ end
4108
+
4109
+ context 'overriding via composition' do
4110
+ module Inherited
4111
+ def inherited(api)
4112
+ super
4113
+ api.instance_variable_set(:@foo, @bar.dup)
4114
+ end
4115
+ end
4116
+
4117
+ let(:root_api) do
4118
+ Class.new(Grape::API) do
4119
+ @bar = 'Hello, world'
4120
+ extend Inherited
4121
+ end
4122
+ end
4123
+
4124
+ let(:child_api) { Class.new(root_api) }
4125
+
4126
+ it 'allows overriding the hook' do
4127
+ expect(child_api.instance_variable_get(:@foo)).to eq('Hello, world')
4128
+ end
4129
+ end
4130
+ end
4131
+
4043
4132
  describe 'const_missing' do
4044
4133
  subject(:grape_api) { Class.new(Grape::API) }
4045
4134
  let(:mounted) do
@@ -12,7 +12,7 @@ module Grape
12
12
 
13
13
  describe Callbacks do
14
14
  subject { Class.new(CallbacksSpec::Dummy) }
15
- let(:proc) { ->() {} }
15
+ let(:proc) { -> {} }
16
16
 
17
17
  describe '.before' do
18
18
  it 'adds a block to "before"' do
@@ -12,7 +12,7 @@ module Grape
12
12
 
13
13
  describe Middleware do
14
14
  subject { Class.new(MiddlewareSpec::Dummy) }
15
- let(:proc) { ->() {} }
15
+ let(:proc) { -> {} }
16
16
  let(:foo_middleware) { Class.new }
17
17
  let(:bar_middleware) { Class.new }
18
18
 
@@ -40,6 +40,7 @@ module Grape
40
40
 
41
41
  def extract_message_option(attrs)
42
42
  return nil unless attrs.is_a?(Array)
43
+
43
44
  opts = attrs.last.is_a?(Hash) ? attrs.pop : {}
44
45
  opts.key?(:message) && !opts[:message].nil? ? opts.delete(:message) : nil
45
46
  end
@@ -12,7 +12,7 @@ module Grape
12
12
 
13
13
  describe Routing do
14
14
  subject { Class.new(RoutingSpec::Dummy) }
15
- let(:proc) { ->() {} }
15
+ let(:proc) { -> {} }
16
16
  let(:options) { { a: :b } }
17
17
  let(:path) { '/dummy' }
18
18
 
@@ -598,4 +598,251 @@ describe Grape::Endpoint do
598
598
  expect(json.key?(:artist_id)).not_to be_truthy
599
599
  end
600
600
  end
601
+
602
+ describe 'parameter renaming' do
603
+ context 'with a deeply nested parameter structure' do
604
+ let(:params) do
605
+ {
606
+ i_a: 'a',
607
+ i_b: {
608
+ i_c: 'c',
609
+ i_d: {
610
+ i_e: {
611
+ i_f: 'f',
612
+ i_g: 'g',
613
+ i_h: [
614
+ {
615
+ i_ha: 'ha1',
616
+ i_hb: {
617
+ i_hc: 'c'
618
+ }
619
+ },
620
+ {
621
+ i_ha: 'ha2',
622
+ i_hb: {
623
+ i_hc: 'c'
624
+ }
625
+ }
626
+ ]
627
+ }
628
+ }
629
+ }
630
+ }
631
+ end
632
+ let(:declared) do
633
+ {
634
+ o_a: 'a',
635
+ o_b: {
636
+ o_c: 'c',
637
+ o_d: {
638
+ o_e: {
639
+ o_f: 'f',
640
+ o_g: 'g',
641
+ o_h: [
642
+ {
643
+ o_ha: 'ha1',
644
+ o_hb: {
645
+ o_hc: 'c'
646
+ }
647
+ },
648
+ {
649
+ o_ha: 'ha2',
650
+ o_hb: {
651
+ o_hc: 'c'
652
+ }
653
+ }
654
+ ]
655
+ }
656
+ }
657
+ }
658
+ }
659
+ end
660
+ let(:params_keys) do
661
+ [
662
+ 'i_a',
663
+ 'i_b',
664
+ 'i_b[i_c]',
665
+ 'i_b[i_d]',
666
+ 'i_b[i_d][i_e]',
667
+ 'i_b[i_d][i_e][i_f]',
668
+ 'i_b[i_d][i_e][i_g]',
669
+ 'i_b[i_d][i_e][i_h]',
670
+ 'i_b[i_d][i_e][i_h][i_ha]',
671
+ 'i_b[i_d][i_e][i_h][i_hb]',
672
+ 'i_b[i_d][i_e][i_h][i_hb][i_hc]'
673
+ ]
674
+ end
675
+
676
+ before do
677
+ subject.format :json
678
+ subject.params do
679
+ optional :i_a, type: String, as: :o_a
680
+ optional :i_b, type: Hash, as: :o_b do
681
+ optional :i_c, type: String, as: :o_c
682
+ optional :i_d, type: Hash, as: :o_d do
683
+ optional :i_e, type: Hash, as: :o_e do
684
+ optional :i_f, type: String, as: :o_f
685
+ optional :i_g, type: String, as: :o_g
686
+ optional :i_h, type: Array, as: :o_h do
687
+ optional :i_ha, type: String, as: :o_ha
688
+ optional :i_hb, type: Hash, as: :o_hb do
689
+ optional :i_hc, type: String, as: :o_hc
690
+ end
691
+ end
692
+ end
693
+ end
694
+ end
695
+ end
696
+ subject.post '/test' do
697
+ declared(params, include_missing: false)
698
+ end
699
+ subject.post '/test/no-mod' do
700
+ before = params.to_h
701
+ declared(params, include_missing: false)
702
+ after = params.to_h
703
+ { before: before, after: after }
704
+ end
705
+ end
706
+
707
+ it 'generates the correct parameter names for documentation' do
708
+ expect(subject.routes.first.params.keys).to match(params_keys)
709
+ end
710
+
711
+ it 'maps the renamed parameter correctly' do
712
+ post '/test', **params
713
+ expect(JSON.parse(last_response.body, symbolize_names: true)).to \
714
+ match(declared)
715
+ end
716
+
717
+ it 'maps no parameters when none are given' do
718
+ post '/test'
719
+ expect(JSON.parse(last_response.body)).to match({})
720
+ end
721
+
722
+ it 'does not modify the request params' do
723
+ post '/test/no-mod', **params
724
+ result = JSON.parse(last_response.body, symbolize_names: true)
725
+ expect(result[:before]).to match(result[:after])
726
+ end
727
+ end
728
+
729
+ context 'with a renamed root parameter' do
730
+ before do
731
+ subject.format :json
732
+ subject.params do
733
+ optional :email_address, type: String, regexp: /.+@.+/, as: :email
734
+ end
735
+ subject.post '/test' do
736
+ declared(params, include_missing: false)
737
+ end
738
+ end
739
+
740
+ it 'generates the correct parameter names for documentation' do
741
+ expect(subject.routes.first.params.keys).to match(%w[email_address])
742
+ end
743
+
744
+ it 'maps the renamed parameter correctly (original name)' do
745
+ post '/test', email_address: 'test@example.com'
746
+ expect(JSON.parse(last_response.body)).to \
747
+ match('email' => 'test@example.com')
748
+ end
749
+
750
+ it 'validates the renamed parameter correctly (original name)' do
751
+ post '/test', email_address: 'bad[at]example.com'
752
+ expect(JSON.parse(last_response.body)).to \
753
+ match('error' => 'email_address is invalid')
754
+ end
755
+
756
+ it 'ignores the renamed parameter (as name)' do
757
+ post '/test', email: 'test@example.com'
758
+ expect(JSON.parse(last_response.body)).to match({})
759
+ end
760
+ end
761
+
762
+ context 'with a renamed hash with nested parameters' do
763
+ before do
764
+ subject.format :json
765
+ subject.params do
766
+ optional :address, type: Hash, as: :address_attributes do
767
+ optional :street, type: String, values: ['Street 1', 'Street 2'],
768
+ default: 'Street 1'
769
+ optional :city, type: String
770
+ end
771
+ end
772
+ subject.post '/test' do
773
+ declared(params, include_missing: false)
774
+ end
775
+ end
776
+
777
+ it 'generates the correct parameter names for documentation' do
778
+ expect(subject.routes.first.params.keys).to \
779
+ match(%w[address address[street] address[city]])
780
+ end
781
+
782
+ it 'maps the renamed parameter correctly (original name)' do
783
+ post '/test', address: { city: 'Berlin', street: 'Street 2', t: 't' }
784
+ expect(JSON.parse(last_response.body)).to \
785
+ match('address_attributes' => { 'city' => 'Berlin',
786
+ 'street' => 'Street 2' })
787
+ end
788
+
789
+ it 'validates the renamed parameter correctly (original name)' do
790
+ post '/test', address: { street: 'unknown' }
791
+ expect(JSON.parse(last_response.body)).to \
792
+ match('error' => 'address[street] does not have a valid value')
793
+ end
794
+
795
+ it 'ignores the renamed parameter (as name)' do
796
+ post '/test', address_attributes: { city: 'Berlin', unknown: '1' }
797
+ expect(JSON.parse(last_response.body)).to match({})
798
+ end
799
+ end
800
+
801
+ context 'with a renamed hash with nested renamed parameter' do
802
+ before do
803
+ subject.format :json
804
+ subject.params do
805
+ optional :user, type: Hash, as: :user_attributes do
806
+ optional :email_address, type: String, regexp: /.+@.+/, as: :email
807
+ end
808
+ end
809
+ subject.post '/test' do
810
+ declared(params, include_missing: false)
811
+ end
812
+ end
813
+
814
+ it 'generates the correct parameter names for documentation' do
815
+ expect(subject.routes.first.params.keys).to \
816
+ match(%w[user user[email_address]])
817
+ end
818
+
819
+ it 'maps the renamed parameter correctly (original name)' do
820
+ post '/test', user: { email_address: 'test@example.com' }
821
+ expect(JSON.parse(last_response.body)).to \
822
+ match('user_attributes' => { 'email' => 'test@example.com' })
823
+ end
824
+
825
+ it 'validates the renamed parameter correctly (original name)' do
826
+ post '/test', user: { email_address: 'bad[at]example.com' }
827
+ expect(JSON.parse(last_response.body)).to \
828
+ match('error' => 'user[email_address] is invalid')
829
+ end
830
+
831
+ it 'ignores the renamed parameter (as name, 1)' do
832
+ post '/test', user: { email: 'test@example.com' }
833
+ expect(JSON.parse(last_response.body)).to \
834
+ match({ 'user_attributes' => {} })
835
+ end
836
+
837
+ it 'ignores the renamed parameter (as name, 2)' do
838
+ post '/test', user_attributes: { email_address: 'test@example.com' }
839
+ expect(JSON.parse(last_response.body)).to match({})
840
+ end
841
+
842
+ it 'ignores the renamed parameter (as name, 3)' do
843
+ post '/test', user_attributes: { email: 'test@example.com' }
844
+ expect(JSON.parse(last_response.body)).to match({})
845
+ end
846
+ end
847
+ end
601
848
  end
@@ -150,7 +150,7 @@ describe Grape::Endpoint do
150
150
  end
151
151
  it 'includes headers passed as symbols' do
152
152
  env = Rack::MockRequest.env_for('/headers')
153
- env['HTTP_SYMBOL_HEADER'.to_sym] = 'Goliath passes symbols'
153
+ env[:HTTP_SYMBOL_HEADER] = 'Goliath passes symbols'
154
154
  body = read_chunks(subject.call(env)[2]).join
155
155
  expect(JSON.parse(body)['Symbol-Header']).to eq('Goliath passes symbols')
156
156
  end
@@ -212,10 +212,10 @@ describe Grape::Endpoint do
212
212
  end
213
213
  get '/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2'
214
214
  expect(last_response.body).to eq('3')
215
- cookies = Hash[last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
215
+ cookies = last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
216
216
  cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
217
217
  [cookie.name, cookie]
218
- end]
218
+ end.to_h
219
219
  expect(cookies.size).to eq(2)
220
220
  %w[and_this delete_this_cookie].each do |cookie_name|
221
221
  cookie = cookies[cookie_name]
@@ -236,10 +236,10 @@ describe Grape::Endpoint do
236
236
  end
237
237
  get('/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2')
238
238
  expect(last_response.body).to eq('3')
239
- cookies = Hash[last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
239
+ cookies = last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
240
240
  cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
241
241
  [cookie.name, cookie]
242
- end]
242
+ end.to_h
243
243
  expect(cookies.size).to eq(2)
244
244
  %w[and_this delete_this_cookie].each do |cookie_name|
245
245
  cookie = cookies[cookie_name]
@@ -238,14 +238,14 @@ describe Grape::Entity do
238
238
  get '/example'
239
239
  expect(last_response.status).to eq(200)
240
240
  expect(last_response.headers['Content-type']).to eq('application/xml')
241
- expect(last_response.body).to eq <<-XML
242
- <?xml version="1.0" encoding="UTF-8"?>
243
- <hash>
244
- <example>
245
- <name>johnnyiller</name>
246
- </example>
247
- </hash>
248
- XML
241
+ expect(last_response.body).to eq <<~XML
242
+ <?xml version="1.0" encoding="UTF-8"?>
243
+ <hash>
244
+ <example>
245
+ <name>johnnyiller</name>
246
+ </example>
247
+ </hash>
248
+ XML
249
249
  end
250
250
 
251
251
  it 'presents with json' do
@@ -326,7 +326,7 @@ XML
326
326
  end
327
327
  get '/example'
328
328
  expect_response_json = {
329
- 'page' => 1,
329
+ 'page' => 1,
330
330
  'user1' => { 'name' => 'user1' },
331
331
  'user2' => { 'name' => 'user2' }
332
332
  }
@@ -5,7 +5,7 @@ require 'spec_helper'
5
5
  describe Grape::Middleware::Auth::DSL do
6
6
  subject { Class.new(Grape::API) }
7
7
 
8
- let(:block) { ->() {} }
8
+ let(:block) { -> {} }
9
9
  let(:settings) do
10
10
  {
11
11
  opaque: 'secret',
@@ -16,8 +16,7 @@ describe Grape::Middleware::Error do
16
16
 
17
17
  class ErrApp
18
18
  class << self
19
- attr_accessor :error
20
- attr_accessor :format
19
+ attr_accessor :error, :format
21
20
 
22
21
  def call(_env)
23
22
  throw :error, error
@@ -20,7 +20,7 @@ describe Grape::Middleware::Formatter do
20
20
  let(:body) { ['foo'] }
21
21
  it 'calls #to_json since default format is json' do
22
22
  body.instance_eval do
23
- def to_json
23
+ def to_json(*_args)
24
24
  '"bar"'
25
25
  end
26
26
  end
@@ -33,7 +33,7 @@ describe Grape::Middleware::Formatter do
33
33
  let(:body) { { 'foos' => [{ 'bar' => 'baz' }] } }
34
34
  it 'calls #to_json if the content type is jsonapi' do
35
35
  body.instance_eval do
36
- def to_json
36
+ def to_json(*_args)
37
37
  '{"foos":[{"bar":"baz"}] }'
38
38
  end
39
39
  end
@@ -5,7 +5,9 @@ require 'spec_helper'
5
5
  describe Grape::Middleware::Stack do
6
6
  module StackSpec
7
7
  class FooMiddleware; end
8
+
8
9
  class BarMiddleware; end
10
+
9
11
  class BlockMiddleware
10
12
  attr_reader :block
11
13
 
@@ -15,7 +17,7 @@ describe Grape::Middleware::Stack do
15
17
  end
16
18
  end
17
19
 
18
- let(:proc) { ->() {} }
20
+ let(:proc) { -> {} }
19
21
  let(:others) { [[:use, StackSpec::BarMiddleware], [:insert_before, StackSpec::BarMiddleware, StackSpec::BlockMiddleware, proc]] }
20
22
 
21
23
  subject { Grape::Middleware::Stack.new }