grape 2.4.0 → 3.0.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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -0
  3. data/CONTRIBUTING.md +1 -9
  4. data/README.md +72 -31
  5. data/UPGRADING.md +34 -0
  6. data/grape.gemspec +4 -4
  7. data/lib/grape/api/instance.rb +49 -72
  8. data/lib/grape/api.rb +24 -34
  9. data/lib/grape/dry_types.rb +48 -4
  10. data/lib/grape/dsl/callbacks.rb +8 -58
  11. data/lib/grape/dsl/desc.rb +8 -67
  12. data/lib/grape/dsl/helpers.rb +59 -64
  13. data/lib/grape/dsl/inside_route.rb +20 -43
  14. data/lib/grape/dsl/logger.rb +3 -6
  15. data/lib/grape/dsl/middleware.rb +22 -40
  16. data/lib/grape/dsl/parameters.rb +7 -16
  17. data/lib/grape/dsl/request_response.rb +136 -139
  18. data/lib/grape/dsl/routing.rb +229 -201
  19. data/lib/grape/dsl/settings.rb +22 -134
  20. data/lib/grape/dsl/validations.rb +37 -45
  21. data/lib/grape/endpoint.rb +64 -96
  22. data/lib/grape/error_formatter/base.rb +2 -0
  23. data/lib/grape/exceptions/base.rb +1 -1
  24. data/lib/grape/exceptions/missing_group_type.rb +0 -2
  25. data/lib/grape/exceptions/unsupported_group_type.rb +0 -2
  26. data/lib/grape/middleware/auth/dsl.rb +5 -6
  27. data/lib/grape/middleware/error.rb +1 -11
  28. data/lib/grape/middleware/formatter.rb +4 -2
  29. data/lib/grape/middleware/stack.rb +2 -2
  30. data/lib/grape/middleware/versioner/accept_version_header.rb +1 -1
  31. data/lib/grape/middleware/versioner/base.rb +24 -42
  32. data/lib/grape/middleware/versioner/header.rb +1 -1
  33. data/lib/grape/middleware/versioner/param.rb +2 -2
  34. data/lib/grape/middleware/versioner/path.rb +1 -1
  35. data/lib/grape/namespace.rb +11 -0
  36. data/lib/grape/params_builder/base.rb +2 -0
  37. data/lib/grape/router.rb +4 -3
  38. data/lib/grape/util/api_description.rb +56 -0
  39. data/lib/grape/util/base_inheritable.rb +5 -2
  40. data/lib/grape/util/inheritable_setting.rb +7 -0
  41. data/lib/grape/util/media_type.rb +1 -1
  42. data/lib/grape/util/registry.rb +1 -1
  43. data/lib/grape/validations/contract_scope.rb +2 -2
  44. data/lib/grape/validations/params_documentation.rb +50 -0
  45. data/lib/grape/validations/params_scope.rb +38 -53
  46. data/lib/grape/validations/types/array_coercer.rb +2 -3
  47. data/lib/grape/validations/types/dry_type_coercer.rb +4 -11
  48. data/lib/grape/validations/types/primitive_coercer.rb +1 -28
  49. data/lib/grape/validations/types.rb +10 -25
  50. data/lib/grape/validations/validators/base.rb +0 -7
  51. data/lib/grape/version.rb +1 -1
  52. data/lib/grape.rb +7 -10
  53. metadata +24 -14
  54. data/lib/grape/api/helpers.rb +0 -9
  55. data/lib/grape/dsl/api.rb +0 -17
  56. data/lib/grape/dsl/configuration.rb +0 -15
  57. data/lib/grape/types/invalid_value.rb +0 -8
  58. data/lib/grape/util/strict_hash_configuration.rb +0 -108
  59. data/lib/grape/validations/attributes_doc.rb +0 -60
@@ -2,9 +2,53 @@
2
2
 
3
3
  module Grape
4
4
  module DryTypes
