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
@@ -103,12 +103,14 @@ module Grape
103
103
  def namespace_stackable_with_hash(key)
104
104
  settings = get_or_set :namespace_stackable, key, nil
105
105
  return if settings.blank?
106
+
106
107
  settings.each_with_object({}) { |value, result| result.deep_merge!(value) }
107
108
  end
108
109
 
109
110
  def namespace_reverse_stackable_with_hash(key)
110
111
  settings = get_or_set :namespace_reverse_stackable, key, nil
111
112
  return if settings.blank?
113
+
112
114
  result = {}
113
115
  settings.each do |setting|
114
116
  setting.each do |field, value|
@@ -154,10 +156,10 @@ module Grape
154
156
 
155
157
  # Execute the block within a context where our inheritable settings are forked
156
158
  # to a new copy (see #namespace_start).
157
- def within_namespace(&_block)
159
+ def within_namespace(&block)
158
160
  namespace_start
159
161
 
160
- result = yield if block_given?
162
+ result = yield if block
161
163
 
162
164
  namespace_end
163
165
  reset_validations!
@@ -175,9 +177,7 @@ module Grape
175
177
  # +inheritable_setting+, however, it doesn't contain any user-defined settings.
176
178
  # Otherwise, it would lead to an extra instance of +Grape::Util::InheritableSetting+
177
179
  # in the chain for every endpoint.
178
- if defined?(superclass) && superclass.respond_to?(:inheritable_setting) && superclass != Grape::API::Instance
179
- setting.inherit_from superclass.inheritable_setting
180
- end
180
+ setting.inherit_from superclass.inheritable_setting if defined?(superclass) && superclass.respond_to?(:inheritable_setting) && superclass != Grape::API::Instance
181
181
  end
182
182
  end
183
183
  end
@@ -20,7 +20,8 @@ module Grape
20
20
  def before_each(new_setup = false, &block)
21
21
  @before_each ||= []
22
22
  if new_setup == false
23
- return @before_each unless block_given?
23
+ return @before_each unless block
24
+
24
25
  @before_each << block
25
26
  else
26
27
  @before_each = [new_setup]
@@ -46,9 +47,7 @@ module Grape
46
47
  # @return [Proc]
47
48
  # @raise [NameError] an instance method with the same name already exists
48
49
  def generate_api_method(method_name, &block)
49
- if method_defined?(method_name)
50
- raise NameError.new("method #{method_name.inspect} already exists and cannot be used as an unbound method name")
51
- end
50
+ raise NameError.new("method #{method_name.inspect} already exists and cannot be used as an unbound method name") if method_defined?(method_name)
52
51
 
53
52
  define_method(method_name, &block)
54
53
  method = instance_method(method_name)
@@ -106,7 +105,7 @@ module Grape
106
105
  @body = nil
107
106
  @proc = nil
108
107
 
109
- return unless block_given?
108
+ return unless block
110
109
 
111
110
  @source = block
112
111
  @block = self.class.generate_api_method(method_name, &block)
@@ -118,11 +117,9 @@ module Grape
118
117
  inheritable_setting.route[:saved_validations] += namespace_stackable[:validations]
119
118
  parent_declared_params = namespace_stackable[:declared_params]
120
119
 
121
- if parent_declared_params
122
- inheritable_setting.route[:declared_params].concat(parent_declared_params.flatten)
123
- end
120
+ inheritable_setting.route[:declared_params].concat(parent_declared_params.flatten) if parent_declared_params
124
121
 
125
- endpoints && endpoints.each { |e| e.inherit_settings(namespace_stackable) }
122
+ endpoints&.each { |e| e.inherit_settings(namespace_stackable) }
126
123
  end
127
124
 
128
125
  def require_option(options, key)
@@ -142,7 +139,7 @@ module Grape
142
139
  end
143
140
 
144
141
  def reset_routes!
145
- endpoints.each(&:reset_routes!) if endpoints
142
+ endpoints&.each(&:reset_routes!)
146
143
  @namespace = nil
147
144
  @routes = nil
148
145
  end
