grape 1.1.0 → 1.5.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 (286) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +278 -44
  3. data/LICENSE +1 -1
  4. data/README.md +514 -69
  5. data/UPGRADING.md +424 -17
  6. data/grape.gemspec +13 -2
  7. data/lib/grape.rb +104 -71
  8. data/lib/grape/api.rb +138 -175
  9. data/lib/grape/api/helpers.rb +2 -0
  10. data/lib/grape/api/instance.rb +283 -0
  11. data/lib/grape/config.rb +34 -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 +22 -0
  16. data/lib/grape/dsl/configuration.rb +2 -0
  17. data/lib/grape/dsl/desc.rb +41 -7
  18. data/lib/grape/dsl/headers.rb +2 -0
  19. data/lib/grape/dsl/helpers.rb +5 -2
  20. data/lib/grape/dsl/inside_route.rb +92 -49
  21. data/lib/grape/dsl/logger.rb +2 -0
  22. data/lib/grape/dsl/middleware.rb +9 -0
  23. data/lib/grape/dsl/parameters.rb +25 -14
  24. data/lib/grape/dsl/request_response.rb +4 -2
  25. data/lib/grape/dsl/routing.rb +17 -10
  26. data/lib/grape/dsl/settings.rb +7 -1
  27. data/lib/grape/dsl/validations.rb +24 -4
  28. data/lib/grape/eager_load.rb +20 -0
  29. data/lib/grape/endpoint.rb +59 -35
  30. data/lib/grape/error_formatter.rb +4 -2
  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 +20 -14
  36. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  37. data/lib/grape/exceptions/incompatible_option_values.rb +2 -0
  38. data/lib/grape/exceptions/invalid_accept_header.rb +2 -0
  39. data/lib/grape/exceptions/invalid_formatter.rb +2 -0
  40. data/lib/grape/exceptions/invalid_message_body.rb +2 -0
  41. data/lib/grape/exceptions/invalid_response.rb +11 -0
  42. data/lib/grape/exceptions/invalid_version_header.rb +2 -0
  43. data/lib/grape/exceptions/invalid_versioner_option.rb +2 -0
  44. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +2 -0
  45. data/lib/grape/exceptions/method_not_allowed.rb +2 -0
  46. data/lib/grape/exceptions/missing_group_type.rb +2 -0
  47. data/lib/grape/exceptions/missing_mime_type.rb +2 -0
  48. data/lib/grape/exceptions/missing_option.rb +2 -0
  49. data/lib/grape/exceptions/missing_vendor_option.rb +2 -0
  50. data/lib/grape/exceptions/unknown_options.rb +2 -0
  51. data/lib/grape/exceptions/unknown_parameter.rb +2 -0
  52. data/lib/grape/exceptions/unknown_validator.rb +2 -0
  53. data/lib/grape/exceptions/unsupported_group_type.rb +2 -0
  54. data/lib/grape/exceptions/validation.rb +4 -2
  55. data/lib/grape/exceptions/validation_array_errors.rb +2 -0
  56. data/lib/grape/exceptions/validation_errors.rb +16 -13
  57. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +4 -3
  58. data/lib/grape/extensions/deep_mergeable_hash.rb +2 -0
  59. data/lib/grape/extensions/deep_symbolize_hash.rb +2 -0
  60. data/lib/grape/extensions/hash.rb +2 -0
  61. data/lib/grape/extensions/hashie/mash.rb +2 -0
  62. data/lib/grape/formatter.rb +5 -3
  63. data/lib/grape/formatter/json.rb +2 -0
  64. data/lib/grape/formatter/serializable_hash.rb +2 -0
  65. data/lib/grape/formatter/txt.rb +2 -0
  66. data/lib/grape/formatter/xml.rb +2 -0
  67. data/lib/grape/http/headers.rb +50 -18
  68. data/lib/grape/locale/en.yml +3 -1
  69. data/lib/grape/middleware/auth/base.rb +7 -7
  70. data/lib/grape/middleware/auth/dsl.rb +2 -0
  71. data/lib/grape/middleware/auth/strategies.rb +2 -0
  72. data/lib/grape/middleware/auth/strategy_info.rb +2 -0
  73. data/lib/grape/middleware/base.rb +10 -7
  74. data/lib/grape/middleware/error.rb +21 -16
  75. data/lib/grape/middleware/filter.rb +2 -0
  76. data/lib/grape/middleware/formatter.rb +8 -6
  77. data/lib/grape/middleware/globals.rb +2 -0
  78. data/lib/grape/middleware/helpers.rb +12 -0
  79. data/lib/grape/middleware/stack.rb +13 -3
  80. data/lib/grape/middleware/versioner.rb +2 -0
  81. data/lib/grape/middleware/versioner/accept_version_header.rb +2 -0
  82. data/lib/grape/middleware/versioner/header.rb +10 -8
  83. data/lib/grape/middleware/versioner/param.rb +3 -1
  84. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +4 -1
  85. data/lib/grape/middleware/versioner/path.rb +3 -1
  86. data/lib/grape/namespace.rb +14 -2
  87. data/lib/grape/parser.rb +4 -2
  88. data/lib/grape/parser/json.rb +3 -1
  89. data/lib/grape/parser/xml.rb +3 -1
  90. data/lib/grape/path.rb +15 -3
  91. data/lib/grape/presenters/presenter.rb +2 -0
  92. data/lib/grape/request.rb +19 -10
  93. data/lib/grape/router.rb +30 -29
  94. data/lib/grape/router/attribute_translator.rb +41 -8
  95. data/lib/grape/router/pattern.rb +20 -16
  96. data/lib/grape/router/route.rb +14 -28
  97. data/lib/grape/{serve_file → serve_stream}/file_body.rb +3 -1
  98. data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +3 -1
  99. data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +10 -8
  100. data/lib/grape/util/base_inheritable.rb +43 -0
  101. data/lib/grape/util/cache.rb +20 -0
  102. data/lib/grape/util/endpoint_configuration.rb +8 -0
  103. data/lib/grape/util/env.rb +19 -17
  104. data/lib/grape/util/inheritable_setting.rb +2 -0
  105. data/lib/grape/util/inheritable_values.rb +7 -25
  106. data/lib/grape/util/json.rb +2 -0
  107. data/lib/grape/util/lazy_block.rb +27 -0
  108. data/lib/grape/util/lazy_object.rb +43 -0
  109. data/lib/grape/util/lazy_value.rb +98 -0
  110. data/lib/grape/util/registrable.rb +2 -0
  111. data/lib/grape/util/reverse_stackable_values.rb +10 -35
  112. data/lib/grape/util/stackable_values.rb +21 -34
  113. data/lib/grape/util/strict_hash_configuration.rb +2 -0
  114. data/lib/grape/util/xml.rb +2 -0
  115. data/lib/grape/validations.rb +2 -0
  116. data/lib/grape/validations/attributes_iterator.rb +16 -6
  117. data/lib/grape/validations/multiple_attributes_iterator.rb +13 -0
  118. data/lib/grape/validations/params_scope.rb +51 -30
  119. data/lib/grape/validations/single_attribute_iterator.rb +24 -0
  120. data/lib/grape/validations/types.rb +13 -38
  121. data/lib/grape/validations/types/array_coercer.rb +65 -0
  122. data/lib/grape/validations/types/build_coercer.rb +47 -49
  123. data/lib/grape/validations/types/custom_type_coercer.rb +29 -51
  124. data/lib/grape/validations/types/custom_type_collection_coercer.rb +10 -25
  125. data/lib/grape/validations/types/dry_type_coercer.rb +76 -0
  126. data/lib/grape/validations/types/file.rb +22 -18
  127. data/lib/grape/validations/types/invalid_value.rb +24 -0
  128. data/lib/grape/validations/types/json.rb +46 -39
  129. data/lib/grape/validations/types/multiple_type_coercer.rb +14 -33
  130. data/lib/grape/validations/types/primitive_coercer.rb +67 -0
  131. data/lib/grape/validations/types/set_coercer.rb +40 -0
  132. data/lib/grape/validations/types/variant_collection_coercer.rb +5 -13
  133. data/lib/grape/validations/validator_factory.rb +8 -11
  134. data/lib/grape/validations/validators/all_or_none.rb +8 -13
  135. data/lib/grape/validations/validators/allow_blank.rb +3 -1
  136. data/lib/grape/validations/validators/as.rb +5 -4
  137. data/lib/grape/validations/validators/at_least_one_of.rb +7 -13
  138. data/lib/grape/validations/validators/base.rb +20 -16
  139. data/lib/grape/validations/validators/coerce.rb +46 -29
  140. data/lib/grape/validations/validators/default.rb +6 -6
  141. data/lib/grape/validations/validators/exactly_one_of.rb +10 -23
  142. data/lib/grape/validations/validators/except_values.rb +4 -2
  143. data/lib/grape/validations/validators/multiple_params_base.rb +17 -10
  144. data/lib/grape/validations/validators/mutual_exclusion.rb +8 -18
  145. data/lib/grape/validations/validators/presence.rb +3 -1
  146. data/lib/grape/validations/validators/regexp.rb +4 -2
  147. data/lib/grape/validations/validators/same_as.rb +26 -0
  148. data/lib/grape/validations/validators/values.rb +18 -6
  149. data/lib/grape/version.rb +3 -1
  150. data/spec/grape/api/custom_validations_spec.rb +5 -3
  151. data/spec/grape/api/deeply_included_options_spec.rb +2 -0
  152. data/spec/grape/api/defines_boolean_in_params_spec.rb +39 -0
  153. data/spec/grape/api/inherited_helpers_spec.rb +2 -0
  154. data/spec/grape/api/instance_spec.rb +104 -0
  155. data/spec/grape/api/invalid_format_spec.rb +2 -0
  156. data/spec/grape/api/namespace_parameters_in_route_spec.rb +2 -0
  157. data/spec/grape/api/nested_helpers_spec.rb +2 -0
  158. data/spec/grape/api/optional_parameters_in_route_spec.rb +2 -0
  159. data/spec/grape/api/parameters_modification_spec.rb +3 -1
  160. data/spec/grape/api/patch_method_helpers_spec.rb +2 -0
  161. data/spec/grape/api/recognize_path_spec.rb +2 -0
  162. data/spec/grape/api/required_parameters_in_route_spec.rb +2 -0
  163. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +2 -0
  164. data/spec/grape/api/routes_with_requirements_spec.rb +61 -0
  165. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +2 -0
  166. data/spec/grape/api/shared_helpers_spec.rb +2 -0
  167. data/spec/grape/api_remount_spec.rb +473 -0
  168. data/spec/grape/api_spec.rb +565 -12
  169. data/spec/grape/config_spec.rb +19 -0
  170. data/spec/grape/dsl/callbacks_spec.rb +2 -0
  171. data/spec/grape/dsl/configuration_spec.rb +2 -0
  172. data/spec/grape/dsl/desc_spec.rb +42 -16
  173. data/spec/grape/dsl/headers_spec.rb +2 -0
  174. data/spec/grape/dsl/helpers_spec.rb +4 -2
  175. data/spec/grape/dsl/inside_route_spec.rb +184 -33
  176. data/spec/grape/dsl/logger_spec.rb +2 -0
  177. data/spec/grape/dsl/middleware_spec.rb +10 -0
  178. data/spec/grape/dsl/parameters_spec.rb +2 -0
  179. data/spec/grape/dsl/request_response_spec.rb +2 -0
  180. data/spec/grape/dsl/routing_spec.rb +12 -0
  181. data/spec/grape/dsl/settings_spec.rb +2 -0
  182. data/spec/grape/dsl/validations_spec.rb +2 -0
  183. data/spec/grape/endpoint/declared_spec.rb +601 -0
  184. data/spec/grape/endpoint_spec.rb +53 -523
  185. data/spec/grape/entity_spec.rb +9 -1
  186. data/spec/grape/exceptions/base_spec.rb +67 -0
  187. data/spec/grape/exceptions/body_parse_errors_spec.rb +2 -0
  188. data/spec/grape/exceptions/invalid_accept_header_spec.rb +2 -0
  189. data/spec/grape/exceptions/invalid_formatter_spec.rb +2 -0
  190. data/spec/grape/exceptions/invalid_response_spec.rb +13 -0
  191. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +2 -0
  192. data/spec/grape/exceptions/missing_mime_type_spec.rb +2 -0
  193. data/spec/grape/exceptions/missing_option_spec.rb +2 -0
  194. data/spec/grape/exceptions/unknown_options_spec.rb +2 -0
  195. data/spec/grape/exceptions/unknown_validator_spec.rb +2 -0
  196. data/spec/grape/exceptions/validation_errors_spec.rb +8 -4
  197. data/spec/grape/exceptions/validation_spec.rb +3 -1
  198. data/spec/grape/extensions/param_builders/hash_spec.rb +2 -0
  199. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +2 -0
  200. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +2 -0
  201. data/spec/grape/integration/global_namespace_function_spec.rb +2 -0
  202. data/spec/grape/integration/rack_sendfile_spec.rb +14 -8
  203. data/spec/grape/integration/rack_spec.rb +25 -7
  204. data/spec/grape/loading_spec.rb +2 -0
  205. data/spec/grape/middleware/auth/base_spec.rb +2 -0
  206. data/spec/grape/middleware/auth/dsl_spec.rb +5 -3
  207. data/spec/grape/middleware/auth/strategies_spec.rb +3 -1
  208. data/spec/grape/middleware/base_spec.rb +10 -0
  209. data/spec/grape/middleware/error_spec.rb +3 -1
  210. data/spec/grape/middleware/exception_spec.rb +4 -2
  211. data/spec/grape/middleware/formatter_spec.rb +33 -16
  212. data/spec/grape/middleware/globals_spec.rb +2 -0
  213. data/spec/grape/middleware/stack_spec.rb +12 -0
  214. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -1
  215. data/spec/grape/middleware/versioner/header_spec.rb +9 -1
  216. data/spec/grape/middleware/versioner/param_spec.rb +3 -1
  217. data/spec/grape/middleware/versioner/path_spec.rb +3 -1
  218. data/spec/grape/middleware/versioner_spec.rb +2 -0
  219. data/spec/grape/named_api_spec.rb +21 -0
  220. data/spec/grape/parser_spec.rb +7 -5
  221. data/spec/grape/path_spec.rb +6 -4
  222. data/spec/grape/presenters/presenter_spec.rb +2 -0
  223. data/spec/grape/request_spec.rb +26 -0
  224. data/spec/grape/util/inheritable_setting_spec.rb +2 -0
  225. data/spec/grape/util/inheritable_values_spec.rb +2 -0
  226. data/spec/grape/util/reverse_stackable_values_spec.rb +2 -0
  227. data/spec/grape/util/stackable_values_spec.rb +3 -1
  228. data/spec/grape/util/strict_hash_configuration_spec.rb +2 -0
  229. data/spec/grape/validations/attributes_iterator_spec.rb +2 -0
  230. data/spec/grape/validations/instance_behaivour_spec.rb +5 -3
  231. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +41 -0
  232. data/spec/grape/validations/params_scope_spec.rb +213 -9
  233. data/spec/grape/validations/single_attribute_iterator_spec.rb +58 -0
  234. data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
  235. data/spec/grape/validations/types/primitive_coercer_spec.rb +135 -0
  236. data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
  237. data/spec/grape/validations/types_spec.rb +9 -36
  238. data/spec/grape/validations/validators/all_or_none_spec.rb +140 -30
  239. data/spec/grape/validations/validators/allow_blank_spec.rb +2 -0
  240. data/spec/grape/validations/validators/at_least_one_of_spec.rb +175 -29
  241. data/spec/grape/validations/validators/coerce_spec.rb +476 -135
  242. data/spec/grape/validations/validators/default_spec.rb +172 -0
  243. data/spec/grape/validations/validators/exactly_one_of_spec.rb +204 -38
  244. data/spec/grape/validations/validators/except_values_spec.rb +4 -1
  245. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +186 -27
  246. data/spec/grape/validations/validators/presence_spec.rb +30 -0
  247. data/spec/grape/validations/validators/regexp_spec.rb +2 -0
  248. data/spec/grape/validations/validators/same_as_spec.rb +65 -0
  249. data/spec/grape/validations/validators/values_spec.rb +30 -5
  250. data/spec/grape/validations_spec.rb +388 -50
  251. data/spec/integration/eager_load/eager_load_spec.rb +15 -0
  252. data/spec/integration/multi_json/json_spec.rb +2 -0
  253. data/spec/integration/multi_xml/xml_spec.rb +2 -0
  254. data/spec/shared/versioning_examples.rb +22 -20
  255. data/spec/spec_helper.rb +12 -1
  256. data/spec/support/basic_auth_encode_helpers.rb +2 -0
  257. data/spec/support/chunks.rb +14 -0
  258. data/spec/support/content_type_helpers.rb +2 -0
  259. data/spec/support/eager_load.rb +19 -0
  260. data/spec/support/endpoint_faker.rb +2 -0
  261. data/spec/support/file_streamer.rb +2 -0
  262. data/spec/support/integer_helpers.rb +2 -0
  263. data/spec/support/versioned_helpers.rb +8 -8
  264. metadata +86 -48
  265. data/Appraisals +0 -32
  266. data/Dangerfile +0 -2
  267. data/Gemfile +0 -33
  268. data/Gemfile.lock +0 -231
  269. data/Guardfile +0 -10
  270. data/RELEASING.md +0 -111
  271. data/Rakefile +0 -25
  272. data/benchmark/simple.rb +0 -27
  273. data/benchmark/simple_with_type_coercer.rb +0 -22
  274. data/gemfiles/multi_json.gemfile +0 -35
  275. data/gemfiles/multi_xml.gemfile +0 -35
  276. data/gemfiles/rack_1.5.2.gemfile +0 -35
  277. data/gemfiles/rack_edge.gemfile +0 -35
  278. data/gemfiles/rails_3.gemfile +0 -36
  279. data/gemfiles/rails_4.gemfile +0 -35
  280. data/gemfiles/rails_5.gemfile +0 -35
  281. data/gemfiles/rails_edge.gemfile +0 -35
  282. data/lib/grape/extensions/deep_hash_with_indifferent_access.rb +0 -18
  283. data/lib/grape/util/content_types.rb +0 -26
  284. data/lib/grape/validations/types/virtus_collection_patch.rb +0 -16
  285. data/pkg/grape-0.17.0.gem +0 -0
  286. data/pkg/grape-0.19.0.gem +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  class AllowBlankValidator < Base