5
- # Call +Dry.Types()+ to add all registered types to +DryTypes+ which is
6
- # a container in this case. Check documentation for more information
7
- # https://dry-rb.org/gems/dry-types/1.2/getting-started/
8
- include Dry.Types()
5
+ # https://dry-rb.org/gems/dry-types/main/getting-started/
6
+ # limit to what Grape is using
7
+ include Dry.Types(:params, :coercible, :strict)
8
+
9
+ class StrictCache < Grape::Util::Cache
10
+ MAPPING = {
11
+ Grape::API::Boolean => DryTypes::Strict::Bool,
12
+ BigDecimal => DryTypes::Strict::Decimal,
13
+ Numeric => DryTypes::Strict::Integer | DryTypes::Strict::Float | DryTypes::Strict::Decimal,
14
+ TrueClass => DryTypes::Strict::Bool.constrained(eql: true),
15
+ FalseClass => DryTypes::Strict::Bool.constrained(eql: false)
16
+ }.freeze
17
+
18
+ def initialize
19
+ super
20
+ @cache = Hash.new do |h, strict_type|
21
+ h[strict_type] = MAPPING.fetch(strict_type) do
22
+ DryTypes.wrapped_dry_types_const_get(DryTypes::Strict, strict_type)
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ class ParamsCache < Grape::Util::Cache
29
+ MAPPING = {
30
+ Grape::API::Boolean => DryTypes::Params::Bool,
31
+ BigDecimal => DryTypes::Params::Decimal,
32
+ Numeric => DryTypes::Params::Integer | DryTypes::Params::Float | DryTypes::Params::Decimal,
33
+ TrueClass => DryTypes::Params::Bool.constrained(eql: true),
34
+ FalseClass => DryTypes::Params::Bool.constrained(eql: false),
35
+ String => DryTypes::Coercible::String
36
+ }.freeze
37
+
38
+ def initialize
39
+ super
40
+ @cache = Hash.new do |h, params_type|
41
+ h[params_type] = MAPPING.fetch(params_type) do
42
+ DryTypes.wrapped_dry_types_const_get(DryTypes::Params, params_type)
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def self.wrapped_dry_types_const_get(dry_type, type)
49
+ dry_type.const_get(type.name, false)
50
+ rescue NameError
51
+ raise ArgumentError, "type #{type} should support coercion via `[]`" unless type.respond_to?(:[])
52
+ end
9
53
  end
10
54
  end
@@ -2,66 +2,16 @@
2
2
 
3
3
  module Grape
4
4
  module DSL
5
- # Blocks can be executed before or after every API call, using `before`, `after`,
6
- # `before_validation` and `after_validation`.
7
- #
8
- # Before and after callbacks execute in the following order:
9
- #
10
- # 1. `before`
11
- # 2. `before_validation`
12
- # 3. _validations_
13
- # 4. `after_validation`
14
- # 5. _the API call_
15
- # 6. `after`
16
- #
17
- # Steps 4, 5 and 6 only happen if validation succeeds.
18
5
  module Callbacks
19
- extend ActiveSupport::Concern
6
+ # before: execute the given block before validation, coercion, or any endpoint
7
+ # before_validation: execute the given block after `before`, but prior to validation or coercion
8
+ # after_validation: execute the given block after validations and coercions, but before any endpoint code
9
+ # after: execute the given block after the endpoint code has run except in unsuccessful
10
+ # finally: execute the given block after the endpoint code even if unsuccessful
20
11
 
21
- include Grape::DSL::Configuration
22
-
23
- module ClassMethods
24
- # Execute the given block before validation, coercion, or any endpoint
25
- # code is executed.
26
- def before(&block)
27
- namespace_stackable(:befores, block)
28
- end
29
-
30
- # Execute the given block after `before`, but prior to validation or
31
- # coercion.
32
- def before_validation(&block)
33
- namespace_stackable(:before_validations, block)
34
- end
35
-
36
- # Execute the given block after validations and coercions, but before
37
- # any endpoint code.
38
- def after_validation(&block)
39
- namespace_stackable(:after_validations, block)
40
- end
41
-
42
- # Execute the given block after the endpoint code has run.
43
- def after(&block)
44
- namespace_stackable(:afters, block)
45
- end
46
-
47
- # Allows you to specify a something that will always be executed after a call
48
- # API call. Unlike the `after` block, this code will run even on
49
- # unsuccesful requests.
50
- # @example
51
- # class ExampleAPI < Grape::API
52
- # before do
53
- # ApiLogger.start
54
- # end
55
- # finally do
56
- # ApiLogger.close
57
- # end
58
- # end
59
- #
60
- # This will make sure that the ApiLogger is opened and closed around every
61
- # request
62
- # @param ensured_block [Proc] The block to be executed after every api_call
63
- def finally(&block)
64
- namespace_stackable(:finallies, block)
12
+ %w[before before_validation after_validation after finally].each do |callback_method|
13
+ define_method callback_method.to_sym do |&block|
14
+ inheritable_setting.namespace_stackable[callback_method.pluralize.to_sym] = block
65
15
  end
