grape 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grape might be problematic. Click here for more details.

Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +23 -80
  3. data/.travis.yml +1 -1
  4. data/CHANGELOG.md +27 -0
  5. data/Gemfile +1 -1
  6. data/Guardfile +1 -1
  7. data/LICENSE +1 -1
  8. data/README.md +131 -30
  9. data/Rakefile +1 -1
  10. data/UPGRADING.md +110 -1
  11. data/gemfiles/rails_3.gemfile +1 -1
  12. data/gemfiles/rails_4.gemfile +1 -1
  13. data/grape.gemspec +4 -4
  14. data/lib/grape.rb +92 -62
  15. data/lib/grape/api.rb +10 -10
  16. data/lib/grape/cookies.rb +1 -1
  17. data/lib/grape/dsl/configuration.rb +7 -7
  18. data/lib/grape/dsl/helpers.rb +3 -3
  19. data/lib/grape/dsl/inside_route.rb +50 -21
  20. data/lib/grape/dsl/parameters.rb +25 -6
  21. data/lib/grape/dsl/request_response.rb +1 -1
  22. data/lib/grape/dsl/routing.rb +11 -10
  23. data/lib/grape/dsl/settings.rb +1 -1
  24. data/lib/grape/endpoint.rb +21 -19
  25. data/lib/grape/error_formatter/json.rb +1 -1
  26. data/lib/grape/exceptions/base.rb +1 -1
  27. data/lib/grape/exceptions/validation.rb +1 -1
  28. data/lib/grape/exceptions/validation_errors.rb +2 -2
  29. data/lib/grape/formatter/base.rb +1 -1
  30. data/lib/grape/formatter/json.rb +1 -1
  31. data/lib/grape/formatter/serializable_hash.rb +4 -4
  32. data/lib/grape/formatter/txt.rb +1 -1
  33. data/lib/grape/formatter/xml.rb +1 -1
  34. data/lib/grape/http/headers.rb +27 -0
  35. data/lib/grape/http/request.rb +1 -1
  36. data/lib/grape/middleware/error.rb +10 -4
  37. data/lib/grape/middleware/formatter.rb +13 -9
  38. data/lib/grape/middleware/globals.rb +2 -1
  39. data/lib/grape/middleware/versioner/accept_version_header.rb +2 -2
  40. data/lib/grape/middleware/versioner/header.rb +4 -4
  41. data/lib/grape/middleware/versioner/param.rb +2 -2
  42. data/lib/grape/middleware/versioner/path.rb +1 -1
  43. data/lib/grape/namespace.rb +2 -1
  44. data/lib/grape/parser/json.rb +1 -1
  45. data/lib/grape/parser/xml.rb +1 -1
  46. data/lib/grape/path.rb +3 -3
  47. data/lib/grape/presenters/presenter.rb +9 -0
  48. data/lib/grape/validations/params_scope.rb +3 -3
  49. data/lib/grape/validations/validators/allow_blank.rb +1 -1
  50. data/lib/grape/validations/validators/coerce.rb +6 -5
  51. data/lib/grape/validations/validators/default.rb +2 -2
  52. data/lib/grape/validations/validators/multiple_params_base.rb +1 -0
  53. data/lib/grape/validations/validators/regexp.rb +1 -1
  54. data/lib/grape/version.rb +1 -1
  55. data/spec/grape/api/custom_validations_spec.rb +47 -0
  56. data/spec/grape/api/deeply_included_options_spec.rb +56 -0
  57. data/spec/grape/api_spec.rb +64 -42
  58. data/spec/grape/dsl/configuration_spec.rb +2 -2
  59. data/spec/grape/dsl/helpers_spec.rb +1 -1
  60. data/spec/grape/dsl/inside_route_spec.rb +75 -19
  61. data/spec/grape/dsl/parameters_spec.rb +59 -10
  62. data/spec/grape/dsl/request_response_spec.rb +62 -2
  63. data/spec/grape/dsl/routing_spec.rb +116 -18
  64. data/spec/grape/endpoint_spec.rb +57 -5
  65. data/spec/grape/entity_spec.rb +1 -1
  66. data/spec/grape/exceptions/body_parse_errors_spec.rb +5 -5
  67. data/spec/grape/exceptions/invalid_accept_header_spec.rb +32 -32
  68. data/spec/grape/exceptions/validation_errors_spec.rb +1 -1
  69. data/spec/grape/integration/rack_spec.rb +4 -3
  70. data/spec/grape/middleware/auth/strategies_spec.rb +2 -2
  71. data/spec/grape/middleware/base_spec.rb +2 -2
  72. data/spec/grape/middleware/error_spec.rb +1 -1
  73. data/spec/grape/middleware/exception_spec.rb +5 -5
  74. data/spec/grape/middleware/formatter_spec.rb +10 -10
  75. data/spec/grape/middleware/globals_spec.rb +27 -0
  76. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +1 -1
  77. data/spec/grape/middleware/versioner/header_spec.rb +1 -1
  78. data/spec/grape/middleware/versioner/param_spec.rb +1 -1
  79. data/spec/grape/middleware/versioner/path_spec.rb +1 -1
  80. data/spec/grape/path_spec.rb +6 -4
  81. data/spec/grape/presenters/presenter_spec.rb +70 -0
  82. data/spec/grape/util/inheritable_values_spec.rb +1 -1
  83. data/spec/grape/util/stackable_values_spec.rb +1 -1
  84. data/spec/grape/util/strict_hash_configuration_spec.rb +1 -1
  85. data/spec/grape/validations/params_scope_spec.rb +64 -0
  86. data/spec/grape/validations/validators/allow_blank_spec.rb +10 -0
  87. data/spec/grape/validations/validators/coerce_spec.rb +48 -18
  88. data/spec/grape/validations/validators/default_spec.rb +110 -20
  89. data/spec/grape/validations/validators/presence_spec.rb +41 -3
  90. data/spec/grape/validations/validators/regexp_spec.rb +7 -2
  91. data/spec/grape/validations_spec.rb +20 -1
  92. data/spec/support/file_streamer.rb +11 -0
  93. data/spec/support/versioned_helpers.rb +1 -1
  94. metadata +14 -2
