grape 2.0.0 → 2.1.3

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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +77 -1
  3. data/README.md +362 -316
  4. data/UPGRADING.md +197 -7
  5. data/grape.gemspec +5 -6
  6. data/lib/grape/api/instance.rb +14 -11
  7. data/lib/grape/api.rb +19 -10
  8. data/lib/grape/content_types.rb +0 -2
  9. data/lib/grape/cookies.rb +2 -1
  10. data/lib/grape/dry_types.rb +0 -2
  11. data/lib/grape/dsl/desc.rb +22 -20
  12. data/lib/grape/dsl/headers.rb +1 -1
  13. data/lib/grape/dsl/inside_route.rb +46 -15
  14. data/lib/grape/dsl/parameters.rb +5 -4
  15. data/lib/grape/dsl/routing.rb +20 -4
  16. data/lib/grape/dsl/validations.rb +13 -0
  17. data/lib/grape/endpoint.rb +14 -17
  18. data/lib/grape/{util/env.rb → env.rb} +0 -5
  19. data/lib/grape/error_formatter/txt.rb +11 -10
  20. data/lib/grape/exceptions/base.rb +3 -3
  21. data/lib/grape/exceptions/validation.rb +0 -2
  22. data/lib/grape/exceptions/validation_array_errors.rb +1 -0
  23. data/lib/grape/exceptions/validation_errors.rb +2 -4
  24. data/lib/grape/extensions/hash.rb +5 -1
  25. data/lib/grape/http/headers.rb +18 -34
  26. data/lib/grape/{util/json.rb → json.rb} +1 -3
  27. data/lib/grape/locale/en.yml +3 -0
  28. data/lib/grape/middleware/auth/base.rb +0 -2
  29. data/lib/grape/middleware/auth/dsl.rb +0 -2
  30. data/lib/grape/middleware/base.rb +1 -3
  31. data/lib/grape/middleware/error.rb +55 -50
  32. data/lib/grape/middleware/formatter.rb +16 -13
  33. data/lib/grape/middleware/globals.rb +1 -3
  34. data/lib/grape/middleware/stack.rb +4 -5
  35. data/lib/grape/middleware/versioner/accept_version_header.rb +0 -2
  36. data/lib/grape/middleware/versioner/header.rb +17 -163
  37. data/lib/grape/middleware/versioner/param.rb +2 -4
  38. data/lib/grape/middleware/versioner/path.rb +1 -3
  39. data/lib/grape/namespace.rb +3 -4
  40. data/lib/grape/path.rb +24 -29
  41. data/lib/grape/request.rb +4 -12
  42. data/lib/grape/router/base_route.rb +39 -0
  43. data/lib/grape/router/greedy_route.rb +20 -0
  44. data/lib/grape/router/pattern.rb +39 -30
  45. data/lib/grape/router/route.rb +22 -59
  46. data/lib/grape/router.rb +32 -37
  47. data/lib/grape/util/accept_header_handler.rb +105 -0
  48. data/lib/grape/util/base_inheritable.rb +4 -4
  49. data/lib/grape/util/cache.rb +0 -3
  50. data/lib/grape/util/endpoint_configuration.rb +1 -1
  51. data/lib/grape/util/header.rb +13 -0
  52. data/lib/grape/util/inheritable_values.rb +0 -2
  53. data/lib/grape/util/lazy/block.rb +29 -0
  54. data/lib/grape/util/lazy/object.rb +45 -0
  55. data/lib/grape/util/lazy/value.rb +38 -0
  56. data/lib/grape/util/lazy/value_array.rb +21 -0
  57. data/lib/grape/util/lazy/value_enumerable.rb +34 -0
  58. data/lib/grape/util/lazy/value_hash.rb +21 -0
  59. data/lib/grape/util/media_type.rb +70 -0
  60. data/lib/grape/util/reverse_stackable_values.rb +1 -6
  61. data/lib/grape/util/stackable_values.rb +1 -6
  62. data/lib/grape/util/strict_hash_configuration.rb +3 -3
  63. data/lib/grape/validations/attributes_doc.rb +38 -36
  64. data/lib/grape/validations/attributes_iterator.rb +1 -0
  65. data/lib/grape/validations/contract_scope.rb +71 -0
  66. data/lib/grape/validations/params_scope.rb +22 -19
  67. data/lib/grape/validations/types/array_coercer.rb +0 -2
  68. data/lib/grape/validations/types/build_coercer.rb +69 -71
  69. data/lib/grape/validations/types/dry_type_coercer.rb +1 -11
  70. data/lib/grape/validations/types/json.rb +0 -2
  71. data/lib/grape/validations/types/primitive_coercer.rb +0 -2
  72. data/lib/grape/validations/types/set_coercer.rb +0 -3
  73. data/lib/grape/validations/types.rb +0 -3
  74. data/lib/grape/validations/validators/base.rb +1 -0
  75. data/lib/grape/validations/validators/default_validator.rb +5 -1
  76. data/lib/grape/validations/validators/exactly_one_of_validator.rb +1 -1
  77. data/lib/grape/validations/validators/length_validator.rb +42 -0
  78. data/lib/grape/validations/validators/values_validator.rb +6 -1
  79. data/lib/grape/validations.rb +3 -7
  80. data/lib/grape/version.rb +1 -1
  81. data/lib/grape/{util/xml.rb → xml.rb} +1 -1
  82. data/lib/grape.rb +30 -274
  83. metadata +30 -37
  84. data/lib/grape/eager_load.rb +0 -20
  85. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +0 -24
  86. data/lib/grape/router/attribute_translator.rb +0 -63
  87. data/lib/grape/util/lazy_block.rb +0 -27
  88. data/lib/grape/util/lazy_object.rb +0 -43
  89. data/lib/grape/util/lazy_value.rb +0 -91
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'stackable_values'
4
-
5
3
  module Grape