@@ -9,7 +11,7 @@ module Grape
9
11
 
10
12
  return if value == false || value.present?
11
13
 
12
- raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:blank)
14
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:blank))
13
15
  end
14
16
  end
15
17
  end
@@ -1,14 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  class AsValidator < Base
4
- def initialize(attrs, options, required, scope, opts = {})
5
- @alias = options
6
+ def initialize(attrs, options, required, scope, **opts)
7
+ @renamed_options = options
6
8
  super
7
9
  end
8
10
 
9
11
  def validate_param!(attr_name, params)
10
- params[@alias] = params[attr_name]
11
- params.delete(attr_name)
12
+ params[@renamed_options] = params[attr_name]
12
13
  end
13
14
  end
14
15
  end
@@ -1,19 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grape/validations/validators/multiple_params_base'
4
+
1
5
  module Grape
2
6
  module Validations
3
- require 'grape/validations/validators/multiple_params_base'
4
7
  class AtLeastOneOfValidator < MultipleParamsBase
5
- def validate!(params)
6
- super
7
- if scope_requires_params && no_exclusive_params_are_present
8
- raise Grape::Exceptions::Validation, params: all_keys, message: message(:at_least_one)
9
- end
10
- params
11
- end
12
-
13
- private
14
-
15
- def no_exclusive_params_are_present
16
- scoped_params.any? { |resource_params| keys_in_common(resource_params).empty? }
8
+ def validate_params!(params)
9
+ return unless keys_in_common(params).empty?
10
+ raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:at_least_one))
17
11
  end