@@ -154,13 +151,9 @@ module Grape
154
151
  reset_routes!
155
152
  routes.each do |route|
156
153
  methods = [route.request_method]
157
- if !namespace_inheritable(:do_not_route_head) && route.request_method == Grape::Http::Headers::GET
158
- methods << Grape::Http::Headers::HEAD
159
- end
154
+ methods << Grape::Http::Headers::HEAD if !namespace_inheritable(:do_not_route_head) && route.request_method == Grape::Http::Headers::GET
160
155
  methods.each do |method|
161
- unless route.request_method == method
162
- route = Grape::Router::Route.new(method, route.origin, **route.attributes.to_h)
163
- end
156
+ route = Grape::Router::Route.new(method, route.origin, **route.attributes.to_h) unless route.request_method == method
164
157
  router.append(route.apply(self))
165
158
  end
166
159
  end
@@ -200,6 +193,7 @@ module Grape
200
193
  def prepare_version
201
194
  version = namespace_inheritable(:version) || []
202
195
  return if version.empty?
196
+
203
197
  version.length == 1 ? version.first.to_s : version
204
198
  end
205
199
 
@@ -234,7 +228,7 @@ module Grape
234
228
  # Return the collection of endpoints within this endpoint.
235
229
  # This is the case when an Grape::API mounts another Grape::API.
236
230
  def endpoints
237
- options[:app].endpoints if options[:app] && options[:app].respond_to?(:endpoints)
231
+ options[:app].endpoints if options[:app].respond_to?(:endpoints)
238
232
  end
239
233
 
240
234
  def equals?(e)
@@ -256,13 +250,13 @@ module Grape
256
250
 
257
251
  if (allowed_methods = env[Grape::Env::GRAPE_ALLOWED_METHODS])
258
252
  raise Grape::Exceptions::MethodNotAllowed.new(header.merge('Allow' => allowed_methods)) unless options?
253
+
259
254
  header 'Allow', allowed_methods
260
255
  response_object = ''
261
256
  status 204
262
257
  else
263
258
  run_filters before_validations, :before_validation
264
259
  run_validators validations, request
265
- remove_renamed_params
266
260
  run_filters after_validations, :after_validation
267
261
  response_object = execute
268
262
  end
@@ -328,14 +322,7 @@ module Grape
328
322
  Module.new { helpers.each { |mod_to_include| include mod_to_include } }
329
323
  end
330
324
 
331
- def remove_renamed_params
332
- return unless route_setting(:renamed_params)
333
- route_setting(:renamed_params).flat_map(&:keys).each do |renamed_param|
334
- @params.delete(renamed_param)
335
- end
336
- end
337
-
338
- private :build_stack, :build_helpers, :remove_renamed_params
325
+ private :build_stack, :build_helpers
339
326
 
340
327
  def execute
341
328
  @block ? @block.call(self) : nil
@@ -365,15 +352,13 @@ module Grape
365
352
 
366
353
  ActiveSupport::Notifications.instrument('endpoint_run_validators.grape', endpoint: self, validators: validators, request: request) do
367
354
  validators.each do |validator|
368
- begin
369
- validator.validate(request)
370
- rescue Grape::Exceptions::Validation => e
371
- validation_errors << e
372
- break if validator.fail_fast?
373
- rescue Grape::Exceptions::ValidationArrayErrors => e
374
- validation_errors.concat e.errors
375
- break if validator.fail_fast?
376
- end
355
+ validator.validate(request)
356
+ rescue Grape::Exceptions::Validation => e
357
+ validation_errors << e
358
+ break if validator.fail_fast?
359
+ rescue Grape::Exceptions::ValidationArrayErrors => e
360
+ validation_errors.concat e.errors
361
+ break if validator.fail_fast?
377
362
  end
378
363
  end
379
364
 
@@ -10,12 +10,8 @@ module Grape
10
10
  result = wrap_message(present(message, env))
11
11
 
12
12
  rescue_options = options[:rescue_options] || {}