6
4
  module Util
7
5
  class ReverseStackableValues < StackableValues
@@ -10,10 +8,7 @@ module Grape
10
8
  def concat_values(inherited_value, new_value)
11
9
  return inherited_value unless new_value
12
10
 
13
- [].tap do |value|
14
- value.concat(new_value)
15
- value.concat(inherited_value)
16
- end
11
+ new_value + inherited_value
17
12
  end
18
13
  end
19
14
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base_inheritable'
4
-
5
3
  module Grape
6
4
  module Util
7
5
  class StackableValues < BaseInheritable
@@ -31,10 +29,7 @@ module Grape
31
29
  def concat_values(inherited_value, new_value)
32
30
  return inherited_value unless new_value
33
31
 
34
- [].tap do |value|
35
- value.concat(inherited_value)
36
- value.concat(new_value)
37
- end
32
+ inherited_value + new_value
38
33
  end
39
34
  end
40
35
  end
@@ -56,19 +56,19 @@ module Grape
56
56
  def self.nested_settings_methods(setting_name, new_config_class)
57
57
  new_config_class.class_eval do
58
58
  setting_name.each_pair do |key, value|
59
- define_method "#{key}_context" do
59
+ define_method :"#{key}_context" do
60
60
  @contexts[key] ||= Grape::Util::StrictHashConfiguration.config_class(*value).new
61
61
  end
62
62
 
63
63
  define_method key do |&block|
64
- send("#{key}_context").instance_exec(&block)
64
+ send(:"#{key}_context").instance_exec(&block)
65
65
  end
66
66
  end
67
67
 
68
68
  define_method :to_hash do
69
69
  @settings.to_hash.merge(
70
70
  setting_name.each_key.with_object({}) do |k, merge_hash|
71
- merge_hash[k] = send("#{k}_context").to_hash
71
+ merge_hash[k] = send(:"#{k}_context").to_hash
72
72
  end
73
73
  )
74
74
  end
@@ -2,56 +2,58 @@
2
2
 
3
3
  module Grape
4
4
  module Validations