18
12
  end
19
13
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  class Base
@@ -10,13 +12,15 @@ module Grape
10
12
  # @param options [Object] implementation-dependent Validator options
11
13
  # @param required [Boolean] attribute(s) are required or optional
12
14
  # @param scope [ParamsScope] parent scope for this Validator
13
- # @param opts [Hash] additional validation options
14
- def initialize(attrs, options, required, scope, opts = {})
15
+ # @param opts [Array] additional validation options
16
+ def initialize(attrs, options, required, scope, *opts)
15
17
  @attrs = Array(attrs)
16
18
  @option = options
17
19
  @required = required
18
20
  @scope = scope
19
- @fail_fast = opts[:fail_fast] || false
21
+ opts = opts.any? ? opts.shift : {}
22
+ @fail_fast = opts.fetch(:fail_fast, false)
23
+ @allow_blank = opts.fetch(:allow_blank, false)
20
24
  end
21
25
 
22
26
  # Validates a given request.
@@ -35,31 +39,31 @@ module Grape
35
39
  # @raise [Grape::Exceptions::Validation] if validation failed
36
40
  # @return [void]
37
41
  def validate!(params)
38
- attributes = AttributesIterator.new(self, @scope, params)
42
+ attributes = SingleAttributeIterator.new(self, @scope, params)
43
+ # we collect errors inside array because
44
+ # there may be more than one error per field
39
45
  array_errors = []