66
16
  end
67
17
  end
@@ -3,28 +3,7 @@
3
3
  module Grape
4
4
  module DSL
5
5
  module Desc
6
- include Grape::DSL::Settings
7
-
8
- ROUTE_ATTRIBUTES = %i[
9
- body_name
10
- consumes
11
- default
12
- deprecated
13
- description
14
- detail
15
- entity
16
- headers
17
- hidden
18
- http_codes
19
- is_array
20
- named
21
- nickname
22
- params
23
- produces
24
- security
25
- summary
26
- tags
27
- ].freeze
6
+ extend Grape::DSL::Settings
28
7
 
29
8
  # Add a description to the next namespace or function.
30
9
  # @param description [String] descriptive string for this endpoint
@@ -70,54 +49,16 @@ module Grape
70
49
  # # ...
71
50
  # end
72
51
  #
73
- def desc(description, options = nil, &config_block)
74
- opts =
52
+ def desc(description, options = {}, &config_block)
53
+ settings =
75
54
  if config_block
76
- desc_container(endpoint_configuration).then do |config_class|
77
- config_class.configure do
78
- description(description)
79
- end
80
-
81
- config_class.configure(&config_block)
82
- config_class.settings
83
- end
55
+ endpoint_config = defined?(configuration) ? configuration : nil
56
+ Grape::Util::ApiDescription.new(description, endpoint_config, &config_block).settings
84
57
  else
85
- options&.merge(description: description) || { description: description }
86
- end
87
-
88
- namespace_setting :description, opts
89
- route_setting :description, opts
90
- end
91
-
92
- # Returns an object which configures itself via an instance-context DSL.
93
- def desc_container(endpoint_configuration)
94
- Module.new do
95
- include Grape::Util::StrictHashConfiguration.module(*ROUTE_ATTRIBUTES)
96
- config_context.define_singleton_method(:configuration) do
97
- endpoint_configuration
98
- end
99
-
100
- def config_context.success(*args)
101
- entity(*args)
102
- end
103
-
104
- def config_context.failure(*args)
105
- http_codes(*args)
58
+ options.merge(description: description)
106
59
  end
107
- end
108
- end
109
-
110
- private
111
-
112
- def endpoint_configuration
113
- return {} unless defined?(configuration)
114
-
115
- if configuration.respond_to?(:evaluate)
116
- configuration.evaluate
117
- # Within `given` or `mounted blocks` the configuration is already evaluated
118
- elsif configuration.is_a?(Hash)
119
- configuration
120
- end
60
+ inheritable_setting.namespace[:description] = settings
61
+ inheritable_setting.route[:description] = settings
121
62
  end
122
63
  end
123
64
  end
@@ -3,81 +3,76 @@
3
3
  module Grape
4
4
  module DSL
5
5
  module Helpers