5
- class ParamsScope
6
- # Documents parameters of an endpoint. If documentation isn't needed (for instance, it is an
7
- # internal API), the class only cleans up attributes to avoid junk in RAM.
8
- class AttributesDoc
9
- attr_accessor :type, :values
10
-
11
- # @param api [Grape::API::Instance]
12
- # @param scope [Validations::ParamsScope]
13
- def initialize(api, scope)
14
- @api = api
15
- @scope = scope
16
- @type = type
17
- end
5
+ # Documents parameters of an endpoint. If documentation isn't needed (for instance, it is an
6
+ # internal API), the class only cleans up attributes to avoid junk in RAM.
7
+
8
+ class AttributesDoc
9
+ attr_accessor :type, :values
10
+
11
+ # @param api [Grape::API::Instance]
12
+ # @param scope [Validations::ParamsScope]
13
+ def initialize(api, scope)
14
+ @api = api
15
+ @scope = scope
16
+ @type = type
17
+ end
18
18
 
19
- def extract_details(validations)
20
- details[:required] = validations.key?(:presence)
19
+ def extract_details(validations)
20
+ details[:required] = validations.key?(:presence)
21
21
 
22
- desc = validations.delete(:desc) || validations.delete(:description)
22
+ desc = validations.delete(:desc) || validations.delete(:description)
23
23
 
24
- details[:desc] = desc if desc
24
+ details[:desc] = desc if desc
25
25
 
26
- documentation = validations.delete(:documentation)
26
+ documentation = validations.delete(:documentation)
27
27
 
28
- details[:documentation] = documentation if documentation
28
+ details[:documentation] = documentation if documentation
29
29
 
30
- details[:default] = validations[:default] if validations.key?(:default)
31
- end
30
+ details[:default] = validations[:default] if validations.key?(:default)
32
31
 
33
- def document(attrs)
34
- return if @api.namespace_inheritable(:do_not_document)
32
+ details[:min_length] = validations[:length][:min] if validations.key?(:length) && validations[:length].key?(:min)
33
+ details[:max_length] = validations[:length][:max] if validations.key?(:length) && validations[:length].key?(:max)
34
+ end
35
35
 
36
- details[:type] = type.to_s if type
37
- details[:values] = values if values
36
+ def document(attrs)
37
+ return if @api.namespace_inheritable(:do_not_document)
38
38
 
39
- documented_attrs = attrs.each_with_object({}) do |name, memo|
40
- memo[@scope.full_name(name)] = details
41
- end
39
+ details[:type] = type.to_s if type
40
+ details[:values] = values if values
42
41
 
43
- @api.namespace_stackable(:params, documented_attrs)
42
+ documented_attrs = attrs.each_with_object({}) do |name, memo|
43
+ memo[@scope.full_name(name)] = details
44
44
  end
45
45
 
46
- def required
47
- details[:required]
48
- end
46
+ @api.namespace_stackable(:params, documented_attrs)
47
+ end
48
+
49
+ def required
50
+ details[:required]
51
+ end
49
52
 
50
- protected
53
+ protected
51
54
 
52
- def details
53
- @details ||= {}
54
- end
55
+ def details
56
+ @details ||= {}
55
57
  end
56
58
  end
57
59
  end
@@ -21,6 +21,7 @@ module Grape
21
21
  private
22
22
 
23
23
  def do_each(params_to_process, parent_indicies = [], &block)
24
+ @scope.reset_index # gets updated depending on the size of params_to_process
24
25
  params_to_process.each_with_index do |resource_params, index|
25
26
  # when we get arrays of arrays it means that target element located inside array