13
- if rescue_options[:backtrace] && backtrace && !backtrace.empty?
14
- result = result.merge(backtrace: backtrace)
15
- end
16
- if rescue_options[:original_exception] && original_exception
17
- result = result.merge(original_exception: original_exception.inspect)
18
- end
13
+ result = result.merge(backtrace: backtrace) if rescue_options[:backtrace] && backtrace && !backtrace.empty?
14
+ result = result.merge(original_exception: original_exception.inspect) if rescue_options[:original_exception] && original_exception
19
15
  ::Grape::Json.dump(result)
20
16
  end
21
17
 
@@ -11,12 +11,8 @@ module Grape
11
11
 
12
12
  result = message.is_a?(Hash) ? message : { message: message }
13
13
  rescue_options = options[:rescue_options] || {}
14
- if rescue_options[:backtrace] && backtrace && !backtrace.empty?
15
- result = result.merge(backtrace: backtrace)
16
- end
17
- if rescue_options[:original_exception] && original_exception
18
- result = result.merge(original_exception: original_exception.inspect)
19
- end
14
+ result = result.merge(backtrace: backtrace) if rescue_options[:backtrace] && backtrace && !backtrace.empty?
15
+ result = result.merge(original_exception: original_exception.inspect) if rescue_options[:original_exception] && original_exception
20
16
  result.respond_to?(:to_xml) ? result.to_xml(root: :error) : result.to_s
21
17
  end
22
18
  end
@@ -5,8 +5,7 @@ require 'grape/exceptions/base'
5
5
  module Grape
6
6
  module Exceptions
7
7
  class Validation < Grape::Exceptions::Base
8
- attr_accessor :params
9
- attr_accessor :message_key
8
+ attr_accessor :params, :message_key
10
9
 
11
10
  def initialize(params:, message: nil, **args)
12
11
  @params = params
@@ -6,6 +6,7 @@ module Grape
6
6
  class << self
7
7
  def call(object, _env)
8
8
  return object.to_json if object.respond_to?(:to_json)
9
+
9
10
  ::Grape::Json.dump(object)
10
11
  end
11
12
  end
@@ -8,13 +8,14 @@ module Grape
8
8
  return object if object.is_a?(String)
9
9
  return ::Grape::Json.dump(serialize(object)) if serializable?(object)
10
10
  return object.to_json if object.respond_to?(:to_json)
11
+
11
12
  ::Grape::Json.dump(object)
12
13
  end
13
14
 
14
15
  private
15
16
 
16
17
  def serializable?(object)
17
- object.respond_to?(:serializable_hash) || object.is_a?(Array) && object.all? { |o| o.respond_to? :serializable_hash } || object.is_a?(Hash)
18
+ object.respond_to?(:serializable_hash) || (object.is_a?(Array) && object.all? { |o| o.respond_to? :serializable_hash }) || object.is_a?(Hash)
18
19
  end
19
20
 
20
21
  def serialize(object)
@@ -6,6 +6,7 @@ module Grape
6
6
  class << self
7
7
  def call(object, _env)
8
8
  return object.to_xml if object.respond_to?(:to_xml)
9
+
9
10
  raise Grape::Exceptions::InvalidFormatter.new(object.class, 'xml')
10
11
  end
11
12
  end
@@ -59,6 +59,7 @@ module Grape
59
59
 
60
60
  def response
61
61
  return @app_response if @app_response.is_a?(Rack::Response)
62
+
62
63
  Rack::Response.new(@app_response[2], @app_response[0], @app_response[1])
63
64
  end
64
65
 
@@ -84,6 +85,7 @@ module Grape
84
85
 
85
86
  def merge_headers(response)
86
87
  return unless headers.is_a?(Hash)
88
+
87
89
  case response
88
90
  when Rack::Response then response.headers.merge!(headers)
89
91
  when Array then response[1].merge!(headers)
@@ -22,6 +22,7 @@ module Grape
22
22
 
23
23
  def after
24
24
  return unless @app_response
25
+
25
26
  status, headers, bodies = *@app_response
26
27
 
27
28
  if Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status)
@@ -79,7 +80,7 @@ module Grape
79
80
  (request.post? || request.put? || request.patch? || request.delete?) &&
