grape 2.0.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +96 -1
  3. data/README.md +364 -317
  4. data/UPGRADING.md +205 -7
  5. data/grape.gemspec +7 -7
  6. data/lib/grape/api/instance.rb +14 -11
  7. data/lib/grape/api.rb +19 -10
  8. data/lib/grape/content_types.rb +13 -10
  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/helpers.rb +7 -3
  14. data/lib/grape/dsl/inside_route.rb +51 -15
  15. data/lib/grape/dsl/parameters.rb +5 -4
  16. data/lib/grape/dsl/request_response.rb +14 -18
  17. data/lib/grape/dsl/routing.rb +20 -4
  18. data/lib/grape/dsl/validations.rb +13 -0
  19. data/lib/grape/endpoint.rb +43 -35
  20. data/lib/grape/{util/env.rb → env.rb} +0 -5
  21. data/lib/grape/error_formatter/json.rb +13 -4
  22. data/lib/grape/error_formatter/txt.rb +11 -10
  23. data/lib/grape/error_formatter.rb +13 -25
  24. data/lib/grape/exceptions/base.rb +3 -3
  25. data/lib/grape/exceptions/validation.rb +0 -2
  26. data/lib/grape/exceptions/validation_array_errors.rb +1 -0
  27. data/lib/grape/exceptions/validation_errors.rb +2 -4
  28. data/lib/grape/extensions/hash.rb +5 -1
  29. data/lib/grape/formatter.rb +15 -25
  30. data/lib/grape/http/headers.rb +18 -34
  31. data/lib/grape/{util/json.rb → json.rb} +1 -3
  32. data/lib/grape/locale/en.yml +4 -0
  33. data/lib/grape/middleware/auth/base.rb +0 -2
  34. data/lib/grape/middleware/auth/dsl.rb +0 -2
  35. data/lib/grape/middleware/base.rb +14 -15
  36. data/lib/grape/middleware/error.rb +61 -54
  37. data/lib/grape/middleware/formatter.rb +18 -15
  38. data/lib/grape/middleware/globals.rb +1 -3
  39. data/lib/grape/middleware/stack.rb +4 -5
  40. data/lib/grape/middleware/versioner/accept_version_header.rb +8 -33
  41. data/lib/grape/middleware/versioner/header.rb +62 -123
  42. data/lib/grape/middleware/versioner/param.rb +5 -23
  43. data/lib/grape/middleware/versioner/path.rb +11 -33
  44. data/lib/grape/middleware/versioner.rb +5 -14
  45. data/lib/grape/middleware/versioner_helpers.rb +75 -0
  46. data/lib/grape/namespace.rb +3 -4
  47. data/lib/grape/parser.rb +8 -24
  48. data/lib/grape/path.rb +24 -29
  49. data/lib/grape/request.rb +4 -12
  50. data/lib/grape/router/base_route.rb +39 -0
  51. data/lib/grape/router/greedy_route.rb +20 -0
  52. data/lib/grape/router/pattern.rb +39 -30
  53. data/lib/grape/router/route.rb +22 -59
  54. data/lib/grape/router.rb +32 -37
  55. data/lib/grape/util/base_inheritable.rb +4 -4
  56. data/lib/grape/util/cache.rb +0 -3
  57. data/lib/grape/util/endpoint_configuration.rb +1 -1
  58. data/lib/grape/util/header.rb +13 -0
  59. data/lib/grape/util/inheritable_values.rb +0 -2
  60. data/lib/grape/util/lazy/block.rb +29 -0
  61. data/lib/grape/util/lazy/object.rb +45 -0
  62. data/lib/grape/util/lazy/value.rb +38 -0
  63. data/lib/grape/util/lazy/value_array.rb +21 -0
  64. data/lib/grape/util/lazy/value_enumerable.rb +34 -0
  65. data/lib/grape/util/lazy/value_hash.rb +21 -0
  66. data/lib/grape/util/media_type.rb +70 -0
  67. data/lib/grape/util/reverse_stackable_values.rb +1 -6
  68. data/lib/grape/util/stackable_values.rb +1 -6
  69. data/lib/grape/util/strict_hash_configuration.rb +3 -3
  70. data/lib/grape/validations/attributes_doc.rb +38 -36
  71. data/lib/grape/validations/attributes_iterator.rb +1 -0
  72. data/lib/grape/validations/contract_scope.rb +71 -0
  73. data/lib/grape/validations/params_scope.rb +22 -19
  74. data/lib/grape/validations/types/array_coercer.rb +0 -2
  75. data/lib/grape/validations/types/build_coercer.rb +69 -71
  76. data/lib/grape/validations/types/dry_type_coercer.rb +1 -11
  77. data/lib/grape/validations/types/json.rb +0 -2
  78. data/lib/grape/validations/types/primitive_coercer.rb +0 -2
  79. data/lib/grape/validations/types/set_coercer.rb +0 -3
  80. data/lib/grape/validations/types.rb +0 -3
  81. data/lib/grape/validations/validators/base.rb +1 -0
  82. data/lib/grape/validations/validators/default_validator.rb +5 -1
  83. data/lib/grape/validations/validators/exactly_one_of_validator.rb +1 -1
  84. data/lib/grape/validations/validators/length_validator.rb +49 -0
  85. data/lib/grape/validations/validators/values_validator.rb +6 -1
  86. data/lib/grape/validations.rb +3 -7
  87. data/lib/grape/version.rb +1 -1
  88. data/lib/grape/{util/xml.rb → xml.rb} +1 -1
  89. data/lib/grape.rb +30 -274
  90. metadata +31 -38
  91. data/lib/grape/eager_load.rb +0 -20
  92. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +0 -24
  93. data/lib/grape/router/attribute_translator.rb +0 -63
  94. data/lib/grape/util/lazy_block.rb +0 -27
  95. data/lib/grape/util/lazy_object.rb +0 -43
  96. data/lib/grape/util/lazy_value.rb +0 -91
  97. data/lib/grape/util/registrable.rb +0 -15
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Util
5
+ class MediaType
6
+ attr_reader :type, :subtype, :vendor, :version, :format
7
+
8
+ # based on the HTTP Accept header with the pattern:
9
+ # application/vnd.:vendor-:version+:format
10
+ VENDOR_VERSION_HEADER_REGEX = /\Avnd\.(?<vendor>[a-z0-9.\-_!^]+?)(?:-(?<version>[a-z0-9*.]+))?(?:\+(?<format>[a-z0-9*\-.]+))?\z/.freeze
11
+
12
+ def initialize(type:, subtype:)
13
+ @type = type
14
+ @subtype = subtype
15
+ VENDOR_VERSION_HEADER_REGEX.match(subtype) do |m|
16
+ @vendor = m[:vendor]
17
+ @version = m[:version]
18
+ @format = m[:format]
19
+ end
20
+ end
21
+
22
+ def ==(other)
23
+ eql?(other)
24
+ end
25
+
26
+ def eql?(other)
27
+ self.class == other.class &&
28
+ other.type == type &&
29
+ other.subtype == subtype &&
30
+ other.vendor == vendor &&
31
+ other.version == version &&
32
+ other.format == format
33
+ end
34
+
35
+ def hash
36
+ [self.class, type, subtype, vendor, version, format].hash
37
+ end
38
+
39
+ class << self
40
+ def best_quality(header, available_media_types)
41
+ parse(best_quality_media_type(header, available_media_types))
42
+ end
43
+
44
+ def parse(media_type)
45
+ return if media_type.blank?
46
+
47
+ type, subtype = media_type.split('/', 2)
48
+ return if type.blank? || subtype.blank?
49
+
50
+ new(type: type, subtype: subtype)
51
+ end
52
+
53
+ def match?(media_type)
54
+ return false if media_type.blank?
55
+
56
+ subtype = media_type.split('/', 2).last
57
+ return false if subtype.blank?
58
+
59
+ VENDOR_VERSION_HEADER_REGEX.match?(subtype)
60
+ end
61
+
62
+ def best_quality_media_type(header, available_media_types)
63
+ header.blank? ? available_media_types.first : Rack::Utils.best_q_match(header, available_media_types)
64
+ end
65
+ end
66
+
67
+ private_class_method :best_quality_media_type
68
+ end
69
+ end
70
+ end
@@ -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