26
27
  # we need this because we want to know parent arrays indicies
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Validations
5
+ class ContractScope
6
+ # Declare the contract to be used for the endpoint's parameters.
7
+ # @param api [API] the API endpoint to modify.
8
+ # @param contract the contract or schema to be used for validation. Optional.
9
+ # @yield a block yielding a new schema class. Optional.
10
+ def initialize(api, contract = nil, &block)
11
+ # When block is passed, the first arg is either schema or nil.
12
+ contract = Dry::Schema.Params(parent: contract, &block) if block
13
+
14
+ if contract.respond_to?(:schema)
15
+ # It's a Dry::Validation::Contract, then.
16
+ contract = contract.new
17
+ key_map = contract.schema.key_map
18
+ else
19
+ # Dry::Schema::Processor, hopefully.
20
+ key_map = contract.key_map
21
+ end
22
+
23
+ api.namespace_stackable(:contract_key_map, key_map)
24
+
25
+ validator_options = {
26
+ validator_class: Validator,
27
+ opts: { schema: contract }
28
+ }
29
+
30
+ api.namespace_stackable(:validations, validator_options)
31
+ end
32
+
33
+ class Validator
34
+ attr_reader :schema
35
+
36
+ def initialize(*_args, schema:)
37
+ @schema = schema
38
+ end
39
+
40
+ # Validates a given request.
41
+ # @param request [Grape::Request] the request currently being handled
42
+ # @raise [Grape::Exceptions::ValidationArrayErrors] if validation failed
43
+ # @return [void]
44
+ def validate(request)
45
+ res = schema.call(request.params)
46
+
47
+ if res.success?
48
+ request.params.deep_merge!(res.to_h)
49
+ return
50
+ end
51
+
52
+ errors = []
53
+
54
+ res.errors.messages.each do |message|
55
+ full_name = message.path.first.to_s
56
+
57
+ full_name += "[#{message.path[1..].join('][')}]" if message.path.size > 1
58
+
59
+ errors << Grape::Exceptions::Validation.new(params: [full_name], message: message.text)
60
+ end
61
+
62
+ raise Grape::Exceptions::ValidationArrayErrors.new(errors)
63
+ end
64
+
65
+ def fail_fast?
66
+ false
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'attributes_doc'
4
-
5
3
  module Grape
6
4
  module Validations
7
5
  class ParamsScope
@@ -95,9 +93,7 @@ module Grape
95
93
 
96
94
  def meets_dependency?(params, request_params)
97
95
  return true unless @dependent_on
98
-
99
96
  return false if @parent.present? && !@parent.meets_dependency?(@parent.params(request_params), request_params)
100
-
101
97
  return params.any? { |param| meets_dependency?(param, request_params) } if params.is_a?(Array)
102
98
 
103
99
  meets_hash_dependency?(params)
@@ -105,7 +101,6 @@ module Grape
105
101
 
106
102
  def attr_meets_dependency?(params)
107
103
  return true unless @dependent_on
108
-
109
104
  return false if @parent.present? && !@parent.attr_meets_dependency?(params)
110
105
 
111
106
  meets_hash_dependency?(params)
@@ -171,6 +166,10 @@ module Grape
171
166
  !@optional
172
167
  end
173
168
 
169
+ def reset_index
170
+ @index = nil
171
+ end
172
+
174
173
  protected
175
174
 
176
175
  # Adds a parameter declaration to our list of validations.
@@ -191,7 +190,13 @@ module Grape
191
190
  #
192
191
  # @return [Array<Symbol>] the nesting/path of the current parameter scope
193
192
  def full_path
194
- nested? ? @parent.full_path + [@element] : []
193
+ if nested?
194
+ (@parent.full_path + [@element])
195
+ elsif lateral?
196
+ @parent.full_path
197
+ else
198
+ []
199
+ end
195
200
  end
196
201
 
197
202
  private
@@ -211,11 +216,11 @@ module Grape
211
216
 
212
217
  def require_required_and_optional_fields(context, opts)
213
218
  if context == :all
214
- optional_fields = Array(opts[:except])
215
- required_fields = opts[:using].keys - optional_fields
219
+ optional_fields = Array.wrap(opts[:except])
220
+ required_fields = opts[:using].keys.delete_if { |f| optional_fields.include?(f) }
216
221
  else # context == :none