6
- extend ActiveSupport::Concern
7
- include Grape::DSL::Configuration
8
-
9
- module ClassMethods
10
- # Add helper methods that will be accessible from any
11
- # endpoint within this namespace (and child namespaces).
12
- #
13
- # When called without a block, all known helpers within this scope
14
- # are included.
15
- #
16
- # @param [Array] new_modules optional array of modules to include
17
- # @param [Block] block optional block of methods to include
18
- #
19
- # @example Define some helpers.
20
- #
21
- # class ExampleAPI < Grape::API
22
- # helpers do
23
- # def current_user
24
- # User.find_by_id(params[:token])
25
- # end
26
- # end
27
- # end
28
- #
29
- # @example Include many modules
30
- #
31
- # class ExampleAPI < Grape::API
32
- # helpers Authentication, Mailer, OtherModule
33
- # end
34
- #
35
- def helpers(*new_modules, &block)
36
- include_new_modules(new_modules)
37
- include_block(block)
38
- include_all_in_scope if !block && new_modules.empty?
39
- end
6
+ # Add helper methods that will be accessible from any
7
+ # endpoint within this namespace (and child namespaces).
8
+ #
9
+ # When called without a block, all known helpers within this scope
10
+ # are included.
11
+ #
12
+ # @param [Array] new_modules optional array of modules to include
13
+ # @param [Block] block optional block of methods to include
14
+ #
15
+ # @example Define some helpers.
16
+ #
17
+ # class ExampleAPI < Grape::API
18
+ # helpers do
19
+ # def current_user
20
+ # User.find_by_id(params[:token])
21
+ # end
22
+ # end
23
+ # end
24
+ #
25
+ # @example Include many modules
26
+ #
27
+ # class ExampleAPI < Grape::API
28
+ # helpers Authentication, Mailer, OtherModule
29
+ # end
30
+ #
31
+ def helpers(*new_modules, &block)
32
+ include_new_modules(new_modules)
33
+ include_block(block)
34
+ include_all_in_scope if !block && new_modules.empty?
35
+ end
40
36
 
41
- protected
37
+ private
42
38
 
43
- def include_new_modules(modules)
44
- return if modules.empty?
39
+ def include_new_modules(modules)
40
+ return if modules.empty?
45
41
 
46
- modules.each { |mod| make_inclusion(mod) }
47
- end
42
+ modules.each { |mod| make_inclusion(mod) }
43
+ end
48
44
 
49
- def include_block(block)
50
- return unless block
45
+ def include_block(block)
46
+ return unless block
51
47
 
52
- Module.new.tap do |mod|
53
- make_inclusion(mod) { mod.class_eval(&block) }
54
- end
48
+ Module.new.tap do |mod|
49
+ make_inclusion(mod) { mod.class_eval(&block) }
55
50
  end
51
+ end
56
52
 
57
- def make_inclusion(mod, &block)
58
- define_boolean_in_mod(mod)
59
- inject_api_helpers_to_mod(mod, &block)
60
- namespace_stackable(:helpers, mod)
61
- end
53
+ def make_inclusion(mod, &block)
54
+ define_boolean_in_mod(mod)
55
+ inject_api_helpers_to_mod(mod, &block)
56
+ inheritable_setting.namespace_stackable[:helpers] = mod
57
+ end
62
58
 
63
- def include_all_in_scope
64
- Module.new.tap do |mod|
65
- namespace_stackable(:helpers).each { |mod_to_include| mod.include mod_to_include }
66
- change!
67
- end
59
+ def include_all_in_scope
60
+ Module.new.tap do |mod|
61
+ namespace_stackable(:helpers).each { |mod_to_include| mod.include mod_to_include }
62
+ change!
68
63
  end
64
+ end
69
65
 
70
- def define_boolean_in_mod(mod)
71
- return if defined? mod::Boolean
66
+ def define_boolean_in_mod(mod)
67
+ return if defined? mod::Boolean
72
68
 
73
- mod.const_set(:Boolean, Grape::API::Boolean)
74
- end
69
+ mod.const_set(:Boolean, Grape::API::Boolean)
70
+ end
75
71
 
76
- def inject_api_helpers_to_mod(mod, &block)
77
- mod.extend(BaseHelper) unless mod.is_a?(BaseHelper)
78
- yield if block
79
- mod.api_changed(self)
80
- end
72
+ def inject_api_helpers_to_mod(mod, &block)
73
+ mod.extend(BaseHelper) unless mod.is_a?(BaseHelper)
74
+ yield if block
75
+ mod.api_changed(self)
81
76
  end
82
77
 
83
78
  # This module extends user defined helpers
@@ -100,7 +95,7 @@ module Grape
100
95
  def process_named_params
101
96
  return if @named_params.blank?
102
97
 
103
- api.namespace_stackable(:named_params, @named_params)
98
+ api.inheritable_setting.namespace_stackable[:named_params] = @named_params
104
99
  end
