grape 1.5.3 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 }