217
- required_fields = Array(opts[:except])
218
- optional_fields = opts[:using].keys - required_fields
222
+ required_fields = Array.wrap(opts[:except])
223
+ optional_fields = opts[:using].keys.delete_if { |f| required_fields.include?(f) }
219
224
  end
220
225
  required_fields.each do |field|
221
226
  field_opts = opts[:using][field]
@@ -231,7 +236,10 @@ module Grape
231
236
 
232
237
  def require_optional_fields(context, opts)
233
238
  optional_fields = opts[:using].keys
234
- optional_fields -= Array(opts[:except]) unless context == :all
239
+ unless context == :all
240
+ except_fields = Array.wrap(opts[:except])
241
+ optional_fields.delete_if { |f| except_fields.include?(f) }
242
+ end
235
243
  optional_fields.each do |field|
236
244
  field_opts = opts[:using][field]
237
245
  optional(field, field_opts) if field_opts
@@ -266,6 +274,7 @@ module Grape
266
274
  parent: self,
267
275
  optional: optional,
268
276
  type: type || Array,
277
+ group: @group,
269
278
  &block
270
279
  )
271
280
  end
@@ -295,12 +304,7 @@ module Grape
295
304
  # `optional` invocation that opened this scope.
296
305
  # @yield parameter scope
297
306
  def new_group_scope(attrs, &block)
298
- self.class.new(
299
- api: @api,
300
- parent: self,
301
- group: attrs.first,
302
- &block
303
- )
307
+ self.class.new(api: @api, parent: self, group: attrs.first, &block)
304
308
  end
305
309
 
306
310
  # Pushes declared params to parent or settings
@@ -463,8 +467,7 @@ module Grape
463
467
  raise Grape::Exceptions::IncompatibleOptionValues.new(:default, default, :values, values) if values && !values.is_a?(Proc) && !Array(default).all? { |def_val| values.include?(def_val) }
464
468
 
465
469
  if except_values && !except_values.is_a?(Proc) && Array(default).any? { |def_val| except_values.include?(def_val) }
466
- raise Grape::Exceptions::IncompatibleOptionValues.new(:default, default, :except, except_values) \
467
-
470
+ raise Grape::Exceptions::IncompatibleOptionValues.new(:default, default, :except, except_values)
468
471
  end
469
472
 
470
473
  return unless excepts && !excepts.is_a?(Proc)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'dry_type_coercer'
4
-
5
3
  module Grape
6
4
  module Validations
7
5
  module Types
@@ -1,94 +1,92 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'array_coercer'
4
- require_relative 'set_coercer'
5
- require_relative 'primitive_coercer'
6
-
7
3
  module Grape
8
4
  module Validations
9
5
  module Types