80
81
  (!request.form_data? || !request.media_type) &&
81
82
  !request.parseable_data? &&
82
- (request.content_length.to_i > 0 || request.env[Grape::Http::Headers::HTTP_TRANSFER_ENCODING] == CHUNKED)
83
+ (request.content_length.to_i.positive? || request.env[Grape::Http::Headers::HTTP_TRANSFER_ENCODING] == CHUNKED)
83
84
 
84
85
  return unless (input = env[Grape::Env::RACK_INPUT])
85
86
 
@@ -96,9 +97,7 @@ module Grape
96
97
  def read_rack_input(body)
97
98
  fmt = request.media_type ? mime_types[request.media_type] : options[:default_format]
98
99
 
99
- unless content_type_for(fmt)
100
- throw :error, status: 415, message: "The provided content-type '#{request.media_type}' is not supported."
101
- end
100
+ throw :error, status: 415, message: "The provided content-type '#{request.media_type}' is not supported." unless content_type_for(fmt)
102
101
  parser = Grape::Parser.parser_for fmt, **options
103
102
  if parser
104
103
  begin
@@ -145,6 +144,7 @@ module Grape
145
144
  fmt = Rack::Utils.parse_nested_query(env[Grape::Http::Headers::QUERY_STRING])[Grape::Http::Headers::FORMAT]
146
145
  # avoid symbol memory leak on an unknown format
147
146
  return fmt.to_sym if content_type_for(fmt)
147
+
148
148
  fmt
149
149
  end
150
150
 
@@ -45,8 +45,8 @@ module Grape
45
45
  @others = []
46
46
  end
47
47
 
48
- def each
49
- @middlewares.each { |x| yield x }
48
+ def each(&block)
49
+ @middlewares.each(&block)
50
50
  end
51
51
 
52
52
  def size
@@ -22,11 +22,9 @@ module Grape
22
22
  def before
23
23
  potential_version = (env[Grape::Http::Headers::HTTP_ACCEPT_VERSION] || '').strip
24
24
 
25
- if strict?
25
+ if strict? && potential_version.empty?
26
26
  # If no Accept-Version header:
27
- if potential_version.empty?
28
- throw :error, status: 406, headers: error_headers, message: 'Accept-Version header must be set.'
29
- end
27
+ throw :error, status: 406, headers: error_headers, message: 'Accept-Version header must be set.'
30
28
  end
31
29
 
32
30
  return if potential_version.empty?
@@ -51,7 +49,7 @@ module Grape
51
49
  # of routes (see Grape::Router) for more information). To prevent
52
50
  # this behavior, and not add the `X-Cascade` header, one can set the `:cascade` option to `false`.
53
51
  def cascade?
54
- if options[:version_options] && options[:version_options].key?(:cascade)
52
+ if options[:version_options]&.key?(:cascade)
55
53
  options[:version_options][:cascade]
56
54
  else
57
55
  true
@@ -26,10 +26,10 @@ module Grape
26
26
  # route.
27
27
  class Header < Base
28
28
  VENDOR_VERSION_HEADER_REGEX =
