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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bda9361933fff7f38c7b6e6f5196d1b245336179a527addf3bfd3aa67c6ec544
4
- data.tar.gz: 71a93ff4542fe59fb985ab0cfba591267b9901171e293988020df381d5377504
3
+ metadata.gz: 7af0abe5fd1cb203ceda93732e74ded372552f7a859c6a3c6b847d1ac31c9c97
4
+ data.tar.gz: 103a38ad4d41eccbfef3240cd8b04fe17f2bc080a4265e4353b43076ce03fb15
5
5
  SHA512:
6
- metadata.gz: c54f78461188735df911a7463b3b4a15f0257d071ac8ca43b5e8539d7bce1098a4383b85b480eced6d3e60cef204e4d7405edf17b3ccdb13d30e3fefb9011ba1
7
- data.tar.gz: e4051ac3c062e2972fb40f22cd95a6d902416b53422450dccef62e94ff20b2f447b86b4ef2d4596d69597da531446e735e53d50faeb0a6ab60996a584991950d
6
+ metadata.gz: 8c8fb085cbaa5ea150e072a54e98546f4336966871225ae5587d70d115da62d420e1f67b2459f83c39c5d29717f311e93d09e0440dd4bf4a75d1f1cec7573022
7
+ data.tar.gz: c0f6eb027e3f43c309c59643ceb28c8f7d783466c0663f3b65e93be52a0c3148123110d9aa81dda842027ace7f0f319519b5cdc1fec7102d65811a84fbc2b2ed
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ### 1.6.0 (2021/10/04)
2
+
3
+ #### Features
4
+
5
+ * [#2190](https://github.com/ruby-grape/grape/pull/2190): Upgrade dev deps & drop Ruby 2.4.x support - [@dnesteryuk](https://github.com/dnesteryuk).
6
+
7
+ #### Fixes
8
+
9
+ * [#2176](https://github.com/ruby-grape/grape/pull/2176): Fix: OPTIONS fails if matching all routes - [@myxoh](https://github.com/myxoh).
10
+ * [#2177](https://github.com/ruby-grape/grape/pull/2177): Fix: `default` validator fails if preceded by `as` validator - [@Catsuko](https://github.com/Catsuko).
11
+ * [#2180](https://github.com/ruby-grape/grape/pull/2180): Call `super` in `API.inherited` - [@yogeshjain999](https://github.com/yogeshjain999).
12
+ * [#2189](https://github.com/ruby-grape/grape/pull/2189): Fix: rename parameters when using `:as` (behaviour and grape-swagger documentation) - [@Jack12816](https://github.com/Jack12816).
13
+
1
14
  ### 1.5.3 (2021/03/07)
2
15
 
3
16
  #### Fixes
data/README.md CHANGED
@@ -158,7 +158,7 @@ content negotiation, versioning and much more.
158
158
 
159
159
  ## Stable Release
160
160
 
161
- You're reading the documentation for the stable release of Grape, **v1.5.3**.
161
+ You're reading the documentation for the stable release of Grape, **1.6.0**.
162
162
  Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
163
163
 
164
164
  ## Project Resources
@@ -800,6 +800,7 @@ Grape allows you to access only the parameters that have been declared by your `
800
800
 
801
801
  * Filter out the params that have been passed, but are not allowed.
802
802
  * Include any optional params that are declared but not passed.
803
+ * Perform any parameter renaming on the resulting hash.
803
804
 
804
805
  Consider the following API endpoint:
805
806
 
@@ -994,8 +995,10 @@ curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d
994
995
  ````json
995
996
  {
996
997
  "declared_params": {
997
- "first_name": "first name",
998
- "last_name": null
998
+ "user": {
999
+ "first_name": "first name",
1000
+ "last_name": null
1001
+ }
999
1002
  }
1000
1003
  }
1001
1004
  ````
@@ -1529,6 +1532,14 @@ end
1529
1532
 
1530
1533
  While Procs are convenient for single cases, consider using [Custom Validators](#custom-validators) in cases where a validation is used more than once.
1531
1534
 
1535
+ Note that [allow_blank](#allow_blank) validator applies while using `:values`. In the following example the absence of `:allow_blank` does not prevent `:state` from receiving blank values because `:allow_blank` defaults to `true`.
1536
+
1537
+ ```ruby
1538
+ params do
1539
+ requires :state, type: Symbol, values: [:active, :inactive]
1540
+ end
1541
+ ```
1542
+
1532
1543
  #### `except_values`
1533
1544
 
1534
1545
  Parameters can be restricted from having a specific set of values with the `:except_values` option.
@@ -3641,6 +3652,14 @@ You can access the controller params, headers, and helpers through the context w
3641
3652
  Note that when you're using Grape mounted on Rails you don't have to use Rails middleware because it's already included into your middleware stack.
3642
3653
  You only have to implement the helpers to access the specific `env` variable.
3643
3654
 
3655
+ If you are using a custom application that is inherited from `Rails::Application` and need to insert a new middleware among the ones initiated via Rails, you will need to register it manually in your custom application class.
3656
+
3657
+ ```ruby
3658
+ class Company::Application < Rails::Application
3659
+ config.middleware.insert_before(Rack::Attack, Middleware::ApiLogger)
3660
+ end
3661
+ ```
3662
+
3644
3663
  ### Remote IP
3645
3664
 
3646
3665
  By default you can access remote IP with `request.ip`. This is the remote IP address implemented by Rack. Sometimes it is desirable to get the remote IP [Rails-style](http://stackoverflow.com/questions/10997005/whats-the-difference-between-request-remote-ip-and-request-ip-in-rails) with `ActionDispatch::RemoteIp`.
@@ -3945,6 +3964,7 @@ Grape integrates with following third-party tools:
3945
3964
  * **[Skylight](https://www.skylight.io/)** - [skylight](https://github.com/skylightio/skylight-ruby) gem, [documentation](https://docs.skylight.io/grape/)
3946
3965
  * **[AppSignal](https://www.appsignal.com)** - [appsignal-ruby](https://github.com/appsignal/appsignal-ruby) gem, [documentation](http://docs.appsignal.com/getting-started/supported-frameworks.html#grape)
3947
3966
  * **[ElasticAPM](https://www.elastic.co/products/apm)** - [elastic-apm](https://github.com/elastic/apm-agent-ruby) gem, [documentation](https://www.elastic.co/guide/en/apm/agent/ruby/3.x/getting-started-rack.html#getting-started-grape)
3967
+ * **[Datadog APM](https://docs.datadoghq.com/tracing/)** - [ddtrace](https://github.com/datadog/dd-trace-rb) gem, [documentation](https://docs.datadoghq.com/tracing/setup_overview/setup/ruby/#grape)
3948
3968
 
3949
3969
  ## Contributing to Grape
3950
3970
 
data/UPGRADING.md CHANGED
@@ -1,10 +1,50 @@
1
1
  Upgrading Grape
2
2
  ===============
3
3
 
4
+ ### Upgrading to >= 1.6.0
5
+
6
+ #### Parameter renaming with :as
7
+
8
+ Prior to 1.6.0 the [parameter renaming](https://github.com/ruby-grape/grape#renaming) with `:as` was directly touching the request payload ([`#params`](https://github.com/ruby-grape/grape#parameters)) while duplicating the old and the new key to be both available in the hash. This allowed clients to bypass any validation in case they knew the internal name of the parameter. Unfortunately, in combination with [grape-swagger](https://github.com/ruby-grape/grape-swagger) the internal name (name set with `:as`) of the parameters were documented.
9
+
10
+ This behavior was fixed. Parameter renaming is now done when using the [`#declared(params)`](https://github.com/ruby-grape/grape#declared) parameters helper. This stops confusing validation/coercion behavior.
11
+
12
+ Here comes an illustration of the old and new behaviour as code:
13
+
14
+ ```ruby
15
+ # (1) Rename a to b, while client sends +a+
16
+ optional :a, type: Integer, as: :b
17
+ params = { a: 1 }
18
+ declared(params, include_missing: false)
19
+ # expected => { b: 1 }
20
+ # actual => { b: 1 }
21
+
22
+ # (2) Rename a to b, while client sends +b+
23
+ optional :a, type: Integer, as: :b, values: [1, 2, 3]
24
+ params = { b: '5' }
25
+ declared(params, include_missing: false)
26
+ # expected => { } (>= 1.6.0)
27
+ # actual => { b: '5' } (uncasted, unvalidated, <= 1.5.3)
28
+ ```
29
+
30
+ Another implication of this change is the dependent parameter resolution. Prior to 1.6.0 the following code produced an `Grape::Exceptions::UnknownParameter` because `:a` was replace by `:b`:
31
+
32
+ ```ruby
33
+ params do
34
+ optional :a, as: :b
35
+ given :a do # (<= 1.5.3 you had to reference +:b+ here to make it work)
36
+ requires :c
37
+ end
38
+ end
39
+ ```
40
+
41
+ This code now works without any errors, as the renaming is just an internal behaviour of the `#declared(params)` parameter helper.
42
+
43
+ See [#2189](https://github.com/ruby-grape/grape/pull/2189) for more information.
4
44
 
5
45
  ### Upgrading to >= 1.5.3
6
46
 
7
- ### Nil value and coercion
47
+ #### Nil value and coercion
8
48
 
9
49
  Prior to 1.2.5 version passing a `nil` value for a parameter with a custom coercer would invoke the coercer, and not passing a parameter would not invoke it.
10
50
  This behavior was not tested or documented. Version 1.3.0 quietly changed this behavior, in such that `nil` values skipped the coercion. Version 1.5.3 fixes and documents this as follows:
@@ -216,6 +256,8 @@ end
216
256
 
217
257
  ### Upgrading to >= 1.3.0
218
258
 
259
+ You will need to upgrade to this version if you depend on `rack >= 2.1.0`.
260
+
219
261
  #### Ruby
220
262
 
221
263
  After adding dry-types, Ruby 2.4 or newer is required.
data/grape.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift File.expand_path('lib', __dir__)
4
4
  require 'grape/version'
5
5
 
6
6
  Gem::Specification.new do |s|
@@ -14,10 +14,10 @@ Gem::Specification.new do |s|
14
14
  s.description = 'A Ruby framework for rapid API development with great conventions.'
15
15
  s.license = 'MIT'
16
16
  s.metadata = {
17
- 'bug_tracker_uri' => 'https://github.com/ruby-grape/grape/issues',
18
- 'changelog_uri' => "https://github.com/ruby-grape/grape/blob/v#{s.version}/CHANGELOG.md",
17
+ 'bug_tracker_uri' => 'https://github.com/ruby-grape/grape/issues',
18
+ 'changelog_uri' => "https://github.com/ruby-grape/grape/blob/v#{s.version}/CHANGELOG.md",
19
19
  'documentation_uri' => "https://www.rubydoc.info/gems/grape/#{s.version}",
20
- 'source_code_uri' => "https://github.com/ruby-grape/grape/tree/v#{s.version}"
20
+ 'source_code_uri' => "https://github.com/ruby-grape/grape/tree/v#{s.version}"
21
21
  }
22
22
 
23
23
  s.add_runtime_dependency 'activesupport'
@@ -32,5 +32,5 @@ Gem::Specification.new do |s|
32
32
  s.files += Dir['lib/**/*']
33
33
  s.test_files = Dir['spec/**/*']
34
34
  s.require_paths = ['lib']
35
- s.required_ruby_version = '>= 2.4.0'
35
+ s.required_ruby_version = '>= 2.5.0'
36
36
  end
@@ -10,12 +10,11 @@ module Grape
10
10
  include Grape::DSL::API
11
11
 
12
12
  class << self
13
- attr_reader :instance
14
- attr_reader :base
13
+ attr_reader :instance, :base
15
14
  attr_accessor :configuration
16
15
 
17
16
  def given(conditional_option, &block)
18
- evaluate_as_instance_with_configuration(block, lazy: true) if conditional_option && block_given?
17
+ evaluate_as_instance_with_configuration(block, lazy: true) if conditional_option && block
19
18
  end
20
19
 
21
20
  def mounted(&block)
@@ -28,7 +27,7 @@ module Grape
28
27
  end
29
28
 
30
29
  def to_s
31
- (base && base.to_s) || super
30
+ base&.to_s || super
32
31
  end
33
32
 
34
33
  def base_instance?
@@ -82,6 +81,7 @@ module Grape
82
81
 
83
82
  def compile!
84
83
  return if instance
84
+
85
85
  LOCK.synchronize { compile unless instance }
86
86
  end
87
87
 
@@ -103,7 +103,7 @@ module Grape
103
103
  def nest(*blocks, &block)
104
104
  blocks.reject!(&:nil?)
105
105
  if blocks.any?
106
- evaluate_as_instance_with_configuration(block) if block_given?
106
+ evaluate_as_instance_with_configuration(block) if block
107
107
  blocks.each { |b| evaluate_as_instance_with_configuration(b) }
108
108
  reset_validations!
109
109
  else
@@ -114,9 +114,7 @@ module Grape
114
114
  def evaluate_as_instance_with_configuration(block, lazy: false)
115
115
  lazy_block = Grape::Util::LazyBlock.new do |configuration|
116
116
  value_for_configuration = configuration
117
- if value_for_configuration.respond_to?(:lazy?) && value_for_configuration.lazy?
118
- self.configuration = value_for_configuration.evaluate
119
- end
117
+ self.configuration = value_for_configuration.evaluate if value_for_configuration.respond_to?(:lazy?) && value_for_configuration.lazy?
120
118
  response = instance_eval(&block)
121
119
  self.configuration = value_for_configuration
122
120
  response
@@ -179,7 +177,8 @@ module Grape
179
177
  # X-Cascade. Default :cascade is true.
180
178
  def cascade?
181
179
  return self.class.namespace_inheritable(:cascade) if self.class.inheritable_setting.namespace_inheritable.key?(:cascade)
182
- return self.class.namespace_inheritable(:version_options)[:cascade] if self.class.namespace_inheritable(:version_options) && self.class.namespace_inheritable(:version_options).key?(:cascade)
180
+ return self.class.namespace_inheritable(:version_options)[:cascade] if self.class.namespace_inheritable(:version_options)&.key?(:cascade)
181
+
183
182
  true
184
183
  end
185
184
 
@@ -200,17 +199,15 @@ module Grape
200
199
  without_root_prefix do
201
200
  without_versioning do
202
201
  versioned_route_configs.each do |config|
202
+ next if config[:options][:matching_wildchar]
203
+
203
204
  allowed_methods = config[:methods].dup
204
205
 
205
- unless self.class.namespace_inheritable(:do_not_route_head)
206
- allowed_methods |= [Grape::Http::Headers::HEAD] if allowed_methods.include?(Grape::Http::Headers::GET)
207
- end
206
+ allowed_methods |= [Grape::Http::Headers::HEAD] if !self.class.namespace_inheritable(:do_not_route_head) && allowed_methods.include?(Grape::Http::Headers::GET)
208
207
 
209
208
  allow_header = (self.class.namespace_inheritable(:do_not_route_options) ? allowed_methods : [Grape::Http::Headers::OPTIONS] | allowed_methods)
210
209
 
211
- unless self.class.namespace_inheritable(:do_not_route_options) || allowed_methods.include?(Grape::Http::Headers::OPTIONS)
212
- config[:endpoint].options[:options_route_enabled] = true
213
- end
210
+ config[:endpoint].options[:options_route_enabled] = true unless self.class.namespace_inheritable(:do_not_route_options) || allowed_methods.include?(Grape::Http::Headers::OPTIONS)
214
211
 
215
212
  attributes = config.merge(allowed_methods: allowed_methods, allow_header: allow_header)
216
213
  generate_not_allowed_method(config[:pattern], **attributes)
@@ -228,7 +225,7 @@ module Grape
228
225
  last_route = routes.last # Most of the configuration is taken from the last endpoint
229
226
  matching_wildchar = routes.any? { |route| route.request_method == '*' }
230
227
  {
231
- options: {},
228
+ options: { matching_wildchar: matching_wildchar },
232
229
  pattern: last_route.pattern,
233
230
  requirements: last_route.requirements,
234
231
  path: last_route.origin,
@@ -248,7 +245,6 @@ module Grape
248
245
  Grape::Http::Headers::SUPPORTED_METHODS_WITHOUT_OPTIONS
249
246
  end
250
247
  not_allowed_methods = supported_methods - allowed_methods
251
- return if not_allowed_methods.empty?
252
248
  @router.associate_routes(pattern, not_allowed_methods: not_allowed_methods, **attributes)
253
249
  end
254
250
 
data/lib/grape/api.rb CHANGED
@@ -20,10 +20,11 @@ module Grape
20
20
 
21
21
  # When inherited, will create a list of all instances (times the API was mounted)
22
22
  # It will listen to the setup required to mount that endpoint, and replicate it on any new instance
23
- def inherited(api, base_instance_parent = Grape::API::Instance)
24
- api.initial_setup(base_instance_parent)
23
+ def inherited(api)
24
+ super
25
+
26
+ api.initial_setup(Grape::API == self ? Grape::API::Instance : @base_instance)
25
27
  api.override_all_methods!
26
- make_inheritable(api)
27
28
  end
28
29
 
29
30
  # Initialize the instance variables on the remountable class, and the base_instance
@@ -68,15 +69,6 @@ module Grape
68
69
  instance_for_rack.call(*args, &block)
69
70
  end
70
71
 
71
- # Allows an API to itself be inheritable:
72
- def make_inheritable(api)
73
- # When a child API inherits from a parent API.
74
- def api.inherited(child_api)
75
- # The instances of the child API inherit from the instances of the parent API
76
- Grape::API.inherited(child_api, base_instance)
77
- end
78
- end
79
-
80
72
  # Alleviates problems with autoloading by tring to search for the constant
81
73
  def const_missing(*args)
82
74
  if base_instance.const_defined?(*args)
@@ -151,6 +143,7 @@ module Grape
151
143
 
152
144
  def replay_step_on(instance, setup_step)
153
145
  return if skip_immediate_run?(instance, setup_step[:args])
146
+
154
147
  args = evaluate_arguments(instance.configuration, *setup_step[:args])
155
148
  response = instance.send(setup_step[:method], *args, &setup_step[:block])
156
149
  if skip_immediate_run?(instance, [response])
data/lib/grape/cookies.rb CHANGED
@@ -33,9 +33,11 @@ module Grape
33
33
  @cookies.each(&block)
34
34
  end
35
35
 
36
+ # rubocop:disable Layout/SpaceBeforeBrackets
36
37
  def delete(name, **opts)
37
38
  options = opts.merge(value: 'deleted', expires: Time.at(0))
38
39
  self.[]=(name, options)
39
40
  end
41
+ # rubocop:enable Layout/SpaceBeforeBrackets
40
42
  end
41
43
  end
@@ -50,7 +50,7 @@ module Grape
50
50
  # end
51
51
  #
52
52
  def desc(description, options = {}, &config_block)
53
- if block_given?
53
+ if config_block
54
54
  endpoint_configuration = if defined?(configuration)
55
55
  # When the instance is mounted - the configuration is executed on mount time
56
56
  if configuration.respond_to?(:evaluate)
@@ -68,9 +68,7 @@ module Grape
68
68
  end
69
69
 
70
70
  config_class.configure(&config_block)
71
- unless options.empty?
72
- warn '[DEPRECATION] Passing a options hash and a block to `desc` is deprecated. Move all hash options to block.'
73
- end
71
+ warn '[DEPRECATION] Passing a options hash and a block to `desc` is deprecated. Move all hash options to block.' unless options.empty?
74
72
  options = config_class.settings
75
73
  else
76
74
  options = options.merge(description: description)
@@ -92,7 +90,7 @@ module Grape
92
90
 
93
91
  def unset_description_field(field)
94
92
  description = route_setting(:description)
95
- description.delete(field) if description
93
+ description&.delete(field)
96
94
  end
97
95
 
98
96
  # Returns an object which configures itself via an instance-context DSL.
@@ -36,8 +36,8 @@ module Grape
36
36
  #
37
37
  def helpers(*new_modules, &block)
38
38
  include_new_modules(new_modules) if new_modules.any?
39
- include_block(block) if block_given?
40
- include_all_in_scope if !block_given? && new_modules.empty?
39
+ include_block(block) if block
40
+ include_all_in_scope if !block && new_modules.empty?
41
41
  end
42
42
 
43
43
  protected
@@ -67,12 +67,13 @@ module Grape
67
67
 
68
68
  def define_boolean_in_mod(mod)
69
69
  return if defined? mod::Boolean
70
+
70
71
  mod.const_set('Boolean', Grape::API::Boolean)
71
72
  end
72
73
 
73
- def inject_api_helpers_to_mod(mod, &_block)
74
+ def inject_api_helpers_to_mod(mod, &block)
74
75
  mod.extend(BaseHelper) unless mod.is_a?(BaseHelper)
75
- yield if block_given?
76
+ yield if block
76
77
  mod.api_changed(self)
77
78
  end
78
79
  end
@@ -96,6 +97,7 @@ module Grape
96
97
 
97
98
  def process_named_params
98
99
  return unless instance_variable_defined?(:@named_params) && @named_params && @named_params.any?
100
+
99
101
  api.namespace_stackable(:named_params, @named_params)
100
102
  end
101
103
  end
@@ -48,6 +48,8 @@ module Grape
48
48
  end
49
49
 
50
50
  def declared_hash(passed_params, options, declared_params, params_nested_path)
51
+ renamed_params = route_setting(:renamed_params) || {}
52
+
51
53
  declared_params.each_with_object(passed_params.class.new) do |declared_param, memo|
52
54
  if declared_param.is_a?(Hash)
53
55
  declared_param.each_pair do |declared_parent_param, declared_children_params|
@@ -55,8 +57,11 @@ module Grape
55
57
  params_nested_path_dup << declared_parent_param.to_s
56
58
  next unless options[:include_missing] || passed_params.key?(declared_parent_param)
57
59
 
60
+ rename_path = params_nested_path + [declared_parent_param.to_s]
61
+ renamed_param_name = renamed_params[rename_path]
62
+
63
+ memo_key = optioned_param_key(renamed_param_name || declared_parent_param, options)
58
64
  passed_children_params = passed_params[declared_parent_param] || passed_params.class.new
59
- memo_key = optioned_param_key(declared_parent_param, options)
60
65
 
61
66
  memo[memo_key] = handle_passed_param(params_nested_path_dup, passed_children_params.any?) do
62
67
  declared(passed_children_params, options, declared_children_params, params_nested_path_dup)
@@ -65,13 +70,13 @@ module Grape
65
70
  else
66
71
  # If it is not a Hash then it does not have children.
67
72
  # Find its value or set it to nil.
68
- has_renaming = route_setting(:renamed_params) && route_setting(:renamed_params).find { |current| current[declared_param] }
69
- param_renaming = has_renaming[declared_param] if has_renaming
73
+ next unless options[:include_missing] || passed_params.key?(declared_param)
70
74
 
71
- next unless options[:include_missing] || passed_params.key?(declared_param) || (param_renaming && passed_params.key?(param_renaming))
75
+ rename_path = params_nested_path + [declared_param.to_s]
76
+ renamed_param_name = renamed_params[rename_path]
72
77
 
73
- memo_key = optioned_param_key(param_renaming || declared_param, options)
74
- passed_param = passed_params[param_renaming || declared_param]
78
+ memo_key = optioned_param_key(renamed_param_name || declared_param, options)
79
+ passed_param = passed_params[declared_param]
75
80
 
76
81
  params_nested_path_dup = params_nested_path.dup
77
82
  params_nested_path_dup << declared_param.to_s
@@ -86,7 +91,7 @@ module Grape
86
91
  return yield if has_passed_children
87
92
 
88
93
  key = params_nested_path[0]
89
- key += '[' + params_nested_path[1..-1].join('][') + ']' if params_nested_path.size > 1
94
+ key += "[#{params_nested_path[1..-1].join('][')}]" if params_nested_path.size > 1
90
95
 
91
96
  route_options_params = options[:route_options][:params] || {}
92
97
  type = route_options_params.dig(key, :type)
@@ -94,7 +99,7 @@ module Grape
94
99
 
95
100
  if type == 'Hash' && !has_children
96
101
  {}
97
- elsif type == 'Array' || type&.start_with?('[') && !type&.include?(',')
102
+ elsif type == 'Array' || (type&.start_with?('[') && !type&.include?(','))
98
103
  []
99
104
  elsif type == 'Set' || type&.start_with?('#<Set')
100
105
  Set.new
@@ -117,6 +122,7 @@ module Grape
117
122
  end
118
123
 
119
124
  raise ArgumentError, 'Tried to filter for declared parameters but none exist.' unless declared_params
125
+
120
126
  declared_params
121
127
  end
122
128
  end
@@ -187,11 +193,13 @@ module Grape
187
193
  case status
188
194
  when Symbol
189
195
  raise ArgumentError, "Status code :#{status} is invalid." unless Rack::Utils::SYMBOL_TO_STATUS_CODE.key?(status)
196
+
190
197
  @status = Rack::Utils.status_code(status)
191
198
  when Integer
192
199
  @status = status
193
200
  when nil
194
201
  return @status if instance_variable_defined?(:@status) && @status
202
+
195
203
  case request.request_method.to_s.upcase
196
204
  when Grape::Http::Headers::POST
197
205
  201
@@ -369,6 +377,7 @@ module Grape
369
377
  representation = (body || {}).merge(key => representation)
370
378
  elsif entity_class.present? && body
371
379
  raise ArgumentError, "Representation of type #{representation.class} cannot be merged." unless representation.respond_to?(:merge)
380
+
372
381
  representation = body.merge(representation)
373
382
  end
374
383
 
@@ -18,28 +18,28 @@ module Grape
18
18
  # to inject.
19
19
  def use(middleware_class, *args, &block)
20
20
  arr = [:use, middleware_class, *args]
21
- arr << block if block_given?
21
+ arr << block if block
22
22
 
23
23
  namespace_stackable(:middleware, arr)
24
24
  end
25
25
 
26
26
  def insert(*args, &block)
27
27
  arr = [:insert, *args]
28
- arr << block if block_given?
28
+ arr << block if block
29
29
 
30
30
  namespace_stackable(:middleware, arr)
31
31
  end
32
32
 
33
33
  def insert_before(*args, &block)
34
34
  arr = [:insert_before, *args]
35
- arr << block if block_given?
35
+ arr << block if block
36
36
 
37
37
  namespace_stackable(:middleware, arr)
38
38
  end
39
39
 
40
40
  def insert_after(*args, &block)
41
41
  arr = [:insert_after, *args]
42
- arr << block if block_given?
42
+ arr << block if block
43
43
 
44
44
  namespace_stackable(:middleware, arr)
45
45
  end
@@ -133,7 +133,7 @@ module Grape
133
133
  require_required_and_optional_fields(attrs.first, opts)
134
134
  else
135
135
  validate_attributes(attrs, opts, &block)
136
- block_given? ? new_scope(orig_attrs, &block) : push_declared_params(attrs, **opts.slice(:as))
136
+ block ? new_scope(orig_attrs, &block) : push_declared_params(attrs, **opts.slice(:as))
137
137
  end
138
138
  end
139
139
 
@@ -149,7 +149,7 @@ module Grape
149
149
  opts = @group.merge(opts) if instance_variable_defined?(:@group) && @group
150
150
 
151
151
  # check type for optional parameter group
152
- if attrs && block_given?
152
+ if attrs && block
153
153
  raise Grape::Exceptions::MissingGroupTypeError.new if type.nil?
154
154
  raise Grape::Exceptions::UnsupportedGroupTypeError.new unless Grape::Validations::Types.group?(type)
155
155
  end
@@ -159,7 +159,7 @@ module Grape
159
159
  else
160
160
  validate_attributes(attrs, opts, &block)
161
161
 
162
- block_given? ? new_scope(orig_attrs, true, &block) : push_declared_params(attrs, **opts.slice(:as))
162
+ block ? new_scope(orig_attrs, true, &block) : push_declared_params(attrs, **opts.slice(:as))
163
163
  end
164
164
  end
165
165
 
@@ -26,6 +26,7 @@ module Grape
26
26
  # define a single mime type
27
27
  mime_type = content_types[new_format.to_sym]
28
28
  raise Grape::Exceptions::MissingMimeType.new(new_format) unless mime_type
29
+
29
30
  namespace_stackable(:content_types, new_format.to_sym => mime_type)
30
31
  else
31
32
  namespace_inheritable(:format)
@@ -102,14 +103,13 @@ module Grape
102
103
  def rescue_from(*args, &block)
103
104
  if args.last.is_a?(Proc)
104
105
  handler = args.pop
105
- elsif block_given?
106
+ elsif block
106
107
  handler = block
107
108
  end
108
109
 
109
110
  options = args.extract_options!
110
- if block_given? && options.key?(:with)
111
- raise ArgumentError, 'both :with option and block cannot be passed'
112
- end
111
+ raise ArgumentError, 'both :with option and block cannot be passed' if block && options.key?(:with)
112
+
113
113
  handler ||= extract_with(options)
114
114
 
115
115
  if args.include?(:all)
@@ -127,7 +127,7 @@ module Grape
127
127
  :base_only_rescue_handlers
128
128
  end
129
129
 
130
- namespace_reverse_stackable handler_type, Hash[args.map { |arg| [arg, handler] }]
130
+ namespace_reverse_stackable handler_type, args.map { |arg| [arg, handler] }.to_h
131
131
  end
132
132
 
133
133
  namespace_stackable(:rescue_options, options)
@@ -154,7 +154,8 @@ module Grape
154
154
  # @param model_class [Class] The model class that will be represented.
155
155
  # @option options [Class] :with The entity class that will represent the model.
156
156
  def represent(model_class, options)
157
- raise Grape::Exceptions::InvalidWithOptionForRepresent.new unless options[:with] && options[:with].is_a?(Class)
157
+ raise Grape::Exceptions::InvalidWithOptionForRepresent.new unless options[:with].is_a?(Class)
158
+
158
159
  namespace_stackable(:representations, model_class => options[:with])
159
160
  end
160
161
 
@@ -162,9 +163,11 @@ module Grape
162
163
 
163
164
  def extract_with(options)
164
165
  return unless options.key?(:with)
166
+
165
167
  with_option = options.delete(:with)
166
168
  return with_option if with_option.instance_of?(Proc)
167
169
  return with_option.to_sym if with_option.instance_of?(Symbol) || with_option.instance_of?(String)
170
+
168
171
  raise ArgumentError, "with: #{with_option.class}, expected Symbol, String or Proc"
169
172
  end
170
173
  end
@@ -38,7 +38,7 @@ module Grape
38
38
 
39
39
  @versions = versions | requested_versions
40
40
 
41
- if block_given?
41
+ if block
42
42
  within_namespace do
43
43
  namespace_inheritable(:version, requested_versions)
44
44
  namespace_inheritable(:version_options, options)
@@ -166,7 +166,7 @@ module Grape
166
166
  def namespace(space = nil, options = {}, &block)
167
167
  @namespace_description = nil unless instance_variable_defined?(:@namespace_description) && @namespace_description
168
168
 
169
- if space || block_given?
169
+ if space || block
170
170
  within_namespace do
171
171
  previous_namespace_description = @namespace_description
172
172
  @namespace_description = (@namespace_description || {}).deep_merge(namespace_setting(:description) || {})