40
- attributes.each do |resource_params, attr_name|
41
- next if !@scope.required? && resource_params.empty?
42
- next unless @required || (resource_params.respond_to?(:key?) && resource_params.key?(attr_name))
43
- next unless @scope.meets_dependency?(resource_params, params)
44
46
 
47
+ attributes.each do |val, attr_name, empty_val, skip_value|
48
+ next if skip_value
49
+ next if !@scope.required? && empty_val
50
+ next unless @scope.meets_dependency?(val, params)
45
51
  begin
46
- validate_param!(attr_name, resource_params)
52
+ validate_param!(attr_name, val) if @required || val.respond_to?(:key?) && val.key?(attr_name)
47
53
  rescue Grape::Exceptions::Validation => e
48
- # we collect errors inside array because
49
- # there may be more than one error per field
50
54
  array_errors << e
51
55
  end
52
56
  end
53
57
 
54
- raise Grape::Exceptions::ValidationArrayErrors, array_errors if array_errors.any?
58
+ raise Grape::Exceptions::ValidationArrayErrors.new(array_errors) if array_errors.any?
55
59
  end
56
60
 
57
61
  def self.convert_to_short_name(klass)
58
62
  ret = klass.name.gsub(/::/, '/')
59
- .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
60
- .gsub(/([a-z\d])([A-Z])/, '\1_\2')
61
- .tr('-', '_')
62
- .downcase
63
+ ret.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
64
+ ret.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
65
+ ret.tr!('-', '_')
66
+ ret.downcase!
63
67
  File.basename(ret, '_validator')