@@ -3,7 +3,7 @@ module Grape
3
3
  class RegexpValidator < Base
4
4
  def validate_param!(attr_name, params)
5
5
  if params.key?(attr_name) &&
6
- (params[attr_name].nil? || !(params[attr_name].to_s =~ @option))
6
+ !params[attr_name].nil? && !(params[attr_name].to_s =~ @option)
7
7
  fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :regexp
8
8
  end
9
9
  end
data/lib/grape/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Grape
2
- VERSION = '0.11.0'
2
+ VERSION = '0.12.0'
3
3
  end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe Grape::Validations do
4
+ before do
5
+ class DefaultLength < Grape::Validations::Base
6
+ def validate_param!(attr_name, params)
7
+ @option = params[:max].to_i if params.key?(:max)
8
+ unless params[attr_name].length <= @option
9
+ fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long"
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ subject do
16
+ Class.new(Grape::API) do
17
+ params do
18
+ requires :text, default_length: 140
19
+ end
20
+ get do
21
+ 'bacon'
22
+ end
23
+ end
24
+ end
25
+
26
+ def app
27
+ subject
28
+ end
29
+
30
+ context 'using a custom length validator' do
31
+ it 'under 140 characters' do
32
+ get '/', text: 'abc'
33
+ expect(last_response.status).to eq 200
34
+ expect(last_response.body).to eq 'bacon'
35
+ end
36
+ it 'over 140 characters' do
37
+ get '/', text: 'a' * 141
38
+ expect(last_response.status).to eq 400
39
+ expect(last_response.body).to eq 'text must be at the most 140 characters long'
40
+ end
41
+ it 'specified in the query string' do
42
+ get '/', text: 'a' * 141, max: 141
43
+ expect(last_response.status).to eq 200
44
+ expect(last_response.body).to eq 'bacon'
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ module API
4
+ module Defaults
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ format :json
8
+ end
9
+ end
10
+
11
+ module Admin
12
+ module Defaults
13
+ extend ActiveSupport::Concern
14
+ include API::Defaults
15
+ end
16
+
17
+ class Users < Grape::API
18
+ include API::Admin::Defaults
19
+
20
+ resource :users do
21
+ get do
22
+ status 200
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ class Main < Grape::API
30
+ mount API::Admin::Users
31
+ end
32
+
33
+ describe Grape::API do
34
+ subject { Main }
35
+
36
+ def app
37
+ subject
38
+ end
39
+
40
+ it 'works for unspecified format' do
41
+ get '/users'
42
+ expect(last_response.status).to eql 200
43
+ expect(last_response.content_type).to eql 'application/json'
44
+ end
45
+
46
+ it 'works for specified format' do
47
+ get '/users.json'
48
+ expect(last_response.status).to eql 200
49
+ expect(last_response.content_type).to eql 'application/json'
50
+ end
51
+
52
+ it "doesn't work for format different than specified" do
53
+ get '/users.txt'
54
+ expect(last_response.status).to eql 404
55
+ end
56
+ end
@@ -278,7 +278,7 @@ describe Grape::API do
278
278
  before do
