grape 1.2.5 → 1.4.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 (262) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -0
  3. data/LICENSE +1 -1
  4. data/README.md +53 -16
  5. data/UPGRADING.md +231 -23
  6. data/grape.gemspec +10 -1
  7. data/lib/grape.rb +6 -7
  8. data/lib/grape/api.rb +4 -2
  9. data/lib/grape/api/helpers.rb +2 -0
  10. data/lib/grape/api/instance.rb +36 -33
  11. data/lib/grape/config.rb +2 -0
  12. data/lib/grape/content_types.rb +34 -0
  13. data/lib/grape/cookies.rb +2 -0
  14. data/lib/grape/dsl/api.rb +2 -0
  15. data/lib/grape/dsl/callbacks.rb +2 -0
  16. data/lib/grape/dsl/configuration.rb +2 -0
  17. data/lib/grape/dsl/desc.rb +2 -0
  18. data/lib/grape/dsl/headers.rb +2 -0
  19. data/lib/grape/dsl/helpers.rb +4 -2
  20. data/lib/grape/dsl/inside_route.rb +83 -34
  21. data/lib/grape/dsl/logger.rb +2 -0
  22. data/lib/grape/dsl/middleware.rb +2 -0
  23. data/lib/grape/dsl/parameters.rb +8 -6
  24. data/lib/grape/dsl/request_response.rb +4 -2
  25. data/lib/grape/dsl/routing.rb +9 -5
  26. data/lib/grape/dsl/settings.rb +7 -1
  27. data/lib/grape/dsl/validations.rb +20 -1
  28. data/lib/grape/eager_load.rb +3 -1
  29. data/lib/grape/endpoint.rb +21 -13
  30. data/lib/grape/error_formatter.rb +3 -1
  31. data/lib/grape/error_formatter/base.rb +2 -0
  32. data/lib/grape/error_formatter/json.rb +2 -0
  33. data/lib/grape/error_formatter/txt.rb +2 -0
  34. data/lib/grape/error_formatter/xml.rb +2 -0
  35. data/lib/grape/exceptions/base.rb +11 -13
  36. data/lib/grape/exceptions/incompatible_option_values.rb +2 -0
  37. data/lib/grape/exceptions/invalid_accept_header.rb +2 -0
  38. data/lib/grape/exceptions/invalid_formatter.rb +2 -0
  39. data/lib/grape/exceptions/invalid_message_body.rb +2 -0
  40. data/lib/grape/exceptions/invalid_response.rb +2 -0
  41. data/lib/grape/exceptions/invalid_version_header.rb +2 -0
  42. data/lib/grape/exceptions/invalid_versioner_option.rb +2 -0
  43. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +2 -0
  44. data/lib/grape/exceptions/method_not_allowed.rb +2 -0
  45. data/lib/grape/exceptions/missing_group_type.rb +2 -0
  46. data/lib/grape/exceptions/missing_mime_type.rb +2 -0
  47. data/lib/grape/exceptions/missing_option.rb +2 -0
  48. data/lib/grape/exceptions/missing_vendor_option.rb +2 -0
  49. data/lib/grape/exceptions/unknown_options.rb +2 -0
  50. data/lib/grape/exceptions/unknown_parameter.rb +2 -0
  51. data/lib/grape/exceptions/unknown_validator.rb +2 -0
  52. data/lib/grape/exceptions/unsupported_group_type.rb +2 -0
  53. data/lib/grape/exceptions/validation.rb +3 -1
  54. data/lib/grape/exceptions/validation_array_errors.rb +2 -0
  55. data/lib/grape/exceptions/validation_errors.rb +13 -12
  56. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +4 -3
  57. data/lib/grape/extensions/deep_mergeable_hash.rb +2 -0
  58. data/lib/grape/extensions/deep_symbolize_hash.rb +2 -0
  59. data/lib/grape/extensions/hash.rb +2 -0
  60. data/lib/grape/extensions/hashie/mash.rb +2 -0
  61. data/lib/grape/formatter.rb +5 -3
  62. data/lib/grape/formatter/json.rb +2 -0
  63. data/lib/grape/formatter/serializable_hash.rb +2 -0
  64. data/lib/grape/formatter/txt.rb +2 -0
  65. data/lib/grape/formatter/xml.rb +2 -0
  66. data/lib/grape/http/headers.rb +50 -18
  67. data/lib/grape/middleware/auth/base.rb +2 -0
  68. data/lib/grape/middleware/auth/dsl.rb +2 -0
  69. data/lib/grape/middleware/auth/strategies.rb +2 -0
  70. data/lib/grape/middleware/auth/strategy_info.rb +2 -0
  71. data/lib/grape/middleware/base.rb +7 -7
  72. data/lib/grape/middleware/error.rb +3 -1
  73. data/lib/grape/middleware/filter.rb +2 -0
  74. data/lib/grape/middleware/formatter.rb +8 -6
  75. data/lib/grape/middleware/globals.rb +2 -0
  76. data/lib/grape/middleware/helpers.rb +2 -0
  77. data/lib/grape/middleware/stack.rb +4 -1
  78. data/lib/grape/middleware/versioner.rb +2 -0
  79. data/lib/grape/middleware/versioner/accept_version_header.rb +2 -0
  80. data/lib/grape/middleware/versioner/header.rb +6 -4
  81. data/lib/grape/middleware/versioner/param.rb +3 -1
  82. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +4 -1
  83. data/lib/grape/middleware/versioner/path.rb +3 -1
  84. data/lib/grape/namespace.rb +14 -2
  85. data/lib/grape/parser.rb +3 -1
  86. data/lib/grape/parser/json.rb +2 -0
  87. data/lib/grape/parser/xml.rb +2 -0
  88. data/lib/grape/path.rb +15 -3
  89. data/lib/grape/presenters/presenter.rb +2 -0
  90. data/lib/grape/request.rb +15 -8
  91. data/lib/grape/router.rb +30 -29
  92. data/lib/grape/router/attribute_translator.rb +39 -8
  93. data/lib/grape/router/pattern.rb +20 -16
  94. data/lib/grape/router/route.rb +12 -26
  95. data/lib/grape/{serve_file → serve_stream}/file_body.rb +3 -1
  96. data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +3 -1
  97. data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +10 -8
  98. data/lib/grape/util/base_inheritable.rb +15 -6
  99. data/lib/grape/util/cache.rb +20 -0
  100. data/lib/grape/util/endpoint_configuration.rb +2 -0
  101. data/lib/grape/util/env.rb +19 -17
  102. data/lib/grape/util/inheritable_setting.rb +2 -0
  103. data/lib/grape/util/inheritable_values.rb +2 -0
  104. data/lib/grape/util/json.rb +2 -0
  105. data/lib/grape/util/lazy_block.rb +2 -0
  106. data/lib/grape/util/lazy_object.rb +43 -0
  107. data/lib/grape/util/lazy_value.rb +2 -0
  108. data/lib/grape/util/registrable.rb +2 -0
  109. data/lib/grape/util/reverse_stackable_values.rb +4 -0
  110. data/lib/grape/util/stackable_values.rb +10 -20
  111. data/lib/grape/util/strict_hash_configuration.rb +2 -0
  112. data/lib/grape/util/xml.rb +2 -0
  113. data/lib/grape/validations.rb +2 -0
  114. data/lib/grape/validations/attributes_iterator.rb +3 -3
  115. data/lib/grape/validations/multiple_attributes_iterator.rb +2 -0
  116. data/lib/grape/validations/params_scope.rb +27 -14
  117. data/lib/grape/validations/single_attribute_iterator.rb +13 -2
  118. data/lib/grape/validations/types.rb +12 -34
  119. data/lib/grape/validations/types/array_coercer.rb +65 -0
  120. data/lib/grape/validations/types/build_coercer.rb +47 -49
  121. data/lib/grape/validations/types/custom_type_coercer.rb +15 -49
  122. data/lib/grape/validations/types/custom_type_collection_coercer.rb +10 -25
  123. data/lib/grape/validations/types/dry_type_coercer.rb +76 -0
  124. data/lib/grape/validations/types/file.rb +22 -18
  125. data/lib/grape/validations/types/json.rb +46 -39
  126. data/lib/grape/validations/types/multiple_type_coercer.rb +14 -33
  127. data/lib/grape/validations/types/primitive_coercer.rb +67 -0
  128. data/lib/grape/validations/types/set_coercer.rb +40 -0
  129. data/lib/grape/validations/types/variant_collection_coercer.rb +5 -13
  130. data/lib/grape/validations/validator_factory.rb +2 -0
  131. data/lib/grape/validations/validators/all_or_none.rb +3 -1
  132. data/lib/grape/validations/validators/allow_blank.rb +3 -1
  133. data/lib/grape/validations/validators/as.rb +2 -0
  134. data/lib/grape/validations/validators/at_least_one_of.rb +3 -1
  135. data/lib/grape/validations/validators/base.rb +8 -5
  136. data/lib/grape/validations/validators/coerce.rb +39 -29
  137. data/lib/grape/validations/validators/default.rb +2 -1
  138. data/lib/grape/validations/validators/exactly_one_of.rb +6 -2
  139. data/lib/grape/validations/validators/except_values.rb +3 -1
  140. data/lib/grape/validations/validators/multiple_params_base.rb +2 -0
  141. data/lib/grape/validations/validators/mutual_exclusion.rb +3 -1
  142. data/lib/grape/validations/validators/presence.rb +3 -1
  143. data/lib/grape/validations/validators/regexp.rb +4 -2
  144. data/lib/grape/validations/validators/same_as.rb +6 -3
  145. data/lib/grape/validations/validators/values.rb +17 -5
  146. data/lib/grape/version.rb +3 -1
  147. data/spec/grape/api/custom_validations_spec.rb +5 -3
  148. data/spec/grape/api/deeply_included_options_spec.rb +2 -0
  149. data/spec/grape/api/defines_boolean_in_params_spec.rb +5 -3
  150. data/spec/grape/api/inherited_helpers_spec.rb +2 -0
  151. data/spec/grape/api/instance_spec.rb +104 -0
  152. data/spec/grape/api/invalid_format_spec.rb +2 -0
  153. data/spec/grape/api/namespace_parameters_in_route_spec.rb +2 -0
  154. data/spec/grape/api/nested_helpers_spec.rb +2 -0
  155. data/spec/grape/api/optional_parameters_in_route_spec.rb +2 -0
  156. data/spec/grape/api/parameters_modification_spec.rb +3 -1
  157. data/spec/grape/api/patch_method_helpers_spec.rb +2 -0
  158. data/spec/grape/api/recognize_path_spec.rb +2 -0
  159. data/spec/grape/api/required_parameters_in_route_spec.rb +2 -0
  160. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +2 -0
  161. data/spec/grape/api/routes_with_requirements_spec.rb +2 -0
  162. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +2 -0
  163. data/spec/grape/api/shared_helpers_spec.rb +2 -0
  164. data/spec/grape/api_remount_spec.rb +2 -0
  165. data/spec/grape/api_spec.rb +99 -11
  166. data/spec/grape/config_spec.rb +2 -0
  167. data/spec/grape/dsl/callbacks_spec.rb +2 -0
  168. data/spec/grape/dsl/configuration_spec.rb +2 -0
  169. data/spec/grape/dsl/desc_spec.rb +2 -0
  170. data/spec/grape/dsl/headers_spec.rb +2 -0
  171. data/spec/grape/dsl/helpers_spec.rb +4 -2
  172. data/spec/grape/dsl/inside_route_spec.rb +177 -33
  173. data/spec/grape/dsl/logger_spec.rb +2 -0
  174. data/spec/grape/dsl/middleware_spec.rb +2 -0
  175. data/spec/grape/dsl/parameters_spec.rb +2 -0
  176. data/spec/grape/dsl/request_response_spec.rb +2 -0
  177. data/spec/grape/dsl/routing_spec.rb +2 -0
  178. data/spec/grape/dsl/settings_spec.rb +2 -0
  179. data/spec/grape/dsl/validations_spec.rb +2 -0
  180. data/spec/grape/endpoint_spec.rb +21 -6
  181. data/spec/grape/entity_spec.rb +2 -0
  182. data/spec/grape/exceptions/base_spec.rb +3 -1
  183. data/spec/grape/exceptions/body_parse_errors_spec.rb +2 -0
  184. data/spec/grape/exceptions/invalid_accept_header_spec.rb +2 -0
  185. data/spec/grape/exceptions/invalid_formatter_spec.rb +2 -0
  186. data/spec/grape/exceptions/invalid_response_spec.rb +2 -0
  187. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +2 -0
  188. data/spec/grape/exceptions/missing_mime_type_spec.rb +2 -0
  189. data/spec/grape/exceptions/missing_option_spec.rb +2 -0
  190. data/spec/grape/exceptions/unknown_options_spec.rb +2 -0
  191. data/spec/grape/exceptions/unknown_validator_spec.rb +2 -0
  192. data/spec/grape/exceptions/validation_errors_spec.rb +4 -2
  193. data/spec/grape/exceptions/validation_spec.rb +3 -1
  194. data/spec/grape/extensions/param_builders/hash_spec.rb +2 -0
  195. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +2 -0
  196. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +2 -0
  197. data/spec/grape/integration/global_namespace_function_spec.rb +2 -0
  198. data/spec/grape/integration/rack_sendfile_spec.rb +14 -8
  199. data/spec/grape/integration/rack_spec.rb +3 -1
  200. data/spec/grape/loading_spec.rb +2 -0
  201. data/spec/grape/middleware/auth/base_spec.rb +2 -0
  202. data/spec/grape/middleware/auth/dsl_spec.rb +2 -0
  203. data/spec/grape/middleware/auth/strategies_spec.rb +3 -1
  204. data/spec/grape/middleware/base_spec.rb +2 -0
  205. data/spec/grape/middleware/error_spec.rb +2 -0
  206. data/spec/grape/middleware/exception_spec.rb +3 -1
  207. data/spec/grape/middleware/formatter_spec.rb +19 -12
  208. data/spec/grape/middleware/globals_spec.rb +2 -0
  209. data/spec/grape/middleware/stack_spec.rb +11 -0
  210. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -1
  211. data/spec/grape/middleware/versioner/header_spec.rb +3 -1
  212. data/spec/grape/middleware/versioner/param_spec.rb +3 -1
  213. data/spec/grape/middleware/versioner/path_spec.rb +3 -1
  214. data/spec/grape/middleware/versioner_spec.rb +2 -0
  215. data/spec/grape/named_api_spec.rb +2 -0
  216. data/spec/grape/parser_spec.rb +7 -5
  217. data/spec/grape/path_spec.rb +6 -4
  218. data/spec/grape/presenters/presenter_spec.rb +2 -0
  219. data/spec/grape/request_spec.rb +2 -0
  220. data/spec/grape/util/inheritable_setting_spec.rb +2 -0
  221. data/spec/grape/util/inheritable_values_spec.rb +2 -0
  222. data/spec/grape/util/reverse_stackable_values_spec.rb +2 -0
  223. data/spec/grape/util/stackable_values_spec.rb +3 -1
  224. data/spec/grape/util/strict_hash_configuration_spec.rb +2 -0
  225. data/spec/grape/validations/attributes_iterator_spec.rb +2 -0
  226. data/spec/grape/validations/instance_behaivour_spec.rb +5 -3
  227. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +2 -0
  228. data/spec/grape/validations/params_scope_spec.rb +3 -1
  229. data/spec/grape/validations/single_attribute_iterator_spec.rb +18 -4
  230. data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
  231. data/spec/grape/validations/types/primitive_coercer_spec.rb +135 -0
  232. data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
  233. data/spec/grape/validations/types_spec.rb +9 -36
  234. data/spec/grape/validations/validators/all_or_none_spec.rb +2 -0
  235. data/spec/grape/validations/validators/allow_blank_spec.rb +2 -0
  236. data/spec/grape/validations/validators/at_least_one_of_spec.rb +2 -0
  237. data/spec/grape/validations/validators/coerce_spec.rb +341 -136
  238. data/spec/grape/validations/validators/default_spec.rb +123 -0
  239. data/spec/grape/validations/validators/exactly_one_of_spec.rb +14 -12
  240. data/spec/grape/validations/validators/except_values_spec.rb +3 -1
  241. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +2 -0
  242. data/spec/grape/validations/validators/presence_spec.rb +30 -0
  243. data/spec/grape/validations/validators/regexp_spec.rb +2 -0
  244. data/spec/grape/validations/validators/same_as_spec.rb +2 -0
  245. data/spec/grape/validations/validators/values_spec.rb +30 -5
  246. data/spec/grape/validations_spec.rb +91 -33
  247. data/spec/integration/eager_load/eager_load_spec.rb +15 -0
  248. data/spec/integration/multi_json/json_spec.rb +2 -0
  249. data/spec/integration/multi_xml/xml_spec.rb +2 -0
  250. data/spec/shared/versioning_examples.rb +2 -0
  251. data/spec/spec_helper.rb +18 -0
  252. data/spec/support/basic_auth_encode_helpers.rb +2 -0
  253. data/spec/support/content_type_helpers.rb +2 -0
  254. data/spec/support/eager_load.rb +19 -0
  255. data/spec/support/endpoint_faker.rb +2 -0
  256. data/spec/support/file_streamer.rb +2 -0
  257. data/spec/support/integer_helpers.rb +2 -0
  258. data/spec/support/versioned_helpers.rb +4 -2
  259. metadata +48 -28
  260. data/lib/grape/extensions/deep_hash_with_indifferent_access.rb +0 -18
  261. data/lib/grape/util/content_types.rb +0 -26
  262. data/lib/grape/validations/types/virtus_collection_patch.rb +0 -16