105
100
  end
106
101
  end
@@ -3,10 +3,6 @@
3
3
  module Grape
4
4
  module DSL
5
5
  module InsideRoute
6
- extend ActiveSupport::Concern
7
- include Grape::DSL::Settings
8
- include Grape::DSL::Headers
9
-
10
6
  # Denotes a situation where a DSL method has been invoked in a
11
7
  # filter which it should not yet be available in
12
8
  class MethodNotYetAvailable < StandardError; end
@@ -35,7 +31,7 @@ module Grape
35
31
  declared_hash(passed_params, options, declared_params, params_nested_path)
36
32
  end
37
33
 
38
- if (key_maps = namespace_stackable(:contract_key_map))
34
+ if (key_maps = inheritable_setting.namespace_stackable[:contract_key_map])
39
35
  key_maps.each { |key_map| key_map.write(passed_params, res) }
40
36
  end
41
37
 
@@ -59,7 +55,7 @@ module Grape
59
55
  end
60
56
 
61
57
  def declared_hash_attr(passed_params, options, declared_param, params_nested_path, memo)
62
- renamed_params = route_setting(:renamed_params) || {}
58
+ renamed_params = inheritable_setting.route[:renamed_params] || {}
63
59
  if declared_param.is_a?(Hash)
64
60
  declared_param.each_pair do |declared_parent_param, declared_children_params|
65
61
  params_nested_path_dup = params_nested_path.dup
@@ -123,10 +119,10 @@ module Grape
123
119
  def optioned_declared_params(include_parent_namespaces)
124
120
  declared_params = if include_parent_namespaces
125
121
  # Declared params including parent namespaces
126
- route_setting(:declared_params)
122
+ inheritable_setting.route[:declared_params]
127
123
  else
128
124
  # Declared params at current namespace
129
- namespace_stackable(:declared_params).last || []
125
+ inheritable_setting.namespace_stackable[:declared_params].last || []
130
126
  end
131
127
 
132
128
  raise ArgumentError, 'Tried to filter for declared parameters but none exist.' unless declared_params
@@ -168,7 +164,7 @@ module Grape
168
164
  # @param backtrace [Array<String>] The backtrace of the exception that caused the error.
169
165
  # @param original_exception [Exception] The original exception that caused the error.
170
166
  def error!(message, status = nil, additional_headers = nil, backtrace = nil, original_exception = nil)
171
- status = self.status(status || namespace_inheritable(:default_error_status))
167
+ status = self.status(status || inheritable_setting.namespace_inheritable[:default_error_status])
172
168
  headers = additional_headers.present? ? header.merge(additional_headers) : header
173
169
  throw :error,
174
170
  message: message,
@@ -178,24 +174,6 @@ module Grape
178
174
  original_exception: original_exception
179
175
  end
180
176
 
181
- # Creates a Rack response based on the provided message, status, and headers.
182
- # The content type in the headers is set to the default content type unless provided.
183
- # The message is HTML-escaped if the content type is 'text/html'.
184
- #
185
- # @param message [String] The content of the response.
186
- # @param status [Integer] The HTTP status code.
187
- # @params headers [Hash] (optional) Headers for the response
188
- # (default: {Rack::CONTENT_TYPE => content_type}).
189
- #
190
- # Returns:
191
- # A Rack::Response object containing the specified message, status, and headers.
192
- #
193
- def rack_response(message, status = 200, headers = { Rack::CONTENT_TYPE => content_type })
194
- Grape.deprecator.warn('The rack_response method has been deprecated, use error! instead.')
195
- message = Rack::Utils.escape_html(message) if headers[Rack::CONTENT_TYPE] == 'text/html'
196
- Rack::Response.new(Array.wrap(message), Rack::Utils.status_code(status), headers)
197
- end
198
-
199
177
  # Redirect to a new url.
200
178
  #
201
179
  # @param url [String] The url to be redirect.
@@ -359,8 +337,7 @@ module Grape
359
337
  # with: API::Entities::User,
360
338
  # admin: current_user.admin?
361
339
  # end