279
279
  subject.format :txt
280
280
  subject.content_type :json, 'application/json'
281
- subject.formatter :json, ->(object, env) { object }
281
+ subject.formatter :json, ->(object, _env) { object }
282
282
  def subject.enable_root_route!
283
283
  get('/') { 'root' }
284
284
  end
@@ -419,7 +419,7 @@ describe Grape::API do
419
419
  send verb, '/', MultiJson.dump(object), 'CONTENT_TYPE' => 'application/json'
420
420
  expect(last_response.status).to eq(verb == :post ? 201 : 200)
421
421
  expect(last_response.body).to eql MultiJson.dump(object)
422
- expect(last_request.params).to eql Hash.new
422
+ expect(last_request.params).to eql({})
423
423
  end
424
424
  it 'stores input in api.request.input' do
425
425
  subject.format :json
@@ -804,7 +804,8 @@ describe Grape::API do
804
804
  it 'sets content type for json error' do
805
805
  subject.format :json
806
806
  subject.get('/error') { error!('error in json', 500) }
807
- get '/error'
807
+ get '/error.json'
808
+ expect(last_response.status).to eql 500
808
809
  expect(last_response.headers['Content-Type']).to eql 'application/json'
809
810
  end
810
811
 
@@ -812,13 +813,14 @@ describe Grape::API do
812
813
  subject.format :xml
813
814
  subject.get('/error') { error!('error in xml', 500) }
814
815
  get '/error'
816
+ expect(last_response.status).to eql 500
815
817
  expect(last_response.headers['Content-Type']).to eql 'application/xml'
816
818
  end
817
819
 
818
820
  context 'with a custom content_type' do
819
821
  before do
820
822
  subject.content_type :custom, 'application/custom'
821
- subject.formatter :custom, ->(object, env) { 'custom' }
823
+ subject.formatter :custom, ->(_object, _env) { 'custom' }
822
824
 
823
825
  subject.get('/custom') { 'bar' }
824
826
  subject.get('/error') { error!('error in custom', 500) }
@@ -984,7 +986,7 @@ describe Grape::API do
984
986
  end
985
987
  describe '.http_basic' do
986
988
  it 'protects any resources on the same scope' do
987
- subject.http_basic do |u, p|
989
+ subject.http_basic do |u, _p|
988
990
  u == 'allow'
989
991
  end
990
992
  subject.get(:hello) { 'Hello, world.' }
@@ -997,7 +999,7 @@ describe Grape::API do
997
999
  it 'is scopable' do
998
1000
  subject.get(:hello) { 'Hello, world.' }
999
1001
  subject.namespace :admin do
1000
- http_basic do |u, p|
1002
+ http_basic do |u, _p|
1001
1003
  u == 'allow'
1002
1004
  end
1003
1005
 
@@ -1011,7 +1013,7 @@ describe Grape::API do
1011
1013
  end
1012
1014
 
1013
1015
  it 'is callable via .auth as well' do
1014
- subject.auth :http_basic do |u, p|
1016
+ subject.auth :http_basic do |u, _p|
1015
1017
  u == 'allow'
1016
1018
  end
1017
1019
 
@@ -1025,7 +1027,7 @@ describe Grape::API do
1025
1027
  it 'has access to the current endpoint' do
1026
1028
  basic_auth_context = nil
1027
1029
 
1028
- subject.http_basic do |u, p|
1030
+ subject.http_basic do |u, _p|
1029
1031
  basic_auth_context = self
1030
1032
 
1031
1033
  u == 'allow'
@@ -1055,7 +1057,7 @@ describe Grape::API do
1055
1057
  end
1056
1058
 
1057
1059
  it 'can set instance variables accessible to routes' do