@@ -1,21 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  module Types
4
- # Instances of this class may be passed to
5
- # +Virtus::Attribute.build+ as the +:coercer+
6
- # option for custom types that do not otherwise
7
- # satisfy the requirements for +Virtus::Attribute::coerce+
8
- # and +Virtus::Attribute::value_coerced?+ to work
9
- # as expected.
10
- #
11
- # Subclasses of +Virtus::Attribute+ or +Axiom::Types::Type+
12
- # (or for which an axiom type can be inferred, i.e. the
13
- # primitives, +Date+, +Time+, etc.) do not need any such
14
- # coercer to be passed with them.
15
- #
16
- # Coercion
17
- # --------
18
- #
19
6
  # This class will detect type classes that implement
20
7
  # a class-level +parse+ method. The method should accept one
21
8
  # +String+ argument and should return the value coerced to
@@ -30,14 +17,14 @@ module Grape
30
17
  # Type Checking
31
18
  # -------------
32
19
  #
33
- # Calls to +value_coerced?+ will consult this class to check
20
+ # Calls to +coerced?+ will consult this class to check
34
21
  # that the coerced value produced above is in fact of the
35
22
  # expected type. By default this class performs a basic check
36
23
  # against the type supplied, but this behaviour will be
37
24
  # overridden if the class implements a class-level
