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
@@ -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)