1058
- subject.http_basic do |u, p|
1060
+ subject.http_basic do |u, _p|
1059
1061
  @hello = 'Hello, world.'
1060
1062
 
1061
1063
  u == 'allow'
@@ -1304,7 +1306,7 @@ describe Grape::API do
1304
1306
  allow(formatter).to receive(:call) { fail StandardError }
1305
1307
  allow(Grape::Formatter::Base).to receive(:formatter_for) { formatter }
1306
1308
 
1307
- subject.rescue_from :all do |e|
1309
+ subject.rescue_from :all do |_e|
1308
1310
  rack_response('Formatter Error', 500)
1309
1311
  end
1310
1312
  subject.get('/formatter_exception') { 'Hello world' }
@@ -1540,7 +1542,7 @@ describe Grape::API do
1540
1542
  context 'class' do
1541
1543
  before :each do
1542
1544
  class CustomErrorFormatter
1543
- def self.call(message, backtrace, options, env)
1545
+ def self.call(message, _backtrace, _options, _env)
1544
1546
  "message: #{message} @backtrace"
1545
1547
  end
1546
1548
  end
@@ -1560,7 +1562,7 @@ describe Grape::API do
1560
1562
  context 'class' do
1561
1563
  before :each do
1562
1564
  class CustomErrorFormatter
1563
- def self.call(message, backtrace, option, env)
1565
+ def self.call(message, _backtrace, _option, _env)
1564
1566
  "message: #{message} @backtrace"
1565
1567
  end
1566
1568
  end
@@ -1646,8 +1648,8 @@ describe Grape::API do
1646
1648
  describe '.formatter' do
1647
1649
  context 'multiple formatters' do
1648
1650
  before :each do
1649
- subject.formatter :json, ->(object, env) { "{\"custom_formatter\":\"#{object[:some] }\"}" }
1650
- subject.formatter :txt, ->(object, env) { "custom_formatter: #{object[:some] }" }
1651
+ subject.formatter :json, ->(object, _env) { "{\"custom_formatter\":\"#{object[:some] }\"}" }
1652
+ subject.formatter :txt, ->(object, _env) { "custom_formatter: #{object[:some] }" }
1651
1653
  subject.get :simple do
1652
1654
  { some: 'hash' }
1653
1655
  end
@@ -1665,7 +1667,7 @@ describe Grape::API do
1665
1667
  before :each do
1666
1668
  subject.content_type :json, 'application/json'
1667
1669
  subject.content_type :custom, 'application/custom'
1668
- subject.formatter :custom, ->(object, env) { "{\"custom_formatter\":\"#{object[:some] }\"}" }
1670
+ subject.formatter :custom, ->(object, _env) { "{\"custom_formatter\":\"#{object[:some] }\"}" }
1669
1671
  subject.get :simple do
1670
1672
  { some: 'hash' }
1671
1673
  end
@@ -1681,7 +1683,7 @@ describe Grape::API do
1681
1683
  end
1682
1684
  context 'custom formatter class' do
1683
1685
  module CustomFormatter
1684
- def self.call(object, env)
1686
+ def self.call(object, _env)
1685
1687
  "{\"custom_formatter\":\"#{object[:some] }\"}"
1686
1688
  end
1687
1689
  end
@@ -1718,7 +1720,7 @@ describe Grape::API do
1718
1720
  before :each do
1719
1721
  subject.content_type :txt, 'text/plain'
1720
1722
  subject.content_type :custom, 'text/custom'
1721
- subject.parser :custom, ->(object, env) { { object.to_sym => object.to_s.reverse } }
1723
+ subject.parser :custom, ->(object, _env) { { object.to_sym => object.to_s.reverse } }
1722
1724
  subject.put :simple do
1723
1725
  params[:simple]
1724
1726
  end
@@ -1733,7 +1735,7 @@ describe Grape::API do
1733
1735
  end
1734
1736
  context 'custom parser class' do
1735
1737
  module CustomParser
1736
- def self.call(object, env)
1738
+ def self.call(object, _env)
1737
1739
  { object.to_sym => object.to_s.reverse }
1738
1740
  end
1739
1741
  end
@@ -2031,6 +2033,22 @@ describe Grape::API do
2031
2033
  expect(route.route_settings[:custom]).to eq(key: 'value')
2032
2034
  end
2033
2035
  end