38
25
  # +coerced?+ or +parsed?+ method. This method
39
26
  # will receive a single parameter that is the coerced value
40
- # and should return +true+ iff the value meets type expectations.
27
+ # and should return +true+ if the value meets type expectations.
41
28
  # Arbitrary assertions may be made here but the grape validation
42
29
  # system should be preferred.
43
30
  #
@@ -46,15 +33,6 @@ module Grape
46
33
  # contract as +coerced?+, and must be supplied with a coercion
47
34
  # +method+.
48
35
  class CustomTypeCoercer
49
- # Uses +Virtus::Attribute.build+ to build a new
50
- # attribute that makes use of this class for
51
- # coercion and type validation logic.
52
- #
53
- # @return [Virtus::Attribute]
54
- def self.build(type, method = nil)
55
- Virtus::Attribute.build(type, coercer: new(type, method))
56
- end
57
-
58
36
  # A new coercer for the given type specification
59
37
  # and coercion method.
60
38
  #
@@ -64,37 +42,25 @@ module Grape
64
42
  # optional coercion method. See class docs.
65
43
  def initialize(type, method = nil)
66
44
  coercion_method = infer_coercion_method type, method
67
-
68
45
  @method = enforce_symbolized_keys type, coercion_method
69
-
70
46
  @type_check = infer_type_check(type)
