grape 0.15.0 → 0.16.1

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -1
  3. data/Gemfile.lock +16 -15
  4. data/README.md +41 -47
  5. data/UPGRADING.md +62 -0
  6. data/gemfiles/rails_3.gemfile.lock +225 -0
  7. data/grape.gemspec +2 -2
  8. data/lib/grape.rb +31 -26
  9. data/lib/grape/api.rb +39 -23
  10. data/lib/grape/dsl/inside_route.rb +8 -4
  11. data/lib/grape/dsl/routing.rb +2 -1
  12. data/lib/grape/endpoint.rb +43 -62
  13. data/lib/grape/error_formatter.rb +4 -2
  14. data/lib/grape/error_formatter/base.rb +10 -6
  15. data/lib/grape/formatter.rb +4 -2
  16. data/lib/grape/http/headers.rb +1 -0
  17. data/lib/grape/middleware/formatter.rb +2 -2
  18. data/lib/grape/middleware/versioner/accept_version_header.rb +2 -2
  19. data/lib/grape/middleware/versioner/header.rb +2 -2
  20. data/lib/grape/middleware/versioner/path.rb +2 -2
  21. data/lib/grape/namespace.rb +1 -1
  22. data/lib/grape/parser.rb +4 -2
  23. data/lib/grape/path.rb +3 -3
  24. data/lib/grape/request.rb +2 -2
  25. data/lib/grape/router.rb +156 -0
  26. data/lib/grape/router/attribute_translator.rb +40 -0
  27. data/lib/grape/router/pattern.rb +55 -0
  28. data/lib/grape/router/route.rb +105 -0
  29. data/lib/grape/serve_file/file_body.rb +34 -0
  30. data/lib/grape/{util → serve_file}/file_response.rb +1 -1
  31. data/lib/grape/{util → serve_file}/sendfile_response.rb +1 -1
  32. data/lib/grape/util/env.rb +1 -1
  33. data/lib/grape/util/registrable.rb +13 -0
  34. data/lib/grape/validations/types/custom_type_coercer.rb +2 -0
  35. data/lib/grape/version.rb +1 -1
  36. data/spec/grape/api/invalid_format_spec.rb +43 -0
  37. data/spec/grape/api/recognize_path_spec.rb +21 -0
  38. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +26 -0
  39. data/spec/grape/api_spec.rb +110 -38
  40. data/spec/grape/dsl/inside_route_spec.rb +267 -240
  41. data/spec/grape/endpoint_spec.rb +10 -0
  42. data/spec/grape/entity_spec.rb +2 -2
  43. data/spec/grape/middleware/formatter_spec.rb +23 -4
  44. data/spec/grape/middleware/versioner/header_spec.rb +1 -1
  45. data/spec/grape/middleware/versioner/path_spec.rb +1 -1
  46. data/spec/grape/parser_spec.rb +82 -0
  47. data/spec/grape/request_spec.rb +2 -2
  48. data/spec/grape/validations/params_scope_spec.rb +2 -2
  49. data/spec/grape/validations/validators/coerce_spec.rb +51 -0
  50. data/spec/grape/validations_spec.rb +1 -1
  51. data/tmp/Gemfile.lock +63 -0
  52. metadata +70 -55
  53. data/lib/grape/route.rb +0 -32