64
68
  end
65
69
 
@@ -1,13 +1,30 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  class API
3
- Boolean = Virtus::Attribute::Boolean
5
+ class Boolean
6
+ def self.build(val)
7
+ return nil if val != true && val != false
8
+
9
+ new
10
+ end
11
+ end
12
+
13
+ class Instance
14
+ Boolean = Grape::API::Boolean
15
+ end
4
16
  end
5
17
 
6
18
  module Validations
7
19
  class CoerceValidator < Base
8
- def initialize(*_args)
20
+ def initialize(attrs, options, required, scope, **opts)
9
21
  super
10
- @converter = Types.build_coercer(type, @option[:method])
22
+
23
+ @converter = if type.is_a?(Grape::Validations::Types::VariantCollectionCoercer)
24
+ type
25
+ else
26
+ Types.build_coercer(type, method: @option[:method])
27
+ end
11
28
  end
12
29
 
13
30
  def validate(request)
@@ -15,10 +32,23 @@ module Grape
15
32
  end
16
33
 
17
34
  def validate_param!(attr_name, params)
18
- raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:coerce) unless params.is_a? Hash
19
- return unless requires_coercion?(params[attr_name])
35
+ raise validation_exception(attr_name) unless params.is_a? Hash
36
+
20
37
  new_value = coerce_value(params[attr_name])