71
47
  end
72
48
 
73
- # This method is called from somewhere within
74
- # +Virtus::Attribute::coerce+ in order to coerce
75
- # the given value.
49
+ # Coerces the given value.
76
50
  #
77
51
  # @param value [String] value to be coerced, in grape
78
52
  # this should always be a string.
79
53
  # @return [Object] the coerced result
80
- def call(value)
81
- @method.call value
54
+ def call(val)
55
+ return if val.nil?
56
+
57
+ coerced_val = @method.call(val)
58
+ return InvalidValue.new unless coerced?(coerced_val)
59
+ coerced_val
82
60
  end
83
61
 
84
- # This method is called from somewhere within
85
- # +Virtus::Attribute::value_coerced?+ in order to
86
- # assert that the value has been coerced successfully.
87
- #
88
- # @param _primitive [Axiom::Types::Type] primitive type
89
- # for the coercion as detected by axiom-types' inference
90
- # system. For custom types this is typically not much use
91
- # (i.e. it is +Axiom::Types::Object+) unless special
92
- # inference rules have been declared for the type.
93
- # @param value [Object] a coerced result returned from {#call}
94
- # @return [true,false] whether or not the coerced value
95
- # satisfies type requirements.
96
- def success?(_primitive, value)
97
- @type_check.call value
62
+ def coerced?(val)
63
+ val.nil? || @type_check.call(val)
98
64
  end