362
- def present(*args)
363
- options = args.count > 1 ? args.extract_options! : {}
340
+ def present(*args, **options)
364
341
  key, object = if args.count == 2 && args.first.is_a?(Symbol)
365
342
  args
366
343
  else
@@ -411,22 +388,22 @@ module Grape
411
388
  # @return [Class] the located Entity class, or nil if none is found
412
389
  def entity_class_for_obj(object, options)
413
390
  entity_class = options.delete(:with)
414
-
415
- if entity_class.nil?
416
- # entity class not explicitly defined, auto-detect from relation#klass or first object in the collection
417
- object_class = if object.respond_to?(:klass)
418
- object.klass
419
- else
420
- object.respond_to?(:first) ? object.first.class : object.class
421
- end
422
-
423
- object_class.ancestors.each do |potential|
424
- entity_class ||= (namespace_stackable_with_hash(:representations) || {})[potential]
425
- end
426
-
427
- entity_class ||= object_class.const_get(:Entity) if object_class.const_defined?(:Entity) && object_class.const_get(:Entity).respond_to?(:represent)
391
+ return entity_class if entity_class
392
+
393
+ # entity class not explicitly defined, auto-detect from relation#klass or first object in the collection
394
+ object_class = if object.respond_to?(:klass)
395
+ object.klass
396
+ else
397
+ object.respond_to?(:first) ? object.first.class : object.class
398
+ end
399
+
400
+ representations = inheritable_setting.namespace_stackable_with_hash(:representations)
401
+ if representations
402
+ potential = object_class.ancestors.detect { |potential| representations.key?(potential) }
403
+ entity_class = representations[potential] if potential
428
404
  end
429
405
 
406
+ entity_class = object_class.const_get(:Entity) if !entity_class && object_class.const_defined?(:Entity) && object_class.const_get(:Entity).respond_to?(:represent)
430
407
  entity_class
431
408
  end
432
409
 
@@ -3,18 +3,15 @@
3
3
  module Grape
4
4
  module DSL
5
5
  module Logger
6
- include Grape::DSL::Settings
7
-
8
- attr_writer :logger
9
-
10
6
  # Set or retrive the configured logger. If none was configured, this
11
7
  # method will create a new one, logging to stdout.
12
8
  # @param logger [Object] the new logger to use
13
9
  def logger(logger = nil)
10
+ global_settings = inheritable_setting.global
14
11
  if logger
15
- global_setting(:logger, logger)
12
+ global_settings[:logger] = logger
16
13
  else
17
- global_setting(:logger) || global_setting(:logger, ::Logger.new($stdout))
14
+ global_settings[:logger] || global_settings[:logger] = ::Logger.new($stdout)
18
15
  end
19
16
  end
20
17
  end
@@ -3,51 +3,33 @@
3
3
  module Grape
4
4
  module DSL
5
5
  module Middleware
6
- extend ActiveSupport::Concern
7
-
8
- include Grape::DSL::Configuration
9
-
10
- module ClassMethods
11
- # Apply a custom middleware to the API. Applies
12
- # to the current namespace and any children, but
13
- # not parents.
14
- #
15
- # @param middleware_class [Class] The class of the middleware you'd like
16
- # to inject.
17
- def use(middleware_class, *args, &block)
18
- arr = [:use, middleware_class, *args]
19
- arr << block if block
20
-
21
- namespace_stackable(:middleware, arr)
22
- end
23
-
24
- def insert(*args, &block)
25
- arr = [:insert, *args]
26
- arr << block if block
27
-
28
- namespace_stackable(:middleware, arr)
29
- end
30
-
31
- def insert_before(*args, &block)
32
- arr = [:insert_before, *args]
33
- arr << block if block
34
-
35
- namespace_stackable(:middleware, arr)
36
- end
6
+ # Apply a custom middleware to the API. Applies
7
+ # to the current namespace and any children, but
8
+ # not parents.
9
+ #
10
+ # @param middleware_class [Class] The class of the middleware you'd like
11
+ # to inject.
12
+ def use(middleware_class, *args, &block)
13
+ arr = [:use, middleware_class, *args]
14
+ arr << block if block
15
+
16
+ inheritable_setting.namespace_stackable[:middleware] = arr
17
+ end
37
18
 
