grape 1.7.1 → 1.8.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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -1
  3. data/CONTRIBUTING.md +1 -1
  4. data/README.md +12 -4
  5. data/grape.gemspec +2 -2
  6. data/lib/grape/api.rb +2 -2
  7. data/lib/grape/content_types.rb +2 -8
  8. data/lib/grape/dsl/desc.rb +1 -1
  9. data/lib/grape/dsl/inside_route.rb +5 -5
  10. data/lib/grape/dsl/request_response.rb +2 -1
  11. data/lib/grape/dsl/settings.rb +2 -6
  12. data/lib/grape/endpoint.rb +19 -17
  13. data/lib/grape/error_formatter/base.rb +1 -1
  14. data/lib/grape/exceptions/base.rb +2 -2
  15. data/lib/grape/exceptions/missing_group_type.rb +1 -6
  16. data/lib/grape/exceptions/unsupported_group_type.rb +1 -6
  17. data/lib/grape/exceptions/validation_errors.rb +1 -6
  18. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +3 -3
  19. data/lib/grape/extensions/hash.rb +4 -7
  20. data/lib/grape/extensions/hashie/mash.rb +3 -3
  21. data/lib/grape/formatter/serializable_hash.rb +7 -7
  22. data/lib/grape/middleware/auth/base.rb +1 -1
  23. data/lib/grape/middleware/error.rb +1 -1
  24. data/lib/grape/middleware/formatter.rb +1 -1
  25. data/lib/grape/middleware/versioner/header.rb +11 -19
  26. data/lib/grape/router/route.rb +1 -3
  27. data/lib/grape/util/lazy_value.rb +3 -11
  28. data/lib/grape/util/strict_hash_configuration.rb +3 -4
  29. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  30. data/lib/grape/validations/params_scope.rb +8 -2
  31. data/lib/grape/validations/single_attribute_iterator.rb +3 -1
  32. data/lib/grape/validations/types/custom_type_coercer.rb +2 -16
  33. data/lib/grape/validations/validators/base.rb +9 -20
  34. data/lib/grape/validations/validators/default_validator.rb +2 -20
  35. data/lib/grape/validations/validators/multiple_params_base.rb +4 -8
  36. data/lib/grape/validations/validators/values_validator.rb +14 -5
  37. data/lib/grape/version.rb +1 -1
  38. data/lib/grape.rb +11 -3
  39. data/spec/grape/api/custom_validations_spec.rb +14 -57
  40. data/spec/grape/api_remount_spec.rb +36 -0
  41. data/spec/grape/api_spec.rb +10 -1
  42. data/spec/grape/dsl/desc_spec.rb +84 -87
  43. data/spec/grape/dsl/inside_route_spec.rb +6 -10
  44. data/spec/grape/dsl/request_response_spec.rb +21 -2
  45. data/spec/grape/endpoint_spec.rb +8 -8
  46. data/spec/grape/exceptions/body_parse_errors_spec.rb +40 -0
  47. data/spec/grape/exceptions/missing_group_type_spec.rb +5 -9
  48. data/spec/grape/exceptions/unsupported_group_type_spec.rb +5 -9
  49. data/spec/grape/grape_spec.rb +9 -0
  50. data/spec/grape/middleware/formatter_spec.rb +1 -1
  51. data/spec/grape/request_spec.rb +4 -14
  52. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +6 -8
  53. data/spec/grape/validations/single_attribute_iterator_spec.rb +8 -9
  54. data/spec/grape/validations/validators/base_spec.rb +38 -0
  55. data/spec/grape/validations/validators/values_spec.rb +37 -0
  56. data/spec/grape/validations_spec.rb +7 -6
  57. data/spec/shared/deprecated_class_examples.rb +16 -0
  58. metadata +17 -22
  59. data/lib/grape/config.rb +0 -34
  60. data/lib/grape/extensions/deep_mergeable_hash.rb +0 -21
  61. data/lib/grape/extensions/deep_symbolize_hash.rb +0 -32
  62. data/spec/grape/config_spec.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40277732454d8810e4e96f638da9e6bd4ab818e39ac9c30788791cb4bd429871