99
65
 
100
66
  private
@@ -160,8 +126,8 @@ module Grape
160
126
  # Collections have all values processed individually
161
127
  if [Array, Set].include?(type)
162
128
  lambda do |val|
163
- method.call(val).tap do |new_value|
164
- new_value.map do |item|
129
+ method.call(val).tap do |new_val|
130
+ new_val.map do |item|
165
131
  item.is_a?(Hash) ? symbolize_keys(item) : item
166
132
  end
167
133
  end
@@ -1,12 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  module Types
4
- # Instances of this class may be passed to
5
- # +Virtus::Attribute.build+ as the +:coercer+
6
- # option, to handle collections of types that
7
- # provide their own parsing (and optionally,
8
- # type-checking) functionality.
9
- #
10
6
  # See {CustomTypeCoercer} for details on types
11
7
  # that will be supported by this by this coercer.
12
8
  # This coercer works in the same way as +CustomTypeCoercer+
@@ -38,32 +34,21 @@ module Grape
38
34
  @set = set
39
35
  end
40
36
 
41
- # This method is called from somewhere within
42
- # +Virtus::Attribute::coerce+ in order to coerce
43
- # the given value.
37
+ # Coerces the given value.
44
38
  #
45
39
  # @param value [Array<String>] an array of values to be coerced