29
- /\Avnd\.([a-z0-9.\-_!#\$&\^]+?)(?:-([a-z0-9*.]+))?(?:\+([a-z0-9*\-.]+))?\z/.freeze
29
+ /\Avnd\.([a-z0-9.\-_!#{Regexp.last_match(0)}\^]+?)(?:-([a-z0-9*.]+))?(?:\+([a-z0-9*\-.]+))?\z/.freeze
30
30
 
31
- HAS_VENDOR_REGEX = /\Avnd\.[a-z0-9.\-_!#\$&\^]+/.freeze
32
- HAS_VERSION_REGEX = /\Avnd\.([a-z0-9.\-_!#\$&\^]+?)(?:-([a-z0-9*.]+))+/.freeze
31
+ HAS_VENDOR_REGEX = /\Avnd\.[a-z0-9.\-_!#{Regexp.last_match(0)}\^]+/.freeze
32
+ HAS_VERSION_REGEX = /\Avnd\.([a-z0-9.\-_!#{Regexp.last_match(0)}\^]+?)(?:-([a-z0-9*.]+))+/.freeze
33
33
 
34
34
  def before
35
35
  strict_header_checks if strict?
@@ -52,12 +52,14 @@ module Grape
52
52
 
53
53
  def strict_accept_header_presence_check
54
54
  return unless header.qvalues.empty?
55
+
55
56
  fail_with_invalid_accept_header!('Accept header must be set.')
56
57
  end
57
58
 
58
59
  def strict_version_vendor_accept_header_presence_check
59
60
  return unless versions.present?
60
61
  return if an_accept_header_with_version_and_vendor_is_present?
62
+
61
63
  fail_with_invalid_accept_header!('API vendor or version not found.')
62
64
  end
63
65
 
@@ -160,7 +162,7 @@ module Grape
160
162
  # information). To prevent # this behavior, and not add the `X-Cascade`
161
163
  # header, one can set the `:cascade` option to `false`.
162
164
  def cascade?
163
- if version_options && version_options.key?(:cascade)
165
+ if version_options&.key?(:cascade)
164
166
  version_options[:cascade]
165
167
  else
166
168
  true
@@ -32,6 +32,7 @@ module Grape
32
32
  def before
33
33
  potential_version = Rack::Utils.parse_nested_query(env[Grape::Http::Headers::QUERY_STRING])[paramkey]
34
34
  return if potential_version.nil?
35
+
35
36
  throw :error, status: 404, message: '404 API Version Not Found', headers: { Grape::Http::Headers::X_CASCADE => 'pass' } if options[:versions] && !options[:versions].find { |v| v.to_s == potential_version }
36
37
  env[Grape::Env::API_VERSION] = potential_version
37
38
  env[Grape::Env::RACK_REQUEST_QUERY_HASH].delete(paramkey) if env.key? Grape::Env::RACK_REQUEST_QUERY_HASH
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'English'
3
4
  module Rack
4
5
  module Accept
5
6
  module Header
6
- ALLOWED_CHARACTERS = %r{^([a-z*]+)\/([a-z0-9*\&\^\-_#\$!.+]+)(?:;([a-z0-9=;]+))?$}.freeze
7
+ ALLOWED_CHARACTERS = %r{^([a-z*]+)/([a-z0-9*&\^\-_#{$ERROR_INFO}.+]+)(?:;([a-z0-9=;]+))?$}.freeze
7
8
  class << self
8
9
  # Corrected version of https://github.com/mjackson/rack-accept/blob/master/lib/rack/accept/header.rb#L40-L44
9
10
  def parse_media_type(media_type)
@@ -37,6 +37,7 @@ module Grape
37
37
  pieces = path.split('/')
38
38
  potential_version = pieces[1]
39
39
  return unless potential_version&.match?(options[:pattern])
40
+
40
41
  throw :error, status: 404, message: '404 API Version Not Found' if options[:versions] && !options[:versions].find { |v| v.to_s == potential_version }
41
42
  env[Grape::Env::API_VERSION] = potential_version
42
43
  end
@@ -45,6 +46,7 @@ module Grape
45
46
 
46
47
  def mounted_path?(path)
47
48
  return false unless mount_path && path.start_with?(mount_path)
49
+
48
50
  rest = path.slice(mount_path.length..-1)
49
51
  rest.start_with?('/') || rest.empty?
50
52
  end
data/lib/grape/path.rb CHANGED
@@ -91,6 +91,7 @@ module Grape
91
91
 
92
92
  def split_setting(key)
93
93
  return if settings[key].nil?
94
+
94
95
  settings[key].to_s.split('/')
95
96
  end
96
97
  end
data/lib/grape/request.rb CHANGED
@@ -37,6 +37,7 @@ module Grape
37
37
  Grape::Util::LazyObject.new do
38
38
  env.each_pair.with_object({}) do |(k, v), headers|
39
39
  next unless k.to_s.start_with? HTTP_PREFIX
40
+
40
41
  transformed_header = Grape::Http::Headers::HTTP_HEADERS[k] || transform_header(k)
41
42
  headers[transformed_header] = v
42
43
  end
@@ -41,7 +41,7 @@ module Grape
41
41
  end
42
42
 
43
43
  pattern = -pattern.split('/').tap do |parts|
44
- parts[parts.length - 1] = '?' + parts.last
44
+ parts[parts.length - 1] = "?#{parts.last}"
45
45
  end.join('/') if pattern.end_with?('*path')
46
46
 
47
47
  PatternCache[[pattern, suffix]]
@@ -84,8 +84,8 @@ module Grape
84
84
  path, line = *location.scan(SOURCE_LOCATION_REGEXP).first
85
85
  path = File.realpath(path) if Pathname.new(path).relative?
86
86
  expected ||= name
87
- warn <<-WARNING
88
- #{path}:#{line}: The route_xxx methods such as route_#{name} have been deprecated, please use #{expected}.
87
+ warn <<~WARNING
88
+ #{path}:#{line}: The route_xxx methods such as route_#{name} have been deprecated, please use #{expected}.
89
89
  WARNING
90
90
  end
91
91
  end
data/lib/grape/router.rb CHANGED
@@ -28,6 +28,7 @@ module Grape
28
28
 
29
29
  def compile!
30
30
  return if compiled
31
+
31
32
  @union = Regexp.union(@neutral_regexes)
32
33
  @neutral_regexes = nil
33
34
  self.class.supported_methods.each do |method|
@@ -60,6 +61,7 @@ module Grape
60
61
  def recognize_path(input)
61
62
  any = with_optimization { greedy_match?(input) }
62
63
  return if any == default_response
64
+
63
65
  any.endpoint
64
66
  end
65
67
 
@@ -80,6 +82,7 @@ module Grape
80
82
  map[method].each do |route|
81
83
  next if exact_route == route
82
84
  next unless route.match?(input)
85
+
83
86
  response = process_route(route, env)
84
87
  break unless cascade?(response)
85
88
  end
@@ -91,6 +94,7 @@ module Grape
91
94
  response = yield(input, method)
92
95
 
93
96
  return response if response && !(cascade = cascade?(response))
97
+
94
98
  last_neighbor_route = greedy_match?(input)
95
99
 
96
100
  # If last_neighbor_route exists and request method is OPTIONS,
@@ -139,12 +143,14 @@ module Grape
139
143
  def match?(input, method)
140
144
  current_regexp = @optimized_map[method]
141
145
  return unless current_regexp.match(input)
146
+
142
147
  last_match = Regexp.last_match
143
148
  @map[method].detect { |route| last_match["_#{route.index}"] }
144
149
  end
145
150
 
146
151
  def greedy_match?(input)
147
152
  return unless @union.match(input)
153
+
148
154
  last_match = Regexp.last_match
149
155
  @neutral_map.detect { |route| last_match["_#{route.index}"] }
150
156
  end
@@ -5,9 +5,7 @@ module Grape
5
5
  # A branchable, inheritable settings object which can store both stackable
6
6
  # and inheritable values (see InheritableValues and StackableValues).
7
7
  class InheritableSetting
8
- attr_accessor :route, :api_class, :namespace
9
- attr_accessor :namespace_inheritable, :namespace_stackable, :namespace_reverse_stackable
10
- attr_accessor :parent, :point_in_time_copies
8
+ attr_accessor :route, :api_class, :namespace, :namespace_inheritable, :namespace_stackable, :namespace_reverse_stackable, :parent, :point_in_time_copies
11
9
 
12
10
  # Retrieve global settings.
13
11
  def self.global
@@ -49,9 +49,10 @@ module Grape
49
49
  end
50
50
 
51
51
  def []=(key, value)
52
- @value_hash[key] = if value.is_a?(Hash)
52
+ @value_hash[key] = case value
53
+ when Hash
53
54
  LazyValueHash.new(value)
54
- elsif value.is_a?(Array)
55
+ when Array
55
56
  LazyValueArray.new(value)
56
57
  else
57
58
  LazyValue.new(value)