2036
+ describe 'status' do
2037
+ it 'can be set to arbitrary Fixnum value' do
2038
+ subject.get '/foo' do
2039
+ status 210
2040
+ end
2041
+ get '/foo'
2042
+ expect(last_response.status).to eq 210
2043
+ end
2044
+ it 'can be set with a status code symbol' do
2045
+ subject.get '/foo' do
2046
+ status :see_other
2047
+ end
2048
+ get '/foo'
2049
+ expect(last_response.status).to eq 303
2050
+ end
2051
+ end
2034
2052
  end
2035
2053
 
2036
2054
  context 'desc' do
@@ -2043,7 +2061,7 @@ describe Grape::API do
2043
2061
  end
2044
2062
  it 'describes a method' do
2045
2063
  subject.desc 'first method'
2046
- subject.get :first do ; end
2064
+ subject.get :first do; end
2047
2065
  expect(subject.routes.length).to eq(1)
2048
2066
  route = subject.routes.first
2049
2067
  expect(route.route_description).to eq('first method')
@@ -2052,47 +2070,47 @@ describe Grape::API do
2052
2070
  end
2053
2071
  it 'describes methods separately' do
2054
2072
  subject.desc 'first method'
2055
- subject.get :first do ; end
2073
+ subject.get :first do; end
2056
2074
  subject.desc 'second method'
2057
- subject.get :second do ; end
2075
+ subject.get :second do; end
2058
2076
  expect(subject.routes.count).to eq(2)
2059
2077
  expect(subject.routes.map { |route|
2060
2078
  { description: route.route_description, params: route.route_params }
2061
2079
  }).to eq [
2062
2080
  { description: 'first method', params: {} },
2063
2081
  { description: 'second method', params: {} }
2064
- ]
2082
+ ]
2065
2083
  end
2066
2084
  it 'resets desc' do
2067
2085
  subject.desc 'first method'
2068
- subject.get :first do ; end
2069
- subject.get :second do ; end
2086
+ subject.get :first do; end
2087
+ subject.get :second do; end
2070
2088
  expect(subject.routes.map { |route|
2071
2089
  { description: route.route_description, params: route.route_params }
2072
2090
  }).to eq [
2073
2091
  { description: 'first method', params: {} },
2074
2092
  { description: nil, params: {} }
2075
- ]
2093
+ ]
2076
2094
  end
2077
2095
  it 'namespaces and describe arbitrary parameters' do
2078
2096
  subject.namespace 'ns' do
2079
2097
  desc 'ns second', foo: 'bar'
2080
- get 'second' do ; end
2098
+ get 'second' do; end
2081
2099
  end
2082
2100
  expect(subject.routes.map { |route|
2083
2101
  { description: route.route_description, foo: route.route_foo, params: route.route_params }
2084
2102
  }).to eq [
2085
2103
  { description: 'ns second', foo: 'bar', params: {} }
2086
- ]
2104
+ ]
2087
2105
  end
2088
2106
  it 'includes details' do
2089
2107
  subject.desc 'method', details: 'method details'
2090
- subject.get 'method' do ; end
2108
+ subject.get 'method' do; end
2091
2109
  expect(subject.routes.map { |route|
2092
2110
  { description: route.route_description, details: route.route_details, params: route.route_params }
2093
2111
  }).to eq [
2094
2112
  { description: 'method', details: 'method details', params: {} }
2095
- ]
2113
+ ]
2096
2114
  end
2097
2115
  it 'describes a method with parameters' do
2098
2116
  subject.desc 'Reverses a string.', params: { 's' => { desc: 'string to reverse', type: 'string' } }
@@ -2103,7 +2121,7 @@ describe Grape::API do
2103
2121
  { description: route.route_description, params: route.route_params }
2104
2122
  }).to eq [
2105
2123
  { description: 'Reverses a string.', params: { 's' => { desc: 'string to reverse', type: 'string' } } }
2106
- ]
2124
+ ]
2107
2125
  end
2108
2126
  it 'merges the parameters of the namespace with the parameters of the method' do
2109
2127
  subject.desc 'namespace'
@@ -2115,7 +2133,7 @@ describe Grape::API do
2115
2133
  params do
2116
2134
  optional :method_param, desc: 'method parameter'
2117
2135
  end
2118
- get 'method' do ; end
2136
+ get 'method' do; end
2119
2137
  end
2120
2138
 