46
40
  # @return [Array,Set] the coerced result. May be an +Array+ or a
47
41
  # +Set+ depending on the setting given to the constructor
48
42
  def call(value)
49
- coerced = value.map { |item| super(item) }
43
+ coerced = value.map do |item|
44
+ coerced_item = super(item)
50
45
 
51
- @set ? Set.new(coerced) : coerced
52
- end
46
+ return coerced_item if coerced_item.is_a?(InvalidValue)
53
47
 
54
- # This method is called from somewhere within
55
- # +Virtus::Attribute::value_coerced?+ in order to assert
56
- # that the all of the values in the array have been coerced
57
- # successfully.
58
- #
59
- # @param primitive [Axiom::Types::Type] primitive type for
60
- # the coercion as deteced by axiom-types' inference system.
61
- # @param value [Enumerable] a coerced result returned from {#call}
62
- # @return [true,false] whether or not all of the coerced values in
63
- # the collection satisfy type requirements.
64
- def success?(primitive, value)
65
- value.is_a?(@set ? Set : Array) &&
66
- value.all? { |item| super(primitive, item) }
48
+ coerced_item
49
+ end
50
+
51
+ @set ? Set.new(coerced) : coerced
67
52
  end
68
53
  end
69
54
  end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-types'
4
+
5
+ module DryTypes
6
+ # Call +Dry.Types()+ to add all registered types to +DryTypes+ which is
7
+ # a container in this case. Check documentation for more information
8
+ # https://dry-rb.org/gems/dry-types/1.2/getting-started/
9
+ include Dry.Types()
10
+ end
11
+
12
+ module Grape
13
+ module Validations
14
+ module Types
15
+ # A base class for classes which must identify a coercer to be used.
16
+ # If the +strict+ argument is true, it won't coerce the given value
17
+ # but check its type. More information there
18
+ # https://dry-rb.org/gems/dry-types/1.2/built-in-types/
19
+ class DryTypeCoercer
20
+ class << self
21
+ # Registers a collection coercer which could be found by a type,
22
+ # see +collection_coercer_for+ method below. This method is meant for inheritors.
23
+ def register_collection(type)
24
+ DryTypeCoercer.collection_coercers[type] = self
25
+ end
26
+
27
+ # Returns a collection coercer which corresponds to a given type.
28
+ # Example:
29
+ #
30
+ # collection_coercer_for(Array)
31
+ # #=> Grape::Validations::Types::ArrayCoercer
32
+ def collection_coercer_for(type)
33
+ collection_coercers[type]
34
+ end
35
+
36
+ # Returns an instance of a coercer for a given type
37
+ def coercer_instance_for(type, strict = false)
38
+ return PrimitiveCoercer.new(type, strict) if type.class == Class
39
+
40
+ # in case of a collection (Array[Integer]) the type is an instance of a collection,
41
+ # so we need to figure out the actual type
42
+ collection_coercer_for(type.class).new(type, strict)
43
+ end
44
+
45
+ protected
46
+
47
+ def collection_coercers
48
+ @collection_coercers ||= {}
49
+ end
50
+ end
51
+
52
+ def initialize(type, strict = false)
53
+ @type = type
54
+ @strict = strict
55
+ @scope = strict ? DryTypes::Strict : DryTypes::Params
56
+ end
57
+
58
+ # Coerces the given value to a type which was specified during
59
+ # initialization as a type argument.
60
+ #
61
+ # @param val [Object]
62
+ def call(val)
63
+ return if val.nil?
64
+
65
+ @coercer[val]
66
+ rescue Dry::Types::CoercionError => _e
67
+ InvalidValue.new
68
+ end
69
+
70
+ protected
71
+
72
+ attr_reader :scope, :type, :strict
73
+ end
74
+ end
75
+ end
76
+ end
@@ -1,25 +1,29 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  module Types
4
- # +Virtus::Attribute+ implementation for parameters
5
- # that are multipart file objects. Actual handling
6
- # of these objects is provided by +Rack::Request+;
7
- # this class is here only to assert that rack's
8
- # handling has succeeded, and to prevent virtus
9
- # from interfering.
10
- class File < Virtus::Attribute
11
- def coerce(input)
12
- # Processing of multipart file objects
13
- # is already taken care of by Rack::Request.
14
- # Nothing to do here.
15
- input
16
- end
6
+ # Implementation for parameters that are multipart file objects.
7
+ # Actual handling of these objects is provided by +Rack::Request+;
8
+ # this class is here only to assert that rack's handling has succeeded.
9
+ class File
10
+ class << self
11
+ def parse(input)
12
+ return if input.nil?
13
+ return InvalidValue.new unless parsed?(input)
14
+
15
+ # Processing of multipart file objects
16
+ # is already taken care of by Rack::Request.
17
+ # Nothing to do here.
18
+ input
19
+ end
17
20
 