21
- raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:coerce) unless valid_type?(new_value)
38
+
39
+ raise validation_exception(attr_name, new_value.message) unless valid_type?(new_value)
40
+
41
+ # Don't assign a value if it is identical. It fixes a problem with Hashie::Mash
42
+ # which looses wrappers for hashes and arrays after reassigning values
43
+ #
44
+ # h = Hashie::Mash.new(list: [1, 2, 3, 4])
45
+ # => #<Hashie::Mash list=#<Hashie::Array [1, 2, 3, 4]>>
46
+ # list = h.list
47
+ # h[:list] = list
48
+ # h
49
+ # => #<Hashie::Mash list=[1, 2, 3, 4]>
50
+ return if params[attr_name].class == new_value.class && params[attr_name] == new_value
51
+
22
52
  params[attr_name] = new_value
23
53
  end
24
54
 
@@ -29,32 +59,17 @@ module Grape
29
59
  #
30
60
  # See {Types.build_coercer}
31
61
  #
32
- # @return [Virtus::Attribute]
62
+ # @return [Object]
33
63
  attr_reader :converter
34
64
 
35
65
  def valid_type?(val)
36
- # Special value to denote coercion failure
37
- return false if val.instance_of?(Types::InvalidValue)
38
-
39
- # Allow nil, to ignore when a parameter is absent
40
- return true if val.nil?
41
-
42
- converter.value_coerced? val
66
+ !val.is_a?(Types::InvalidValue)
43
67
  end