10
- # Chooses the best coercer for the given type. For example, if the type
11
- # is Integer, it will return a coercer which will be able to coerce a value
12
- # to the integer.
13
- #
14
- # There are a few very special coercers which might be returned.
15
- #
16
- # +Grape::Types::MultipleTypeCoercer+ is a coercer which is returned when
17
- # the given type implies values in an array with different types.
18
- # For example, +[Integer, String]+ allows integer and string values in
19
- # an array.
20
- #
21
- # +Grape::Types::CustomTypeCoercer+ is a coercer which is returned when
22
- # a method is specified by a user with +coerce_with+ option or the user
23
- # specifies a custom type which implements requirments of
24
- # +Grape::Types::CustomTypeCoercer+.
25
- #
26
- # +Grape::Types::CustomTypeCollectionCoercer+ is a very similar to the
27
- # previous one, but it expects an array or set of values having a custom
28
- # type implemented by the user.
29
- #
30
- # There is also a group of custom types implemented by Grape, check
31
- # +Grape::Validations::Types::SPECIAL+ to get the full list.
32
- #
33
- # @param type [Class] the type to which input strings
34
- # should be coerced
35
- # @param method [Class,#call] the coercion method to use
36
- # @return [Object] object to be used
37
- # for coercion and type validation
38
- def self.build_coercer(type, method: nil, strict: false)
39
- cache_instance(type, method, strict) do
40
- create_coercer_instance(type, method, strict)
6
+ module BuildCoercer
7
+ # Chooses the best coercer for the given type. For example, if the type
8
+ # is Integer, it will return a coercer which will be able to coerce a value
9
+ # to the integer.
10
+ #
11
+ # There are a few very special coercers which might be returned.
12
+ #
13
+ # +Grape::Types::MultipleTypeCoercer+ is a coercer which is returned when
14
+ # the given type implies values in an array with different types.
15
+ # For example, +[Integer, String]+ allows integer and string values in
16
+ # an array.
17
+ #
18
+ # +Grape::Types::CustomTypeCoercer+ is a coercer which is returned when
19
+ # a method is specified by a user with +coerce_with+ option or the user
20
+ # specifies a custom type which implements requirments of
21
+ # +Grape::Types::CustomTypeCoercer+.
22
+ #
23
+ # +Grape::Types::CustomTypeCollectionCoercer+ is a very similar to the
24
+ # previous one, but it expects an array or set of values having a custom
25
+ # type implemented by the user.
26
+ #
27
+ # There is also a group of custom types implemented by Grape, check
28
+ # +Grape::Validations::Types::SPECIAL+ to get the full list.
29
+ #
30
+ # @param type [Class] the type to which input strings
31
+ # should be coerced
32
+ # @param method [Class,#call] the coercion method to use
33
+ # @return [Object] object to be used
34
+ # for coercion and type validation
35
+ def self.build_coercer(type, method: nil, strict: false)
36
+ cache_instance(type, method, strict) do
37
+ create_coercer_instance(type, method, strict)
38
+ end
41
39
  end
42
- end
43
40
 
44
- def self.create_coercer_instance(type, method, strict)
45
- # Maps a custom type provided by Grape, it doesn't map types wrapped by collections!!!
46
- type = Types.map_special(type)
41
+ def self.create_coercer_instance(type, method, strict)
42
+ # Maps a custom type provided by Grape, it doesn't map types wrapped by collections!!!
43
+ type = Types.map_special(type)
47
44
 
48
- # Use a special coercer for multiply-typed parameters.
49
- if Types.multiple?(type)
50
- MultipleTypeCoercer.new(type, method)
45
+ # Use a special coercer for multiply-typed parameters.
46
+ if Types.multiple?(type)
47
+ MultipleTypeCoercer.new(type, method)
51
48
 
52
- # Use a special coercer for custom types and coercion methods.
53
- elsif method || Types.custom?(type)
54
- CustomTypeCoercer.new(type, method)
49
+ # Use a special coercer for custom types and coercion methods.
50
+ elsif method || Types.custom?(type)
51
+ CustomTypeCoercer.new(type, method)
55
52
 
56
- # Special coercer for collections of types that implement a parse method.
57
- # CustomTypeCoercer (above) already handles such types when an explicit coercion
58
- # method is supplied.
59
- elsif Types.collection_of_custom?(type)
60
- Types::CustomTypeCollectionCoercer.new(
61
- Types.map_special(type.first), type.is_a?(Set)
62
- )
63
- else
64
- DryTypeCoercer.coercer_instance_for(type, strict)
53
+ # Special coercer for collections of types that implement a parse method.
54
+ # CustomTypeCoercer (above) already handles such types when an explicit coercion
55
+ # method is supplied.
56
+ elsif Types.collection_of_custom?(type)
57
+ Types::CustomTypeCollectionCoercer.new(
58
+ Types.map_special(type.first), type.is_a?(Set)
59
+ )
60
+ else
61
+ DryTypeCoercer.coercer_instance_for(type, strict)
62
+ end
65
63
  end
66
- end
67
64
 
68
- def self.cache_instance(type, method, strict, &_block)
69
- key = cache_key(type, method, strict)
65
+ def self.cache_instance(type, method, strict, &_block)
66
+ key = cache_key(type, method, strict)
70
67
 
71
- return @__cache[key] if @__cache.key?(key)
68
+ return @__cache[key] if @__cache.key?(key)
72
69
 