18
- def value_coerced?(value)
19
- # Rack::Request creates a Hash with filename,
20
- # content type and an IO object. Do a bit of basic
21
- # duck-typing.
22
- value.is_a?(::Hash) && value.key?(:tempfile) && value[:tempfile].is_a?(Tempfile)
21
+ def parsed?(value)
22
+ # Rack::Request creates a Hash with filename,
23
+ # content type and an IO object. Do a bit of basic
24
+ # duck-typing.
25
+ value.is_a?(::Hash) && value.key?(:tempfile) && value[:tempfile].is_a?(Tempfile)
26
+ end
23
27
  end
24
28
  end
25
29
  end
@@ -1,43 +1,48 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'json'
2
4
 
3
5
  module Grape
4
6
  module Validations
5
7
  module Types
6
- # +Virtus::Attribute+ implementation that handles coercion
7
- # and type checking for parameters that are complex types
8
- # given as JSON-encoded strings. It accepts both JSON objects
8
+ # Handles coercion and type checking for parameters that are complex
9
+ # types given as JSON-encoded strings. It accepts both JSON objects
9
10
  # and arrays of objects, and will coerce the input to a +Hash+
10
11
  # or +Array+ object respectively. In either case the Grape
11
12
  # validation system will apply nested validation rules to
12
13
  # all returned objects.
13
- class Json < Virtus::Attribute
14
- # Coerce the input into a JSON-like data structure.
15
- #
16
- # @param input [String] a JSON-encoded parameter value
17
- # @return [Hash,Array<Hash>,nil]
18
- def coerce(input)
19
- # Allow nulls and blank strings
20
- return if input.nil? || input =~ /^\s*$/
21
- JSON.parse(input, symbolize_names: true)
22
- end
14
+ class Json
15
+ class << self
16
+ # Coerce the input into a JSON-like data structure.
17
+ #
18
+ # @param input [String] a JSON-encoded parameter value
19
+ # @return [Hash,Array<Hash>,nil]
20
+ def parse(input)
21
+ return input if parsed?(input)
23
22
 
24
- # Checks that the input was parsed successfully
25
- # and isn't something odd such as an array of primitives.
26
- #
27
- # @param value [Object] result of {#coerce}
28
- # @return [true,false]
29
- def value_coerced?(value)
30
- value.is_a?(::Hash) || coerced_collection?(value)
31
- end
23
+ # Allow nulls and blank strings
24
+ return if input.nil? || input.match?(/^\s*$/)
25
+ JSON.parse(input, symbolize_names: true)
26
+ end
32
27
 
33
- protected
28
+ # Checks that the input was parsed successfully
29
+ # and isn't something odd such as an array of primitives.
30
+ #
31
+ # @param value [Object] result of {#parse}
32
+ # @return [true,false]
33
+ def parsed?(value)
34
+ value.is_a?(::Hash) || coerced_collection?(value)
35
+ end
34
36
 