4
- data.tar.gz: b075dd96ba3dda6fcd05e6b1c126255b5e206b2d6bb9bf9b52f9cd6ec25a6efc
3
+ metadata.gz: ac7bd232782ed265b59ec7f4ea0dec03a0896b328694ebe1507cf9680e1bee41
4
+ data.tar.gz: b81cb45c2b6daab5b413af0df615a542907c9fbf1732e3fc46347321dedc4f65
5
5
  SHA512:
6
- metadata.gz: 61d1ef36c90927e08119b6abf57b87fc5317b7b4ac73587d14bc23c9b671e0e76930b89b22d15ec806861f2c60c582647a4f95bc6a1100dca07066be1853d4e6
7
- data.tar.gz: 42a4595d466b2092759dee55ad467a6733e29912b0faaf3abe203c18ab1c84b53b6a1d45868102ac16e6b431254664a6762b3ec0b8e52217c777f99adcf965cc
6
+ metadata.gz: 1929a95447ec3923443e908a8240195e7e4a0f5a3113f8679e947cc3813e800f45f35c928dfef9495ff277a983bf3bdcb4ca358ab889e28224d890a3d078d7de
7
+ data.tar.gz: 4d5141c1f331ee07eaa78bd89e1b76f99b6cbcb7d6f0dda3f12f9e6b900c977c9a0757c0d912a6cd53ea5ef9bce8409a211c4a77c4b78a0f5e607ecd1e055480
data/CHANGELOG.md CHANGED
@@ -1,4 +1,25 @@
1
- ### 1.7.1 (2023/05/14)
1
+ ### 1.8.0 (2023/08/30)
2
+
3
+ #### Features
4
+
5
+ * [#2326](https://github.com/ruby-grape/grape/pull/2326): Use ActiveSupport extensions - [@ericproulx](https://github.com/ericproulx).
6
+ * [#2327](https://github.com/ruby-grape/grape/pull/2327): Use ActiveSupport deprecation - [@ericproulx](https://github.com/ericproulx).
7
+ * [#2330](https://github.com/ruby-grape/grape/pull/2330): Use ActiveSupport inflector - [@ericproulx](https://github.com/ericproulx).
8
+ * [#2331](https://github.com/ruby-grape/grape/pull/2331): Memory optimization when running validators - [@ericproulx](https://github.com/ericproulx).
9
+ * [#2332](https://github.com/ruby-grape/grape/pull/2332): Use ActiveSupport configurable - [@ericproulx](https://github.com/ericproulx).
10
+ * [#2333](https://github.com/ruby-grape/grape/pull/2333): Use custom messages in parameter validation with arity 1 - [@thedevjoao](https://github.com/TheDevJoao).
11
+ * [#2341](https://github.com/ruby-grape/grape/pull/2341): Stop yielding skip value - [@ericproulx](https://github.com/ericproulx).
12
+ * [#2342](https://github.com/ruby-grape/grape/pull/2342): Allow specifying a handler for grape_exceptions - [@mscrivo](https://github.com/mscrivo).
13
+ * [#2338](https://github.com/ruby-grape/grape/pull/2338): Fix unknown validator when using requires/optional with entity - [@mscrivo](https://github.com/mscrivo).
14
+
15
+ #### Fixes
16
+
17
+ * [#2339](https://github.com/ruby-grape/grape/pull/2339): Documentation and specs for remountable configuration in params - [@myxoh](https://github.com/myxoh).
18
+ * [#2328](https://github.com/ruby-grape/grape/pull/2328): Don't cache Class.instance_methods - [@byroot](https://github.com/byroot).
19
+ * [#2337](https://github.com/ruby-grape/grape/pull/2337): Fix: allow custom validators that do not end with _validator - [@ericproulx](https://github.com/ericproulx).
20
+ * [#2346](https://github.com/ruby-grape/grape/pull/2346): Adjust test expectations to conform to rack 3 - [@kbarrette](https://github.com/kbarrette).
21
+
22
+ ## 1.7.1 (2023/05/14)
2
23
 
3
24
  #### Features
4
25
 
data/CONTRIBUTING.md CHANGED
@@ -145,7 +145,7 @@ git push origin my-feature-branch -f
145
145
 
146
146
  #### Check on Your Pull Request
147
147
 
148
- Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above.
148
+ Go back to your pull request after a few minutes and see whether it passed muster with CI. Everything should look green, otherwise fix issues and amend your commit as described above.
149
149
 
150
150
  #### Be Patient
151
151
 
data/README.md CHANGED
@@ -159,7 +159,7 @@ content negotiation, versioning and much more.
159
159
 
160
160
  ## Stable Release
161
161
 
162
- You're reading the documentation for the stable release of Grape, 1.7.1.
162
+ You're reading the documentation for the stable release of Grape, **1.8.0**.
163
163
  Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
164
164
 
165
165
  ## Project Resources
@@ -524,15 +524,15 @@ end
524
524
  ```ruby
525
525
  class BasicAPI < Grape::API
526
526
  desc 'Statuses index' do
527
- params: mounted { configuration[:entity] || API::Entities::Status }.documentation
527
+ params: (configuration[:entity] || API::Entities::Status).documentation
528
528
  end
529
529
  params do
530
- requires :all, using: mounted { configuration[:entity] || API::Entities::Status }.documentation
530
+ requires :all, using: (configuration[:entity] || API::Entities::Status).documentation
531
531
  end
532
532
  get '/statuses' do
533
533
  statuses = Status.all
534
534
  type = current_user.admin? ? :full : :default
535
- present statuses, with: mounted { configuration[:entity] || API::Entities::Status }, type: type
535
+ present statuses, with: (configuration[:entity] || API::Entities::Status), type: type
536
536
  end
537
537
  end
538
538
 
@@ -2624,6 +2624,14 @@ class Twitter::API < Grape::API
2624
2624
  end
2625
2625
  ```
2626
2626
 
2627
+ If you want to customize the shape of grape exceptions returned to the user, to match your `:all` handler for example, you can pass a block to `rescue_from :grape_exceptions`.
2628
+
2629
+ ```ruby
2630
+ rescue_from :grape_exceptions do |e|
2631
+ error!(e, e.status)
2632
+ end
2633
+ ```
2634
+
2627
2635
  You can also rescue specific exceptions.
2628
2636
 
2629
2637
  ```ruby
data/grape.gemspec CHANGED
@@ -20,11 +20,11 @@ Gem::Specification.new do |s|
20
20
  'source_code_uri' => "https://github.com/ruby-grape/grape/tree/v#{s.version}"
21
21
  }
22
22
 
23
- s.add_runtime_dependency 'activesupport'
23
+ s.add_runtime_dependency 'activesupport', '>= 5'
24
24
  s.add_runtime_dependency 'builder'
25
25
  s.add_runtime_dependency 'dry-types', '>= 1.1'
26
26
  s.add_runtime_dependency 'mustermann-grape', '~> 1.0.0'
27
- s.add_runtime_dependency 'rack', '>= 1.3.0', '< 3'
27
+ s.add_runtime_dependency 'rack', '>= 1.3.0'
28
28
  s.add_runtime_dependency 'rack-accept'
29
29
 
30
30
  s.files = %w[CHANGELOG.md CONTRIBUTING.md README.md grape.png UPGRADING.md LICENSE]
data/lib/grape/api.rb CHANGED
@@ -8,7 +8,7 @@ module Grape
8
8
  # should subclass this class in order to build an API.
9
9
  class API
10
10
  # Class methods that we want to call on the API rather than on the API object
11
- NON_OVERRIDABLE = (Class.new.methods + %i[call call! configuration compile! inherited]).freeze
11
+ NON_OVERRIDABLE = %i[call call! configuration compile! inherited].freeze
12
12
 
13
13
  class Boolean
14
14
  def self.build(val)
@@ -50,7 +50,7 @@ module Grape
50
50
 
51
51
  # Redefines all methods so that are forwarded to add_setup and be recorded
52
52
  def override_all_methods!
53
- (base_instance.methods - NON_OVERRIDABLE).each do |method_override|
53
+ (base_instance.methods - Class.methods - NON_OVERRIDABLE).each do |method_override|
54
54
  define_singleton_method(method_override) do |*args, &block|
55
55
  add_setup(method_override, *args, &block)
56
56
  end
@@ -17,17 +17,11 @@ module Grape
17
17
 
18
18
  class << self
19
19
  def content_types_for_settings(settings)
20
- return if settings.blank?
21
-
22
- settings.each_with_object({}) { |value, result| result.merge!(value) }
20
+ settings&.inject(:merge!)
23
21
  end
24
22
 
25
23
  def content_types_for(from_settings)
26
- if from_settings.present?
27
- from_settings
28
- else
29
- Grape::ContentTypes::CONTENT_TYPES.merge(default_elements)
30
- end
24
+ from_settings.presence || Grape::ContentTypes::CONTENT_TYPES.merge(default_elements)
31
25
  end
32
26
  end
33
27
  end
@@ -68,7 +68,7 @@ module Grape
68
68
  end
69
69
 
70
70
  config_class.configure(&config_block)
71
- warn '[DEPRECATION] Passing a options hash and a block to `desc` is deprecated. Move all hash options to block.' unless options.empty?
71
+ ActiveSupport::Deprecation.warn('Passing a options hash and a block to `desc` is deprecated. Move all hash options to block.') if options.any?
72
72
  options = config_class.settings
73
73
  else
74
74
  options = options.merge(description: description)
@@ -103,7 +103,7 @@ module Grape
103
103
 
104
104
  if type == 'Hash' && !has_children
105
105
  {}
106
- elsif type == 'Array' || (type&.start_with?('[') && !type&.include?(','))
106
+ elsif type == 'Array' || (type&.start_with?('[') && type&.exclude?(','))
107
107
  []
108
108
  elsif type == 'Set' || type&.start_with?('#<Set')
109
109
  Set.new
@@ -280,13 +280,13 @@ module Grape
280
280
  # Deprecated method to send files to the client. Use `sendfile` or `stream`
281
281
  def file(value = nil)
282
282
  if value.is_a?(String)
283
- warn '[DEPRECATION] Use sendfile or stream to send files.'
283
+ ActiveSupport::Deprecation.warn('Use sendfile or stream to send files.')
284
284
  sendfile(value)
285
285
  elsif !value.is_a?(NilClass)
286
- warn '[DEPRECATION] Use stream to use a Stream object.'
286
+ ActiveSupport::Deprecation.warn('Use stream to use a Stream object.')
287
287
  stream(value)
288
288
  else
289
- warn '[DEPRECATION] Use sendfile or stream to send files.'
289
+ ActiveSupport::Deprecation.warn('Use sendfile or stream to send files.')
290
290
  sendfile
291
291
  end
292
292
  end
@@ -433,7 +433,7 @@ module Grape
433
433
  # the given entity_class.
434
434
  def entity_representation_for(entity_class, object, options)
435
435
  embeds = { env: env }
436
- embeds[:version] = env[Grape::Env::API_VERSION] if env[Grape::Env::API_VERSION]
436
+ embeds[:version] = env[Grape::Env::API_VERSION] if env.key?(Grape::Env::API_VERSION)
437
437
  entity_class.represent(object, **embeds.merge(options))
438
438
  end
439
439
  end
@@ -112,10 +112,11 @@ module Grape
112
112
 
113
113
  if args.include?(:all)
114
114
  namespace_inheritable(:rescue_all, true)
115
- namespace_inheritable :all_rescue_handler, handler
115
+ namespace_inheritable(:all_rescue_handler, handler)
116
116
  elsif args.include?(:grape_exceptions)
117
117
  namespace_inheritable(:rescue_all, true)
118
118
  namespace_inheritable(:rescue_grape_exceptions, true)
119
+ namespace_inheritable(:grape_exceptions_rescue_handler, handler)
119
120
  else
120
121
  handler_type =
121
122
  case options[:rescue_subclasses]
@@ -109,13 +109,9 @@ module Grape
109
109
  settings = get_or_set :namespace_reverse_stackable, key, nil
110
110
  return if settings.blank?
111
111
 
112
- result = {}
113
- settings.each do |setting|
114
- setting.each do |field, value|
115
- result[field] ||= value
116
- end
112
+ settings.each_with_object({}) do |setting, result|
113
+ result.merge!(setting) { |_k, s1, _s2| s1 }
117
114
  end
118
- result
119
115
  end
120
116
 
121
117
  # (see #unset_global_setting)
@@ -171,10 +171,9 @@ module Grape
171
171
  end
172
172
 
173
173
  def prepare_routes_requirements
174
- endpoint_requirements = options[:route_options][:requirements] || {}
175
- all_requirements = (namespace_stackable(:namespace).map(&:requirements) << endpoint_requirements)
176
- all_requirements.reduce({}) do |base_requirements, single_requirements|
177
- base_requirements.merge!(single_requirements)
174
+ {}.merge!(*namespace_stackable(:namespace).map(&:requirements)).tap do |requirements|
175
+ endpoint_requirements = options.dig(:route_options, :requirements)
176
+ requirements.merge!(endpoint_requirements) if endpoint_requirements
178
177
  end
179
178
  end
180
179
 
@@ -293,7 +292,8 @@ module Grape
293
292
  rescue_options: namespace_stackable_with_hash(:rescue_options) || {},
294
293
  rescue_handlers: namespace_reverse_stackable_with_hash(:rescue_handlers) || {},
295
294
  base_only_rescue_handlers: namespace_stackable_with_hash(:base_only_rescue_handlers) || {},
296
- all_rescue_handler: namespace_inheritable(:all_rescue_handler)
295
+ all_rescue_handler: namespace_inheritable(:all_rescue_handler),
296
+ grape_exceptions_rescue_handler: namespace_inheritable(:grape_exceptions_rescue_handler)
297
297
 
298
298
  stack.concat namespace_stackable(:middleware)
299
299
 
@@ -318,8 +318,8 @@ module Grape
318
318
  end
319
319
 
320
320
  def build_helpers
321
- helpers = namespace_stackable(:helpers) || []
322
- Module.new { helpers.each { |mod_to_include| include mod_to_include } }
321
+ helpers = namespace_stackable(:helpers)
322
+ Module.new { helpers&.each { |mod_to_include| include mod_to_include } }
323
323
  end
324
324
 
325
325
  private :build_stack, :build_helpers
@@ -345,11 +345,9 @@ module Grape
345
345
  end
346
346
  end
347
347
 
348
- def run_validators(validator_factories, request)
348
+ def run_validators(validators, request)
349
349
  validation_errors = []
350
350
 
351
- validators = validator_factories.map { |options| Grape::Validations::ValidatorFactory.create_validator(**options) }
352
-
353
351
  ActiveSupport::Notifications.instrument('endpoint_run_validators.grape', endpoint: self, validators: validators, request: request) do
354
352
  validators.each do |validator|
355
353
  validator.validate(request)
@@ -367,34 +365,38 @@ module Grape
367
365
 
368
366
  def run_filters(filters, type = :other)
369
367
  ActiveSupport::Notifications.instrument('endpoint_run_filters.grape', endpoint: self, filters: filters, type: type) do
370
- (filters || []).each { |filter| instance_eval(&filter) }
368
+ filters&.each { |filter| instance_eval(&filter) }
371
369
  end
372
370
  post_extension = DSL::InsideRoute.post_filter_methods(type)
373
371
  extend post_extension if post_extension
374
372
  end
375
373
 
376
374
  def befores
377
- namespace_stackable(:befores) || []
375
+ namespace_stackable(:befores)
378
376
  end
379
377
 
380
378
  def before_validations
381
- namespace_stackable(:before_validations) || []
379
+ namespace_stackable(:before_validations)
382
380
  end
383
381
 
384
382
  def after_validations
385
- namespace_stackable(:after_validations) || []
383
+ namespace_stackable(:after_validations)
386
384
  end
387
385
 
388
386
  def afters
389
- namespace_stackable(:afters) || []
387
+ namespace_stackable(:afters)
390
388
  end
391
389
 
392
390
  def finallies
393
- namespace_stackable(:finallies) || []
391
+ namespace_stackable(:finallies)
394
392
  end
395
393
 
396
394
  def validations
397
- route_setting(:saved_validations) || []
395
+ return enum_for(:validations) unless block_given?
396
+
397
+ route_setting(:saved_validations)&.each do |saved_validation|
398
+ yield Grape::Validations::ValidatorFactory.create_validator(**saved_validation)
399
+ end
398
400
  end
399
401
 
400
402
  def options?
@@ -27,7 +27,7 @@ module Grape
27
27
 
28
28
  if presenter
29
29
  embeds = { env: env }
30
- embeds[:version] = env[Grape::Env::API_VERSION] if env[Grape::Env::API_VERSION]
30
+ embeds[:version] = env[Grape::Env::API_VERSION] if env.key?(Grape::Env::API_VERSION)
31
31
  presented_message = presenter.represent(presented_message, embeds).serializable_hash
32
32
  end
33
33
 
@@ -73,11 +73,11 @@ module Grape
73
73
  options = options.dup
74
74
  options[:default] &&= options[:default].to_s
75
75
  message = ::I18n.translate(key, **options)
76
- message.present? ? message : fallback_message(key, **options)
76
+ message.presence || fallback_message(key, **options)
77
77
  end
78
78
 
79
79
  def fallback_message(key, **options)
80
- if ::I18n.enforce_available_locales && !::I18n.available_locales.include?(FALLBACK_LOCALE)
80
+ if ::I18n.enforce_available_locales && ::I18n.available_locales.exclude?(FALLBACK_LOCALE)
81
81
  key
82
82
  else
83
83
  ::I18n.translate(key, locale: FALLBACK_LOCALE, **options)
@@ -10,9 +10,4 @@ module Grape
10
10
  end
11
11
  end
12
12
 
13
- Grape::Exceptions::MissingGroupTypeError = Class.new(Grape::Exceptions::MissingGroupType) do
14
- def initialize(*)
15
- super
16
- warn '[DEPRECATION] `Grape::Exceptions::MissingGroupTypeError` is deprecated. Use `Grape::Exceptions::MissingGroupType` instead.'
17
- end
18
- end
13
+ Grape::Exceptions::MissingGroupTypeError = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Grape::Exceptions::MissingGroupTypeError', 'Grape::Exceptions::MissingGroupType')
@@ -10,9 +10,4 @@ module Grape
10
10
  end
11
11
  end
12
12
 
13
- Grape::Exceptions::UnsupportedGroupTypeError = Class.new(Grape::Exceptions::UnsupportedGroupType) do
14
- def initialize(*)
15
- super
16
- warn '[DEPRECATION] `Grape::Exceptions::UnsupportedGroupTypeError` is deprecated. Use `Grape::Exceptions::UnsupportedGroupType` instead.'
17
- end
18
- end
13
+ Grape::Exceptions::UnsupportedGroupTypeError = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Grape::Exceptions::UnsupportedGroupTypeError', 'Grape::Exceptions::UnsupportedGroupType')
@@ -13,12 +13,7 @@ module Grape
13
13
  attr_reader :errors
14
14
 
15
15
  def initialize(errors: [], headers: {}, **_options)
16
- @errors = {}
17
- errors.each do |validation_error|
18
- @errors[validation_error.params] ||= []
19
- @errors[validation_error.params] << validation_error
20
- end
21
-
16
+ @errors = errors.group_by(&:params)
22
17
  super message: full_messages.join(', '), status: 400, headers: headers
23
18
  end
24
19
 
@@ -16,9 +16,9 @@ module Grape
16
16
  end
17
17
 
18
18
  def build_params
19
- params = ::ActiveSupport::HashWithIndifferentAccess.new(rack_params)
20
- params.deep_merge!(grape_routing_args) if env[Grape::Env::GRAPE_ROUTING_ARGS]
21
- params
19
+ ::ActiveSupport::HashWithIndifferentAccess.new(rack_params).tap do |params|
20
+ params.deep_merge!(grape_routing_args) if env.key?(Grape::Env::GRAPE_ROUTING_ARGS)
21
+ end
22
22
  end
23
23
  end
24
24
  end
@@ -11,13 +11,10 @@ module Grape
11
11
  end
12
12
 
13
13
  def build_params
14
- params = Grape::Extensions::DeepMergeableHash[rack_params]
15
- params.deep_merge!(grape_routing_args) if env[Grape::Env::GRAPE_ROUTING_ARGS]
16
- post_process_params(params)
17
- end
18
-
19
- def post_process_params(params)
20
- Grape::Extensions::DeepSymbolizeHash.deep_symbolize_keys_in(params)
14
+ rack_params.deep_dup.tap do |params|
15
+ params.deep_merge!(grape_routing_args) if env.key?(Grape::Env::GRAPE_ROUTING_ARGS)
16
+ params.deep_symbolize_keys!
17
+ end
21
18
  end
22
19
  end
23
20
  end
@@ -15,9 +15,9 @@ module Grape
15
15
  end
16
16
 
17
17
  def build_params
18
- params = ::Hashie::Mash.new(rack_params)
19
- params.deep_merge!(grape_routing_args) if env[Grape::Env::GRAPE_ROUTING_ARGS]
20
- params
18
+ ::Hashie::Mash.new(rack_params).tap do |params|
19
+ params.deep_merge!(grape_routing_args) if env.key?(Grape::Env::GRAPE_ROUTING_ARGS)
20
+ end
21
21
  end
22
22
  end
23
23
  end
@@ -15,24 +15,24 @@ module Grape
15
15
  private
16
16
 
17
17
  def serializable?(object)
18
- 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) || array_serializable?(object) || object.is_a?(Hash)
19
19
  end
20
20
 
21
21
  def serialize(object)
22
22
  if object.respond_to? :serializable_hash
23
23
  object.serializable_hash
24
- elsif object.is_a?(Array) && object.all? { |o| o.respond_to? :serializable_hash }
24
+ elsif array_serializable?(object)
25
25
  object.map(&:serializable_hash)
26
26
  elsif object.is_a?(Hash)
27
- h = {}
28
- object.each_pair do |k, v|
29
- h[k] = serialize(v)
30
- end
31
- h
27
+ object.transform_values { |v| serialize(v) }
32
28
  else
33
29
  object
34
30
  end
35
31
  end
32
+
33
+ def array_serializable?(object)
34
+ object.is_a?(Array) && object.all? { |o| o.respond_to? :serializable_hash }
35
+ end
36
36
  end
37
37
  end
38
38
  end
@@ -28,7 +28,7 @@ module Grape
28
28
 
29
29
  strategy_info = Grape::Middleware::Auth::Strategies[options[:type]]
30
30
 
31
- throw(:error, status: 401, message: 'API Authorization Failed.') unless strategy_info.present?
31
+ throw(:error, status: 401, message: 'API Authorization Failed.') if strategy_info.blank?
32
32
 
33
33
  strategy = strategy_info.create(@app, options) do |*args|
34
34
  auth_proc_context.instance_exec(*args, &auth_proc)
@@ -109,7 +109,7 @@ module Grape
109
109
  return :error_response if klass == Grape::Exceptions::InvalidVersionHeader
110
110
  return unless options[:rescue_grape_exceptions] || !options[:rescue_all]
111
111
 
112
- :error_response
112
+ options[:grape_exceptions_rescue_handler] || :error_response
113
113
  end
114
114
 
115
115
  def rescue_handler_for_any_class(klass)
@@ -103,7 +103,7 @@ module Grape
103
103
  begin
104
104
  body = (env[Grape::Env::API_REQUEST_BODY] = parser.call(body, env))
105
105
  if body.is_a?(Hash)
106
- env[Grape::Env::RACK_REQUEST_FORM_HASH] = if env[Grape::Env::RACK_REQUEST_FORM_HASH]
106
+ env[Grape::Env::RACK_REQUEST_FORM_HASH] = if env.key?(Grape::Env::RACK_REQUEST_FORM_HASH)
107
107
  env[Grape::Env::RACK_REQUEST_FORM_HASH].merge(body)
108
108
  else
109
109
  body
@@ -57,8 +57,7 @@ module Grape
57
57
  end
58
58
 
59
59
  def strict_version_vendor_accept_header_presence_check
60
- return unless versions.present?
61
- return if an_accept_header_with_version_and_vendor_is_present?
60
+ return if versions.blank? || an_accept_header_with_version_and_vendor_is_present?
62
61
 
63
62
  fail_with_invalid_accept_header!('API vendor or version not found.')
64
63
  end
@@ -101,25 +100,18 @@ module Grape
101
100
  end
102
101
 
103
102
  def available_media_types
104
- available_media_types = []
105
-
106
- content_types.each_key do |extension|
107
- versions.reverse_each do |version|
108
- available_media_types += [
109
- "application/vnd.#{vendor}-#{version}+#{extension}",
110
- "application/vnd.#{vendor}-#{version}"
111
- ]
103
+ [].tap do |available_media_types|
104
+ content_types.each_key do |extension|
105
+ versions.reverse_each do |version|
106
+ available_media_types << "application/vnd.#{vendor}-#{version}+#{extension}"
107
+ available_media_types << "application/vnd.#{vendor}-#{version}"
108
+ end
109
+ available_media_types << "application/vnd.#{vendor}+#{extension}"
112
110
  end
113
- available_media_types << "application/vnd.#{vendor}+#{extension}"
114
- end
115
-
116
- available_media_types << "application/vnd.#{vendor}"
117
111
 
118
- content_types.each_value do |media_type|
119
- available_media_types << media_type
112
+ available_media_types << "application/vnd.#{vendor}"
113
+ available_media_types.concat(content_types.values.flatten)
120
114
  end
121
-
122
- available_media_types.flatten
123
115
  end
124
116
 
125
117
  def headers_contain_wrong_vendor?
@@ -130,7 +122,7 @@ module Grape
130
122
 
131
123
  def headers_contain_wrong_version?
132
124
  header.values.all? do |header_value|
133
- version?(header_value) && !versions.include?(request_version(header_value))
125
+ version?(header_value) && versions.exclude?(request_version(header_value))
134
126
  end
135
127
  end
136
128
 
@@ -84,9 +84,7 @@ 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}.
89
- WARNING
87
+ ActiveSupport::Deprecation.warn("#{path}:#{line}: The route_xxx methods such as route_#{name} have been deprecated, please use #{expected}.")
90
88
  end
91
89
  end
92
90
  end
@@ -70,29 +70,21 @@ module Grape
70
70
  end
71
71
 
72
72
  def evaluate
73
- evaluated = []
74
- @value_hash.each_with_index do |value, index|
75
- evaluated[index] = value.evaluate
76
- end
77
- evaluated
73
+ @value_hash.map(&:evaluate)
78
74
  end
79
75
  end
80
76
 
81
77
  class LazyValueHash < LazyValueEnumerable
82
78
  def initialize(hash)
83
79
  super
84
- @value_hash = {}.with_indifferent_access
80
+ @value_hash = ActiveSupport::HashWithIndifferentAccess.new
85
81
  hash.each do |key, value|
86
82
  self[key] = value
87
83
  end
88
84
  end
89
85
 
90
86
  def evaluate
91
- evaluated = {}.with_indifferent_access
92
- @value_hash.each do |key, value|
93
- evaluated[key] = value.evaluate
94
- end
95
- evaluated
87
+ @value_hash.transform_values(&:evaluate)
96
88
  end
97
89
  end
98
90
  end
@@ -66,11 +66,10 @@ module Grape
66
66
  end
67
67
 
68
68
  define_method :to_hash do
69
- merge_hash = {}
70
- setting_name.each_key { |k| merge_hash[k] = send("#{k}_context").to_hash }
71
-
72
69
  @settings.to_hash.merge(
73
- merge_hash
70
+ setting_name.each_key.with_object({}) do |k, merge_hash|
71
+ merge_hash[k] = send("#{k}_context").to_hash
72
+ end
74
73
  )
75
74
  end
76
75
  end
@@ -6,7 +6,7 @@ module Grape
6
6
  private
7
7
 
8
8
  def yield_attributes(resource_params, _attrs)
9
- yield resource_params, skip?(resource_params)
9
+ yield resource_params unless skip?(resource_params)
10
10
  end
11
11
  end
12
12
  end