73
- instance = yield
70
+ instance = yield
74
71
 
75
- @__cache_write_lock.synchronize do
76
- @__cache[key] = instance
77
- end
72
+ @__cache_write_lock.synchronize do
73
+ @__cache[key] = instance
74
+ end
78
75
 
79
- instance
80
- end
76
+ instance
77
+ end
81
78
 
82
- def self.cache_key(type, method, strict)
83
- [type, method, strict].each_with_object(+'_') do |val, memo|
84
- next if val.nil?
79
+ def self.cache_key(type, method, strict)
80
+ [type, method, strict].each_with_object(+'_') do |val, memo|
81
+ next if val.nil?
85
82
 
86
- memo << '_' << val.to_s
83
+ memo << '_' << val.to_s
84
+ end
87
85
  end
88
- end
89
86
 
90
- instance_variable_set(:@__cache, {})
91
- instance_variable_set(:@__cache_write_lock, Mutex.new)
87
+ instance_variable_set(:@__cache, {})
88
+ instance_variable_set(:@__cache_write_lock, Mutex.new)
89
+ end
92
90
  end
93
91
  end
94
92
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry-types'
4
-
5
3
  module DryTypes
6
4
  # Call +Dry.Types()+ to add all registered types to +DryTypes+ which is
7
5
  # a container in this case. Check documentation for more information
@@ -24,9 +22,7 @@ module Grape
24
22
  # collection_coercer_for(Array)
25
23
  # #=> Grape::Validations::Types::ArrayCoercer
26
24
  def collection_coercer_for(type)
27
- collection_coercers.fetch(type) do
28
- DryTypeCoercer.collection_coercers[type] = Grape::Validations::Types.const_get("#{type.name.camelize}Coercer")
29
- end
25
+ Grape::Validations::Types.const_get(:"#{type.name.camelize}Coercer")
30
26
  end
31
27
 
32
28
  # Returns an instance of a coercer for a given type
@@ -37,12 +33,6 @@ module Grape
37
33
  # so we need to figure out the actual type
38
34
  collection_coercer_for(type.class).new(type, strict)
39
35
  end
40
-
41
- protected
42
-
43
- def collection_coercers
44
- @collection_coercers ||= {}
45
- end
46
36
  end
47
37
 
48
38
  def initialize(type, strict = false)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json'
4
-
5
3
  module Grape
6
4
  module Validations
7
5
  module Types
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'dry_type_coercer'
4
-
5
3
  module Grape
6
4
  module Validations
7
5
  module Types
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'set'
4
- require_relative 'array_coercer'
5
-
6
3
  module Grape
7
4
  module Validations
8
5
  module Types
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'grape/validations/types/json'
4
- require 'grape/validations/types/file'
5
-
6
3
  module Grape
7
4
  module Validations
8
5
  # Module for code related to grape's system for
@@ -59,6 +59,7 @@ module Grape
59
59
  end
60
60
 
61
61
  def self.inherited(klass)
62
+ super
62
63
  return if klass.name.blank?
63
64
 
64
65
  short_validator_name = klass.name.demodulize.underscore.delete_suffix('_validator')
@@ -11,7 +11,11 @@ module Grape
11
11
 
12
12
  def validate_param!(attr_name, params)
13
13
  params[attr_name] = if @default.is_a? Proc
14
- @default.call
14
+ if @default.parameters.empty?
15
+ @default.call
16
+ else
17
+ @default.call(params)
18
+ end
15
19
  elsif @default.frozen? || !@default.duplicable?
16
20
  @default
17
21
  else
@@ -7,7 +7,7 @@ module Grape
7
7
  def validate_params!(params)
8
8
  keys = keys_in_common(params)
9
9
  return if keys.length == 1
10
- raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:exactly_one)) if keys.length.zero?
10
+ raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:exactly_one)) if keys.empty?
11
11
 
12
12
  raise Grape::Exceptions::Validation.new(params: keys, message: message(:mutual_exclusion))
13
13
  end