38
- def insert_after(*args, &block)
39
- arr = [:insert_after, *args]
19
+ %i[insert insert_before insert_after].each do |method_name|
20
+ define_method method_name do |*args, &block|
21
+ arr = [method_name, *args]
40
22
  arr << block if block
41
23
 
42
- namespace_stackable(:middleware, arr)
24
+ inheritable_setting.namespace_stackable[:middleware] = arr
43
25
  end
26
+ end
44
27
 
45
- # Retrieve an array of the middleware classes
46
- # and arguments that are currently applied to the
47
- # application.
48
- def middleware
49
- namespace_stackable(:middleware) || []
50
- end
28
+ # Retrieve an array of the middleware classes
29
+ # and arguments that are currently applied to the
30
+ # application.
31
+ def middleware
32
+ inheritable_setting.namespace_stackable[:middleware] || []
51
33
  end
52
34
  end
53
35
  end
@@ -6,8 +6,6 @@ module Grape
6
6
  # and describe the parameters accepted by an endpoint, or all endpoints
7
7
  # within a namespace.
8
8
  module Parameters
9
- extend ActiveSupport::Concern
10
-
11
9
  # Set the module used to build the request.params.
12
10
  #
13
11
  # @param build_with the ParamBuilder module to use when building request.params
@@ -31,7 +29,7 @@ module Grape
31
29
  # end
32
30
  # end
33
31
  def build_with(build_with)
34
- @api.namespace_inheritable(:build_params_with, build_with)
32
+ @api.inheritable_setting.namespace_inheritable[:build_params_with] = build_with
35
33
  end
36
34
 
37
35
  # Include reusable params rules among current.
@@ -55,9 +53,8 @@ module Grape
55
53
  # Collection.page(params[:page]).per(params[:per_page])
56
54
  # end
57
55
  # end
58
- def use(*names)
59
- named_params = @api.namespace_stackable_with_hash(:named_params) || {}
60
- options = names.extract_options!
56
+ def use(*names, **options)
57
+ named_params = @api.inheritable_setting.namespace_stackable_with_hash(:named_params) || {}
61
58
  names.each do |name|
62
59
  params_block = named_params.fetch(name) do
63
60
  raise "Params :#{name} not found!"
@@ -125,10 +122,7 @@ module Grape
125
122
  # requires :name, type: String
126
123
  # end
127
124
  # end
128
- def requires(*attrs, &block)
129
- orig_attrs = attrs.clone
130
-
131
- opts = attrs.extract_options!.clone
125
+ def requires(*attrs, **opts, &block)
132
126
  opts[:presence] = { value: true, message: opts[:message] }
133
127
  opts = @group.deep_merge(opts) if instance_variable_defined?(:@group) && @group
134
128
 
@@ -136,7 +130,7 @@ module Grape
136
130
  require_required_and_optional_fields(attrs.first, opts)
137
131
  else
138
132
  validate_attributes(attrs, opts, &block)
139
- block ? new_scope(orig_attrs, &block) : push_declared_params(attrs, opts.slice(:as))
133
+ block ? new_scope(attrs, opts, &block) : push_declared_params(attrs, opts.slice(:as))
140
134
  end
141
135
  end
142
136
 
@@ -144,10 +138,7 @@ module Grape
144
138
  # endpoint.
145
139
  # @param (see #requires)
146
140
  # @option (see #requires)
147
- def optional(*attrs, &block)
148
- orig_attrs = attrs.clone
149
-
150
- opts = attrs.extract_options!.clone
141
+ def optional(*attrs, **opts, &block)
151
142
  type = opts[:type]
152
143
  opts = @group.deep_merge(opts) if instance_variable_defined?(:@group) && @group
153
144
 
@@ -162,7 +153,7 @@ module Grape
162
153
  else
163
154
  validate_attributes(attrs, opts, &block)
164
155
 
165
- block ? new_scope(orig_attrs, true, &block) : push_declared_params(attrs, opts.slice(:as))
156
+ block ? new_scope(attrs, opts, true, &block) : push_declared_params(attrs, opts.slice(:as))
166
157
  end
167
158
  end
168
159