@@ -0,0 +1,105 @@
1
+ require 'grape/router/pattern'
2
+ require 'grape/router/attribute_translator'
3
+ require 'forwardable'
4
+ require 'pathname'
5
+
6
+ module Grape
7
+ class Router
8
+ class Route
9
+ ROUTE_ATTRIBUTE_REGEXP = /route_([_a-zA-Z]\w*)/.freeze
10
+ SOURCE_LOCATION_REGEXP = /^(.*?):(\d+?)(?::in `.+?')?$/.freeze
11
+ TRANSLATION_ATTRIBUTES = [
12
+ :prefix,
13
+ :version,
14
+ :namespace,
15
+ :settings,
16
+ :format,
17
+ :description,
18
+ :http_codes,
19
+ :headers,
20
+ :entity,
21
+ :details,
22
+ :requirements,
23
+ :request_method
24
+ ].freeze
25
+
26
+ attr_accessor :pattern, :translator, :app, :index, :regexp
27
+
28
+ alias_method :attributes, :translator
29
+
30
+ extend Forwardable
31
+ def_delegators :pattern, :path, :origin
32
+
33
+ def self.translate(*attributes)
34
+ AttributeTranslator.register(*attributes)
35
+ def_delegators :@translator, *attributes
36
+ end
37
+
38
+ translate(*TRANSLATION_ATTRIBUTES)
39
+
40
+ def method_missing(method_id, *arguments)
41
+ match = ROUTE_ATTRIBUTE_REGEXP.match(method_id.to_s)
42
+ if match
43
+ method_name = match.captures.last.to_sym
44
+ warn_route_methods(method_name, caller(1).shift)
45
+ @options[method_name]
46
+ else
47
+ super
48
+ end
49
+ end
50
+
51
+ def route_method
52
+ warn_route_methods(:method, caller(1).shift, :request_method)
53
+ request_method
54
+ end
55
+
56
+ def route_path
57
+ warn_route_methods(:path, caller(1).shift)
58
+ pattern.path
59
+ end
60
+
61
+ def initialize(method, pattern, options = {})
62
+ @suffix = options[:suffix]
63
+ @options = options.merge(method: method.to_s.upcase)
64
+ @pattern = Pattern.new(pattern, options)
65
+ @translator = AttributeTranslator.new(options.merge(request_method: method.to_s.upcase))
66
+ end
67
+
68
+ def exec(env)
69
+ @app.call(env)
70
+ end
71
+
72
+ def apply(app)
73
+ @app = app
74
+ self
75
+ end
76
+
77
+ def match?(input)
78
+ translator.respond_to?(:forward_match) && translator.forward_match ? input.start_with?(pattern.origin) : pattern.match?(input)
79
+ end
80
+
81
+ def params(input = nil)
82
+ if input.nil?
83
+ default = pattern.named_captures.keys.each_with_object({}) do |key, defaults|
84
+ defaults[key] = ''
85
+ end
86
+ default.delete_if { |key, _| key == 'format' }.merge(translator.params)
87
+ else
88
+ parsed = pattern.params(input)
89
+ parsed ? parsed.delete_if { |_, value| value.nil? }.symbolize_keys : {}
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ def warn_route_methods(name, location, expected = nil)
96
+ path, line = *location.scan(SOURCE_LOCATION_REGEXP).first
97
+ path = File.realpath(path) if Pathname.new(path).relative?
98
+ expected ||= name
99
+ warn <<-EOS
100
+ #{path}:#{line}: The route_xxx methods such as route_#{name} have been deprecated, please use #{expected}.
101
+ EOS
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,34 @@
1
+ module Grape
2
+ module ServeFile
3
+ CHUNK_SIZE = 16_384
4
+
5
+ # Class helps send file through API
6
+ class FileBody
7
+ attr_reader :path
8
+
9
+ # @param path [String]
10
+ def initialize(path)
11
+ @path = path
12
+ end
13
+
14
+ # Need for Rack::Sendfile middleware
15
+ #
16
+ # @return [String]
17
+ def to_path
18
+ path
19
+ end
20
+
21
+ def each
22
+ File.open(path, 'rb') do |file|
23
+ while (chunk = file.read(CHUNK_SIZE))
24
+ yield chunk
25
+ end
26
+ end
27
+ end
28
+
29
+ def ==(other)
30
+ path == other.path
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,5 +1,5 @@
1
1
  module Grape
2
- module Util
2
+ module ServeFile
3
3
  # A simple class used to identify responses which represent files and do not
4
4
  # need to be formatted or pre-read by Rack::Response
5
5
  class FileResponse
@@ -1,5 +1,5 @@
1
1
  module Grape
2
- module Util
2
+ module ServeFile
3
3
  # Response should respond to to_path method
4
4
  # for using Rack::SendFile middleware
5
5
  class SendfileResponse < Rack::Response
@@ -13,10 +13,10 @@ module Grape
13
13
  RACK_REQUEST_QUERY_HASH = 'rack.request.query_hash'.freeze
14
14
  RACK_REQUEST_FORM_HASH = 'rack.request.form_hash'.freeze
15
15
  RACK_REQUEST_FORM_INPUT = 'rack.request.form_input'.freeze
16
- RACK_ROUTING_ARGS = 'rack.routing_args'.freeze
17
16
 
18
17
  GRAPE_REQUEST = 'grape.request'.freeze
19
18
  GRAPE_REQUEST_HEADERS = 'grape.request.headers'.freeze
20
19
  GRAPE_REQUEST_PARAMS = 'grape.request.params'.freeze
20
+ GRAPE_ROUTING_ARGS = 'grape.routing_args'.freeze
21
21
  end
22
22
  end
@@ -0,0 +1,13 @@
1
+ module Grape
2
+ module Util
3
+ module Registrable
4
+ def default_elements
5
+ @default_elements ||= {}
6
+ end
7
+
8
+ def register(format, element)
9
+ default_elements[format] = element unless default_elements[format]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -136,6 +136,8 @@ module Grape
136
136
  # Note that this will fail unless a method is also
137
137
  # passed, or if the type also implements a parse() method.
138
138
  type
139
+ elsif type.is_a?(Enumerable)
140
+ ->(value) { value.all? { |item| item.is_a? type[0] } }
139
141
  else
140
142
  # By default, do a simple type check
141
143
  ->(value) { value.is_a? type }
@@ -1,4 +1,4 @@
1
1
  module Grape
2
2
  # The current version of Grape.
3
- VERSION = '0.15.0'
3
+ VERSION = '0.16.1'
4
4
  end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Grape::Endpoint do
4
+ subject { Class.new(Grape::API) }
5
+
6
+ def app
7
+ subject
8
+ end
9
+
10
+ before do
11
+ subject.namespace do
12
+ format :json
13
+ content_type :json, 'application/json'
14
+ params do
15
+ requires :id, desc: 'Identifier.'
16
+ end
17
+ get ':id' do
18
+ {
19
+ id: params[:id],
20
+ format: params[:format]
21
+ }
22
+ end
23
+ end
24
+ end
25
+
26
+ context 'get' do
27
+ it 'no format' do
28
+ get '/foo'
29
+ expect(last_response.status).to eq 200
30
+ expect(last_response.body).to eq(MultiJson.dump(id: 'foo', format: nil))
31
+ end
32
+ it 'json format' do
33
+ get '/foo.json'
34
+ expect(last_response.status).to eq 200
35
+ expect(last_response.body).to eq(MultiJson.dump(id: 'foo', format: 'json'))
36
+ end
37
+ it 'invalid format' do
38
+ get '/foo.invalid'
39
+ expect(last_response.status).to eq 200
40
+ expect(last_response.body).to eq(MultiJson.dump(id: 'foo', format: 'invalid'))
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Grape::API do
4
+ describe '.recognize_path' do
5
+ subject { Class.new(Grape::API) }
6
+
7
+ it 'fetches endpoint by given path' do
8
+ subject.get('/foo/:id') {}
9
+ subject.get('/bar/:id') {}
10
+ subject.get('/baz/:id') {}
11
+
12
+ actual = subject.recognize_path('/bar/1234').routes[0].origin
13
+ expect(actual).to eq('/bar/:id')
14
+ end
15
+
16
+ it 'returns nil if given path does not match with registered routes' do
17
+ subject.get {}
18
+ expect(subject.recognize_path('/bar/1234')).to be_nil
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Grape::Endpoint do
4
+ subject { Class.new(Grape::API) }
5
+
6
+ def app
7
+ subject
8
+ end
9
+
10
+ before do
11
+ subject.namespace do
12
+ params do
13
+ requires :id, desc: 'Identifier.'
14
+ end
15
+ get ':id' do
16
+ end
17
+ end
18
+ end
19
+
20
+ context 'post' do
21
+ it '405' do
22
+ post '/something'
23
+ expect(last_response.status).to eq 405
24
+ end
25
+ end
26
+ end
@@ -411,7 +411,7 @@ describe Grape::API do
411
411
  end
412
412
 
413
413
  subject.endpoints.first.routes.each do |route|
414
- expect(route.route_path).to eql '/abc(.:format)'
414
+ expect(route.path).to eql '/abc(.:format)'
415
415
  end
416
416
 
417
417
  get '/abc'
@@ -567,6 +567,72 @@ XML
567
567
  expect(last_response.headers['Content-Type']).to eql 'text/plain'
568
568
  end
569
569
 
570
+ describe 'adds an OPTIONS route that' do
571
+ before do
572
+ subject.before { header 'X-Custom-Header', 'foo' }
573
+ subject.get 'example' do
574
+ 'example'
575
+ end
576
+ subject.route :any, '*path' do
577
+ error! :not_found, 404
578
+ end
579
+ options '/example'
580
+ end
581
+
582
+ it 'returns a 204' do
583
+ expect(last_response.status).to eql 204
584
+ end
585
+
586
+ it 'has an empty body' do
587
+ expect(last_response.body).to be_blank
588
+ end
589
+
590
+ it 'has an Allow header' do
591
+ expect(last_response.headers['Allow']).to eql 'OPTIONS, GET, HEAD'
592
+ end
593
+
594
+ it 'has a X-Custom-Header' do
595
+ expect(last_response.headers['X-Custom-Header']).to eql 'foo'
596
+ end
597
+
598
+ it 'has no Content-Type' do
599
+ expect(last_response.content_type).to be_nil
600
+ end
601
+
602
+ it 'has no Content-Length' do
603
+ expect(last_response.content_length).to be_nil
604
+ end
605
+ end
606
+
607
+ describe 'adds a 405 Not Allowed route that' do
608
+ before do
609
+ subject.before { header 'X-Custom-Header', 'foo' }
610
+ subject.post :example do
611
+ 'example'
612
+ end
613
+ subject.route :any, '*path' do
614
+ error! :not_found, 404
615
+ end
616
+ get '/example'
617
+ end
618
+
619
+ it 'returns a 405' do
620
+ expect(last_response.status).to eql 405
621
+ end
622
+
623
+ it 'contains error message in body' do
624
+ expect(last_response.body).to eq '405 Not Allowed'
625
+ end
626
+
627
+ it 'has an Allow header' do
628
+ expect(last_response.headers['Allow']).to eql 'OPTIONS, POST'
629
+ end
630
+
631
+ it 'has a X-Custom-Header' do
632
+ expect(last_response.headers['X-Custom-Header']).to eql 'foo'
633
+ end
634
+ end
635
+
570
636
  context 'allows HEAD on a GET request that' do
571
637
  before do
572
638
  subject.get 'example' do
@@ -1980,7 +2046,7 @@ XML
1980
2046
  end
1981
2047
 
1982
2048
  it 'presented with' do
1983
- error = { code: 408, with: error_presenter }
2049
+ error = { code: 408, with: error_presenter }.freeze
1984
2050
  subject.get '/exception' do
1985
2051
  error! error, 408
1986
2052
  end
@@ -2006,9 +2072,9 @@ XML
2006
2072
  it 'returns one route' do
2007
2073
  expect(subject.routes.size).to eq(1)
2008
2074
  route = subject.routes[0]
2009
- expect(route.route_version).to be_nil
2010
- expect(route.route_path).to eq('/ping(.:format)')
2011
- expect(route.route_method).to eq('GET')
2075
+ expect(route.version).to be_nil
2076
+ expect(route.path).to eq('/ping(.:format)')
2077
+ expect(route.request_method).to eq('GET')
2012
2078
  end
2013
2079
  end
2014
2080
  describe 'api structure with two versions and a namespace' do
@@ -2036,18 +2102,18 @@ XML
2036
2102
  end
2037
2103
  it 'sets route paths' do
2038
2104
  expect(subject.routes.size).to be >= 2
2039
- expect(subject.routes[0].route_path).to eq('/:version/version(.:format)')
2040
- expect(subject.routes[1].route_path).to eq('/p/:version/n1/n2/version(.:format)')
2105
+ expect(subject.routes[0].path).to eq('/:version/version(.:format)')
2106
+ expect(subject.routes[1].path).to eq('/p/:version/n1/n2/version(.:format)')
2041
2107
  end
2042
2108
  it 'sets route versions' do
2043
- expect(subject.routes[0].route_version).to eq('v1')
2044
- expect(subject.routes[1].route_version).to eq('v2')
2109
+ expect(subject.routes[0].version).to eq('v1')
2110
+ expect(subject.routes[1].version).to eq('v2')
2045
2111
  end
2046
2112
  it 'sets a nested namespace' do
2047
- expect(subject.routes[1].route_namespace).to eq('/n1/n2')
2113
+ expect(subject.routes[1].namespace).to eq('/n1/n2')
2048
2114
  end
2049
2115
  it 'sets prefix' do
2050
- expect(subject.routes[1].route_prefix).to eq('p')
2116
+ expect(subject.routes[1].prefix).to eq('p')
2051
2117
  end
2052
2118
  end
2053
2119
  describe 'api structure with additional parameters' do
@@ -2068,9 +2134,9 @@ XML
2068
2134
  get '/split/a,b,c.json', token: ',', limit: '2'
2069
2135
  expect(last_response.body).to eq('["a","b,c"]')
2070
2136
  end
2071
- it 'sets route_params' do
2137
+ it 'sets params' do
2072
2138
  expect(subject.routes.map { |route|
2073
- { params: route.route_params }
2139
+ { params: route.params }
2074
2140
  }).to eq [
2075
2141
  {
2076
2142
  params: {
@@ -2098,9 +2164,9 @@ XML
2098
2164
  subject.get 'two' do
2099
2165
  end
2100
2166
  end
2101
- it 'sets route_params' do
2167
+ it 'sets params' do
2102
2168
  expect(subject.routes.map { |route|
2103
- { params: route.route_params }
2169
+ { params: route.params }
2104
2170
  }).to eq [
2105
2171
  {
2106
2172
  params: {
@@ -2129,9 +2195,9 @@ XML
2129
2195
  subject.get 'two' do
2130
2196
  end
2131
2197
  end
2132
- it 'sets route_params' do
2198
+ it 'sets params' do
2133
2199
  expect(subject.routes.map { |route|
2134
- { params: route.route_params }
2200
+ { params: route.params }
2135
2201
  }).to eq [
2136
2202
  {
2137
2203
  params: {
@@ -2153,7 +2219,7 @@ XML
2153
2219
  it 'exposed' do
2154
2220
  expect(subject.routes.count).to eq 1
2155
2221
  route = subject.routes.first
2156
- expect(route.route_settings[:custom]).to eq(key: 'value')
2222
+ expect(route.settings[:custom]).to eq(key: 'value')
2157
2223
  end
2158
2224
  end
2159
2225
  describe 'status' do
@@ -2187,9 +2253,9 @@ XML
2187
2253
  subject.get :first do; end
2188
2254
  expect(subject.routes.length).to eq(1)
2189
2255
  route = subject.routes.first
2190
- expect(route.route_description).to eq('first method')
2256
+ expect(route.description).to eq('first method')
2191
2257
  expect(route.route_foo).to be_nil
2192
- expect(route.route_params).to eq({})
2258
+ expect(route.params).to eq({})
2193
2259
  end
2194
2260
  it 'describes methods separately' do
2195
2261
  subject.desc 'first method'
@@ -2198,7 +2264,7 @@ XML
2198
2264
  subject.get :second do; end
2199
2265
  expect(subject.routes.count).to eq(2)
2200
2266
  expect(subject.routes.map { |route|
2201
- { description: route.route_description, params: route.route_params }
2267
+ { description: route.description, params: route.params }
2202
2268
  }).to eq [
2203
2269
  { description: 'first method', params: {} },
2204
2270
  { description: 'second method', params: {} }
@@ -2209,7 +2275,7 @@ XML
2209
2275
  subject.get :first do; end
2210
2276
  subject.get :second do; end
2211
2277
  expect(subject.routes.map { |route|
2212
- { description: route.route_description, params: route.route_params }
2278
+ { description: route.description, params: route.params }
2213
2279
  }).to eq [
2214
2280
  { description: 'first method', params: {} },
2215
2281
  { description: nil, params: {} }
@@ -2221,7 +2287,7 @@ XML
2221
2287
  get 'second' do; end
2222
2288
  end
2223
2289
  expect(subject.routes.map { |route|
2224
- { description: route.route_description, foo: route.route_foo, params: route.route_params }
2290
+ { description: route.description, foo: route.route_foo, params: route.params }
2225
2291
  }).to eq [
2226
2292
  { description: 'ns second', foo: 'bar', params: {} }
2227
2293
  ]
@@ -2230,7 +2296,7 @@ XML
2230
2296
  subject.desc 'method', details: 'method details'
2231
2297
  subject.get 'method' do; end
2232
2298
  expect(subject.routes.map { |route|
2233
- { description: route.route_description, details: route.route_details, params: route.route_params }
2299
+ { description: route.description, details: route.details, params: route.params }
2234
2300
  }).to eq [
2235
2301
  { description: 'method', details: 'method details', params: {} }
2236
2302
  ]
@@ -2241,7 +2307,7 @@ XML
2241
2307
  params[:s].reverse
2242
2308
  end
2243
2309
  expect(subject.routes.map { |route|
2244
- { description: route.route_description, params: route.route_params }
2310
+ { description: route.description, params: route.params }
2245
2311
  }).to eq [
2246
2312
  { description: 'Reverses a string.', params: { 's' => { desc: 'string to reverse', type: 'string' } } }
2247
2313
  ]
@@ -2262,7 +2328,7 @@ XML
2262
2328
  get do; end
2263
2329
  end
2264
2330
  routes_doc = subject.routes.map { |route|
2265
- { description: route.route_description, params: route.route_params }
2331
+ { description: route.description, params: route.params }
2266
2332
  }
2267
2333
  expect(routes_doc).to eq [
2268
2334
  { description: 'global description',
@@ -2292,7 +2358,7 @@ XML
2292
2358
  end
2293
2359
 
2294
2360
  routes_doc = subject.routes.map { |route|
2295
- { description: route.route_description, params: route.route_params }
2361
+ { description: route.description, params: route.params }
2296
2362
  }
2297
2363
  expect(routes_doc).to eq [
2298
2364
  { description: 'method',
@@ -2324,7 +2390,7 @@ XML
2324
2390
  end
2325
2391
  end
2326
2392
  expect(subject.routes.map { |route|
2327
- { description: route.route_description, params: route.route_params }
2393
+ { description: route.description, params: route.params }
2328
2394
  }).to eq [
2329
2395
  { description: 'method',
2330
2396
  params: {
@@ -2350,7 +2416,7 @@ XML
2350
2416
  end
2351
2417
  subject.get 'method' do; end
2352
2418
 
2353
- expect(subject.routes.map(&:route_params)).to eq [{
2419
+ expect(subject.routes.map(&:params)).to eq [{
2354
2420
  'group1' => { required: true, type: 'Array' },
2355
2421
  'group1[param1]' => { required: false, desc: 'group1 param1 desc' },
2356
2422
  'group1[param2]' => { required: true, desc: 'group1 param2 desc' },
@@ -2369,7 +2435,7 @@ XML
2369
2435
  end
2370
2436
  subject.get 'method' do; end
2371
2437
  expect(subject.routes.map { |route|
2372
- { description: route.route_description, params: route.route_params }
2438
+ { description: route.description, params: route.params }
2373
2439
  }).to eq [
2374
2440
  { description: 'nesting',
2375
2441
  params: {
@@ -2393,7 +2459,7 @@ XML
2393
2459
  end
2394
2460
  subject.get 'method' do; end
2395
2461
  expect(subject.routes.map { |route|
2396
- { description: route.route_description, params: route.route_params }
2462
+ { description: route.description, params: route.params }
2397
2463
  }).to eq [
2398
2464
  { description: nil, params: { 'one_param' => { required: true, desc: 'one param' } } }
2399
2465
  ]
@@ -2404,7 +2470,7 @@ XML
2404
2470
  params[:s].reverse
2405
2471
  end
2406
2472
  expect(subject.routes.map { |route|
2407
- { description: route.route_description, params: route.route_params }
2473
+ { description: route.description, params: route.params }
2408
2474
  }).to eq [
2409
2475
  { description: 'Reverses a string.', params: { 's' => { desc: 'string to reverse', type: 'string' } } }
2410
2476
  ]
@@ -2512,8 +2578,8 @@ XML
2512
2578
  mount app
2513
2579
  end
2514
2580
  expect(subject.routes.size).to eq(2)
2515
- expect(subject.routes.first.route_path).to match(%r{\/cool\/awesome})
2516
- expect(subject.routes.last.route_path).to match(%r{\/cool\/sauce})
2581
+ expect(subject.routes.first.path).to match(%r{\/cool\/awesome})
2582
+ expect(subject.routes.last.path).to match(%r{\/cool\/sauce})
2517
2583
  end
2518
2584
 
2519
2585
  it 'mounts on a path' do
@@ -2732,10 +2798,10 @@ XML
2732
2798
  context 'plain' do
2733
2799
  before(:each) do
2734
2800
  subject.get '/' do
2735
- route.route_path
2801
+ route.path
2736
2802
  end
2737
2803
  subject.get '/path' do
2738
- route.route_path
2804
+ route.path
2739
2805
  end
2740
2806
  end
2741
2807
  it 'provides access to route info' do
@@ -2749,11 +2815,11 @@ XML
2749
2815
  before(:each) do
2750
2816
  subject.desc 'returns description'
2751
2817
  subject.get '/description' do
2752
- route.route_description
2818
+ route.description
2753
2819
  end
2754
2820
  subject.desc 'returns parameters', params: { 'x' => 'y' }
2755
2821
  subject.get '/params/:id' do
2756
- route.route_params[params[:id]]
2822
+ route.params[params[:id]]
2757
2823
  end
2758
2824
  end
2759
2825
  it 'returns route description' do
@@ -2980,6 +3046,12 @@ XML
2980
3046
  get '/v2/hello'
2981
3047
  expect(last_response.status).to eq(200)
2982
3048
  expect(last_response.body).to eq('v2')
3049
+ options '/v2/hello'
3050
+ expect(last_response.status).to eq(204)
3051
+ expect(last_response.body).to be_blank
3052
+ head '/v2/hello'
3053
+ expect(last_response.status).to eq(200)
3054
+ expect(last_response.body).to be_blank
2983
3055
  get '/foobar'
2984
3056
  expect(last_response.status).to eq(404)
2985
3057
  expect(last_response.body).to eq('Unrecognized request path: foobar - /foobar')