44
68
 
45
69
  def coerce_value(val)
46
- # Don't coerce things other than nil to Arrays or Hashes
47
- unless (@option[:method] && !val.nil?) || type.is_a?(Virtus::Attribute)
48
- return val || [] if type == Array
49
- return val || Set.new if type == Set
50
- return val || {} if type == Hash
51
- end
52
-
53
- converter.coerce(val)
54
-
55
- # not the prettiest but some invalid coercion can currently trigger
56
- # errors in Virtus (see coerce_spec.rb:75)
57
- rescue
70
+ converter.call(val)
71
+ # Some custom types might fail, so it should be treated as an invalid value
72
+ rescue StandardError
58
73
  Types::InvalidValue.new
59
74
  end
60
75
 
@@ -65,9 +80,11 @@ module Grape
65
80
  @option[:type].is_a?(Hash) ? @option[:type][:value] : @option[:type]
66
81
  end
67
82
 
68
- def requires_coercion?(value)
69
- # JSON types do not require coercion if value is valid
70
- !valid_type?(value) || converter.coercer.respond_to?(:method) && !converter.is_a?(Grape::Validations::Types::Json)
83
+ def validation_exception(attr_name, custom_msg = nil)
84
+ Grape::Exceptions::Validation.new(
85
+ params: [@scope.full_name(attr_name)],
86
+ message: custom_msg || message(:coerce)
87
+ )
71
88
  end
72
89
  end
73
90
  end
@@ -1,13 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  class DefaultValidator < Base
4
- def initialize(attrs, options, required, scope, opts = {})
6
+ def initialize(attrs, options, required, scope, **opts)
5
7
  @default = options
6
8
  super
7
9
  end
8
10
 
9
11
  def validate_param!(attr_name, params)
10
- return if params.key? attr_name
11
12
  params[attr_name] = if @default.is_a? Proc
12
13
  @default.call
13
14
  elsif @default.frozen? || !duplicatable?(@default)
@@ -18,11 +19,10 @@ module Grape
18
19
  end
19
20
 
20
21
  def validate!(params)
21
- attrs = AttributesIterator.new(self, @scope, params)
22
+ attrs = SingleAttributeIterator.new(self, @scope, params)
22
23
  attrs.each do |resource_params, attr_name|
23
- if resource_params.is_a?(Hash) && resource_params[attr_name].nil?
24
- validate_param!(attr_name, resource_params)
25
- end
24
+ next unless @scope.meets_dependency?(resource_params, params)
25
+ validate_param!(attr_name, resource_params) if resource_params.is_a?(Hash) && resource_params[attr_name].nil?
26
26
  end
27
27
  end
28
28
 
@@ -1,28 +1,15 @@
1
- module Grape
2
- module Validations
3
- require 'grape/validations/validators/mutual_exclusion'
4
- class ExactlyOneOfValidator < MutualExclusionValidator
5
- def validate!(params)
6
- super
7
- if scope_requires_params && none_of_restricted_params_is_present
8
- raise Grape::Exceptions::Validation, params: all_keys, message: message(:exactly_one)
9
- end
10
- params
11
- end
1
+ # frozen_string_literal: true
12
2
 
13
- def message(default_key = nil)
14
- options = instance_variable_get(:@option)
15
- if options_key?(:message)
16
- (options_key?(default_key, options[:message]) ? options[:message][default_key] : options[:message])
17
- else
18
- default_key
19
- end
20
- end
3
+ require 'grape/validations/validators/multiple_params_base'
21
4
 
22
- private
23
-
24
- def none_of_restricted_params_is_present
25
- scoped_params.any? { |resource_params| keys_in_common(resource_params).empty? }
5
+ module Grape
6
+ module Validations
7
+ class ExactlyOneOfValidator < MultipleParamsBase
8
+ def validate_params!(params)
9
+ keys = keys_in_common(params)
10
+ return if keys.length == 1
11
+ raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:exactly_one)) if keys.length.zero?
12
+ raise Grape::Exceptions::Validation.new(params: keys, message: message(:mutual_exclusion))
26
13
  end