35
- # Is the value an array of JSON-like objects?
36
- #
37
- # @param value [Object] result of {#coerce}
38
- # @return [true,false]
39
- def coerced_collection?(value)
40
- value.is_a?(::Array) && value.all? { |i| i.is_a? ::Hash }
37
+ protected
38
+
39
+ # Is the value an array of JSON-like objects?
40
+ #
41
+ # @param value [Object] result of {#parse}
42
+ # @return [true,false]
43
+ def coerced_collection?(value)
44
+ value.is_a?(::Array) && value.all? { |i| i.is_a? ::Hash }
45
+ end
41
46
  end
42
47
  end
43
48
 
@@ -46,18 +51,20 @@ module Grape
46
51
  # objects and arrays of objects, but wraps single objects
47
52
  # in an Array.
48
53
  class JsonArray < Json
49
- # See {Json#coerce}. Wraps single objects in an array.
50
- #
51
- # @param input [String] JSON-encoded parameter value
52
- # @return [Array<Hash>]
53
- def coerce(input)
54
- json = super
55
- Array.wrap(json) unless json.nil?
56
- end
54
+ class << self
55
+ # See {Json#parse}. Wraps single objects in an array.
56
+ #
57
+ # @param input [String] JSON-encoded parameter value
58
+ # @return [Array<Hash>]
59
+ def parse(input)
60
+ json = super
61
+ Array.wrap(json) unless json.nil?
62
+ end
57
63
 
58
- # See {Json#coerced_collection?}
59
- def value_coerced?(value)
60
- coerced_collection? value
64
+ # See {Json#coerced_collection?}
65
+ def parsed?(value)
66
+ coerced_collection? value
67
+ end
61
68
  end
62
69
  end
63
70
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  module Types
@@ -22,53 +24,32 @@ module Grape
22
24
 
23
25
  @type_coercers = types.map do |type|
24
26
  if Types.multiple? type
25
- VariantCollectionCoercer.new type
27
+ VariantCollectionCoercer.new type, @method
26
28
  else
27
- Types.build_coercer type
29
+ Types.build_coercer type, strict: !@method.nil?
28
30
  end
29
31
  end
30
32
  end
31
33
 
32
- # This method is called from somewhere within
33
- # +Virtus::Attribute::coerce+ in order to coerce
34
- # the given value.
34
+ # Coerces the given value.
35
35
  #
36
- # @param value [String] value to be coerced, in grape
36
+ # @param val [String] value to be coerced, in grape
37
37
  # this should always be a string.
38
38
  # @return [Object,InvalidValue] the coerced result, or an instance
39
39
  # of {InvalidValue} if the value could not be coerced.
40
- def call(value)
41
- return @method.call(value) if @method
40
+ def call(val)
41
+ # once the value is coerced by the custom method, its type should be checked
42
+ val = @method.call(val) if @method
43
+
44
+ coerced_val = InvalidValue.new
42
45
 
43
46
  @type_coercers.each do |coercer|
44
- coerced = coercer.coerce(value)
47
+ coerced_val = coercer.call(val)
45
48
 
46
- return coerced if coercer.value_coerced? coerced
49
+ return coerced_val unless coerced_val.is_a?(InvalidValue)
47
50
  end
48
51
 
49
- # Declare that we couldn't coerce the value in such a way
50
- # that Grape won't ask us again if the value is valid
51
- InvalidValue.new
52
- end
53
-
54
- # This method is called from somewhere within
55
- # +Virtus::Attribute::value_coerced?+ in order to
56
- # assert that the value has been coerced successfully.
57
- # Due to Grape's design this will in fact only be called
58
- # if a custom coercion method is being used, since {#call}
59
- # returns an {InvalidValue} object if the value could not
60
- # be coerced.
61
- #
62
- # @param _primitive [Axiom::Types::Type] primitive type
63
- # for the coercion as detected by axiom-types' inference
64
- # system. For custom types this is typically not much use
65
- # (i.e. it is +Axiom::Types::Object+) unless special
66
- # inference rules have been declared for the type.
67
- # @param value [Object] a coerced result returned from {#call}
68
- # @return [true,false] whether or not the coerced value
69
- # satisfies type requirements.
70
- def success?(_primitive, value)
71
- @type_coercers.any? { |coercer| coercer.value_coerced? value }
52
+ coerced_val
72
53
  end
73
54
  end
74
55
  end