2121
2139
  routes_doc = subject.routes.map { |route|
@@ -2128,7 +2146,7 @@ describe Grape::API do
2128
2146
  'method_param' => { required: false, desc: 'method parameter' }
2129
2147
  }
2130
2148
  }
2131
- ]
2149
+ ]
2132
2150
  end
2133
2151
  it 'merges the parameters of nested namespaces' do
2134
2152
  subject.desc 'ns1'
@@ -2147,7 +2165,7 @@ describe Grape::API do
2147
2165
  params do
2148
2166
  optional :method_param, desc: 'method param'
2149
2167
  end
2150
- get 'method' do ; end
2168
+ get 'method' do; end
2151
2169
  end
2152
2170
  end
2153
2171
  expect(subject.routes.map { |route|
@@ -2161,7 +2179,7 @@ describe Grape::API do
2161
2179
  'method_param' => { required: false, desc: 'method param' }
2162
2180
  }
2163
2181
  }
2164
- ]
2182
+ ]
2165
2183
  end
2166
2184
  it 'groups nested params and prevents overwriting of params with same name in different groups' do
2167
2185
  subject.desc 'method'
@@ -2175,7 +2193,7 @@ describe Grape::API do
2175
2193
  requires :param2, desc: 'group2 param2 desc'
2176
2194
  end
2177
2195
  end
2178
- subject.get 'method' do ; end
2196
+ subject.get 'method' do; end
2179
2197
 
2180
2198
  expect(subject.routes.map(&:route_params)).to eq [{
2181
2199
  'group1' => { required: true, type: 'Array' },
@@ -2194,7 +2212,7 @@ describe Grape::API do
2194
2212
  requires :nested_param, desc: 'nested param'
2195
2213
  end
2196
2214
  end
2197
- subject.get 'method' do ; end
2215
+ subject.get 'method' do; end
2198
2216
  expect(subject.routes.map { |route|
2199
2217
  { description: route.route_description, params: route.route_params }
2200
2218
  }).to eq [
@@ -2205,7 +2223,7 @@ describe Grape::API do
2205
2223
  'nested[nested_param]' => { required: true, desc: 'nested param' }
2206
2224
  }
2207
2225
  }
2208
- ]
2226
+ ]
2209
2227
  end
2210
2228
  it 'allows to set the type attribute on :group element' do
2211
2229
  subject.params do
@@ -2218,12 +2236,12 @@ describe Grape::API do
2218
2236
  subject.params do
2219
2237
  requires :one_param, desc: 'one param'
2220
2238
  end
2221
- subject.get 'method' do ; end
2239
+ subject.get 'method' do; end
2222
2240
  expect(subject.routes.map { |route|
2223
2241
  { description: route.route_description, params: route.route_params }
2224
2242
  }).to eq [
2225
2243
  { description: nil, params: { 'one_param' => { required: true, desc: 'one param' } } }
2226
- ]
2244
+ ]
2227
2245
  end
2228
2246
  it 'does not symbolize params' do
2229
2247
  subject.desc 'Reverses a string.', params: { 's' => { desc: 'string to reverse', type: 'string' } }
@@ -2234,12 +2252,12 @@ describe Grape::API do
2234
2252
  { description: route.route_description, params: route.route_params }
2235
2253
  }).to eq [
2236
2254
  { description: 'Reverses a string.', params: { 's' => { desc: 'string to reverse', type: 'string' } } }
2237
- ]
2255
+ ]
2238
2256
  end
2239
2257
  end
2240
2258
 
2241
2259
  describe '.mount' do
2242
- let(:mounted_app) { ->(env) { [200, {}, ['MOUNTED']] } }
2260
+ let(:mounted_app) { ->(_env) { [200, {}, ['MOUNTED']] } }
2243
2261
 
2244
2262
  context 'with a bare rack app' do
2245
2263
  before do
@@ -2626,7 +2644,11 @@ describe Grape::API do
2626
2644
  get '/meaning_of_life'
2627
2645
  expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
2628
2646
  end
2629
- it 'does not accept any extensions' do
2647
+ it 'accepts specified extension' do
2648
+ get '/meaning_of_life.txt'
2649
+ expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
2650
+ end
2651
+ it 'does not accept extensions other than specified' do
2630
2652
  get '/meaning_of_life.json'
2631
2653
  expect(last_response.status).to eq(404)
2632
2654
  end