27
14
  end
28
15
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  class ExceptValuesValidator < Base
4
- def initialize(attrs, options, required, scope, opts = {})
6
+ def initialize(attrs, options, required, scope, **opts)
5
7
  @except = options.is_a?(Hash) ? options[:value] : options
6
8
  super
7
9
  end
@@ -13,7 +15,7 @@ module Grape
13
15
  return if excepts.nil?
14
16
 
15
17
  param_array = params[attr_name].nil? ? [nil] : Array.wrap(params[attr_name])
16
- raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:except_values) if param_array.any? { |param| excepts.include?(param) }
18
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:except_values)) if param_array.any? { |param| excepts.include?(param) }
17
19
  end
18
20
  end
19
21
  end
@@ -1,26 +1,33 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  class MultipleParamsBase < Base
4
- attr_reader :scoped_params
5
-
6
6
  def validate!(params)
7
- @scoped_params = [@scope.params(params)].flatten
8
- params
9
- end
7
+ attributes = MultipleAttributesIterator.new(self, @scope, params)
8
+ array_errors = []
10
9
 
11
- private
10
+ attributes.each do |resource_params, skip_value|
11
+ next if skip_value
12
+ begin
13
+ validate_params!(resource_params)
14
+ rescue Grape::Exceptions::Validation => e
15
+ array_errors << e
16
+ end
17
+ end
12
18
 
13
- def scope_requires_params
14
- @scope.required? || scoped_params.any?(&:any?)
19
+ raise Grape::Exceptions::ValidationArrayErrors.new(array_errors) if array_errors.any?
15
20
  end
16
21
 
22
+ private
23
+
17
24
  def keys_in_common(resource_params)
18
25
  return [] unless resource_params.is_a?(Hash)
19
- (all_keys & resource_params.stringify_keys.keys).map(&:to_s)
26
+ all_keys & resource_params.keys.map! { |attr| @scope.full_name(attr) }
20
27
  end
21
28
 
22
29
  def all_keys
23
- attrs.map(&:to_s)
30
+ attrs.map { |attr| @scope.full_name(attr) }
24
31
  end
25
32
  end
26
33
  end
@@ -1,24 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grape/validations/validators/multiple_params_base'
4
+
1
5
  module Grape
2
6
  module Validations
3
- require 'grape/validations/validators/multiple_params_base'
4
7
  class MutualExclusionValidator < MultipleParamsBase
5
- attr_reader :processing_keys_in_common
6
-
7
- def validate!(params)
8
- super
9
- if two_or_more_exclusive_params_are_present
10
- raise Grape::Exceptions::Validation, params: processing_keys_in_common, message: message(:mutual_exclusion)
11
- end
12
- params
13
- end
14
-
15
- private
16
-
17
- def two_or_more_exclusive_params_are_present
18
- scoped_params.any? do |resource_params|
19
- @processing_keys_in_common = keys_in_common(resource_params)
20
- @processing_keys_in_common.length > 1
21
- end
8
+ def validate_params!(params)
9
+ keys = keys_in_common(params)
10
+ return if keys.length <= 1
11
+ raise Grape::Exceptions::Validation.new(params: keys, message: message(:mutual_exclusion))
22
12
  end
23
13
  end
24
14
  end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  class PresenceValidator < Base
4
6
  def validate_param!(attr_name, params)
5
7
  return if params.respond_to?(:key?) && params.key?(attr_name)
6
- raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:presence)
8
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:presence))
7
9
  end
8
10
  end
9
11
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  class RegexpValidator < Base
4
6
  def validate_param!(attr_name, params)
5
7
  return unless params.respond_to?(:key?) && params.key?(attr_name)
6
- return if Array.wrap(params[attr_name]).all? { |param| param.nil? || (param.to_s =~ (options_key?(:value) ? @option[:value] : @option)) }
7
- raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:regexp)
8
+ return if Array.wrap(params[attr_name]).all? { |param| param.nil? || param.to_s.match?((options_key?(:value) ? @option[:value] : @option)) }
9
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:regexp))
8
10
  end
9
11
  end
10
12
  end