grape 1.8.0 → 3.3.5

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 (312) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +391 -1
  3. data/CONTRIBUTING.md +3 -11
  4. data/README.md +648 -552
  5. data/UPGRADING.md +803 -7
  6. data/grape.gemspec +11 -14
  7. data/lib/grape/api/instance.rb +68 -158
  8. data/lib/grape/api.rb +71 -107
  9. data/lib/grape/content_types.rb +23 -11
  10. data/lib/grape/cookies.rb +28 -25
  11. data/lib/grape/declared_params_handler.rb +116 -0
  12. data/lib/grape/dry_types.rb +48 -6
  13. data/lib/grape/dsl/callbacks.rb +14 -58
  14. data/lib/grape/dsl/declared.rb +35 -0
  15. data/lib/grape/dsl/desc.rb +15 -63
  16. data/lib/grape/dsl/entity.rb +88 -0
  17. data/lib/grape/dsl/headers.rb +2 -2
  18. data/lib/grape/dsl/helpers.rb +83 -64
  19. data/lib/grape/dsl/inside_route.rb +56 -295
  20. data/lib/grape/dsl/logger.rb +4 -9
  21. data/lib/grape/dsl/middleware.rb +22 -40
  22. data/lib/grape/dsl/parameters.rb +50 -82
  23. data/lib/grape/dsl/request_response.rb +144 -146
  24. data/lib/grape/dsl/rescue_options.rb +24 -0
  25. data/lib/grape/dsl/routing.rb +261 -186
  26. data/lib/grape/dsl/settings.rb +29 -135
  27. data/lib/grape/dsl/validations.rb +39 -32
  28. data/lib/grape/dsl/version_options.rb +23 -0
  29. data/lib/grape/endpoint/options.rb +19 -0
  30. data/lib/grape/endpoint.rb +277 -250
  31. data/lib/grape/{util/env.rb → env.rb} +1 -8
  32. data/lib/grape/error_formatter/base.rb +56 -21
  33. data/lib/grape/error_formatter/json.rb +13 -15
  34. data/lib/grape/error_formatter/serializable_hash.rb +7 -0
  35. data/lib/grape/error_formatter/txt.rb +12 -18
  36. data/lib/grape/error_formatter/xml.rb +3 -13
  37. data/lib/grape/error_formatter.rb +5 -25
  38. data/lib/grape/exceptions/base.rb +22 -58
  39. data/lib/grape/exceptions/error_response.rb +45 -0
  40. data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
  41. data/lib/grape/exceptions/internal_server_error.rb +16 -0
  42. data/lib/grape/exceptions/invalid_accept_header.rb +1 -1
  43. data/lib/grape/exceptions/invalid_formatter.rb +1 -1
  44. data/lib/grape/exceptions/invalid_message_body.rb +1 -1
  45. data/lib/grape/exceptions/invalid_version_header.rb +1 -1
  46. data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
  47. data/lib/grape/exceptions/method_not_allowed.rb +1 -1
  48. data/lib/grape/exceptions/missing_group_type.rb +0 -2
  49. data/lib/grape/exceptions/missing_mime_type.rb +1 -1
  50. data/lib/grape/exceptions/request_error.rb +11 -0
  51. data/lib/grape/exceptions/unknown_auth_strategy.rb +11 -0
  52. data/lib/grape/exceptions/unknown_parameter.rb +1 -1
  53. data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
  54. data/lib/grape/exceptions/unknown_validator.rb +1 -1
  55. data/lib/grape/exceptions/unsupported_group_type.rb +0 -2
  56. data/lib/grape/exceptions/validation.rb +25 -9
  57. data/lib/grape/exceptions/validation_array_errors.rb +5 -0
  58. data/lib/grape/exceptions/validation_errors.rb +22 -26
  59. data/lib/grape/formatter/base.rb +16 -0
  60. data/lib/grape/formatter/json.rb +4 -6
  61. data/lib/grape/formatter/serializable_hash.rb +6 -10
  62. data/lib/grape/formatter/txt.rb +3 -5
  63. data/lib/grape/formatter/xml.rb +4 -6
  64. data/lib/grape/formatter.rb +7 -25
  65. data/lib/grape/json.rb +46 -0
  66. data/lib/grape/locale/en.yml +43 -42
  67. data/lib/grape/middleware/auth/base.rb +11 -33
  68. data/lib/grape/middleware/auth/dsl.rb +37 -31
  69. data/lib/grape/middleware/auth/strategies.rb +1 -2
  70. data/lib/grape/middleware/base.rb +56 -33
  71. data/lib/grape/middleware/deprecated_options_hash_access.rb +19 -0
  72. data/lib/grape/middleware/error.rb +183 -91
  73. data/lib/grape/middleware/formatter.rb +94 -105
  74. data/lib/grape/middleware/precomputed_content_types.rb +46 -0
  75. data/lib/grape/middleware/stack.rb +27 -38
  76. data/lib/grape/middleware/versioner/accept_version_header.rb +6 -33
  77. data/lib/grape/middleware/versioner/base.rb +72 -0
  78. data/lib/grape/middleware/versioner/header.rb +44 -129
  79. data/lib/grape/middleware/versioner/param.rb +4 -25
  80. data/lib/grape/middleware/versioner/path.rb +13 -32
  81. data/lib/grape/middleware/versioner.rb +7 -14
  82. data/lib/grape/mountable.rb +22 -0
  83. data/lib/grape/namespace.rb +18 -12
  84. data/lib/grape/params_builder/base.rb +20 -0
  85. data/lib/grape/params_builder/hash.rb +11 -0
  86. data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
  87. data/lib/grape/params_builder/hashie_mash.rb +11 -0
  88. data/lib/grape/params_builder.rb +15 -0
  89. data/lib/grape/parser/base.rb +16 -0
  90. data/lib/grape/parser/json.rb +6 -8
  91. data/lib/grape/parser/xml.rb +6 -8
  92. data/lib/grape/parser.rb +5 -23
  93. data/lib/grape/path.rb +38 -63
  94. data/lib/grape/railtie.rb +9 -0
  95. data/lib/grape/request.rb +168 -26
  96. data/lib/grape/router/base_route.rb +48 -0
  97. data/lib/grape/router/greedy_route.rb +26 -0
  98. data/lib/grape/router/mustermann_pattern.rb +44 -0
  99. data/lib/grape/router/pattern.rb +30 -34
  100. data/lib/grape/router/route.rb +28 -61
  101. data/lib/grape/router.rb +71 -86
  102. data/lib/grape/serve_stream/file_body.rb +1 -0
  103. data/lib/grape/serve_stream/sendfile_response.rb +3 -5
  104. data/lib/grape/serve_stream/stream_response.rb +1 -0
  105. data/lib/grape/testing.rb +33 -0
  106. data/lib/grape/util/api_description.rb +58 -0
  107. data/lib/grape/util/base_inheritable.rb +14 -14
  108. data/lib/grape/util/cache.rb +1 -3
  109. data/lib/grape/util/deep_freeze.rb +35 -0
  110. data/lib/grape/util/endpoint_configuration.rb +1 -1
  111. data/lib/grape/util/header.rb +13 -0
  112. data/lib/grape/util/inheritable_setting.rb +51 -27
  113. data/lib/grape/util/inheritable_values.rb +7 -5
  114. data/lib/grape/util/lazy/base.rb +16 -0
  115. data/lib/grape/util/lazy/block.rb +22 -0
  116. data/lib/grape/util/lazy/value.rb +31 -0
  117. data/lib/grape/util/lazy/value_array.rb +21 -0
  118. data/lib/grape/util/lazy/value_enumerable.rb +31 -0
  119. data/lib/grape/util/lazy/value_hash.rb +21 -0
  120. data/lib/grape/util/media_type.rb +67 -0
  121. data/lib/grape/util/path_normalizer.rb +34 -0
  122. data/lib/grape/util/registry.rb +27 -0
  123. data/lib/grape/util/reverse_stackable_values.rb +1 -6
  124. data/lib/grape/util/stackable_values.rb +12 -14
  125. data/lib/grape/util/translation.rb +42 -0
  126. data/lib/grape/validations/attributes_iterator.rb +43 -27
  127. data/lib/grape/validations/coerce_options.rb +21 -0
  128. data/lib/grape/validations/contract_scope.rb +28 -0
  129. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  130. data/lib/grape/validations/oneof_collector.rb +39 -0
  131. data/lib/grape/validations/param_scope_tracker.rb +62 -0
  132. data/lib/grape/validations/params_documentation.rb +52 -0
  133. data/lib/grape/validations/params_scope.rb +180 -303
  134. data/lib/grape/validations/shared_options.rb +19 -0
  135. data/lib/grape/validations/single_attribute_iterator.rb +2 -2
  136. data/lib/grape/validations/types/array_coercer.rb +4 -7
  137. data/lib/grape/validations/types/custom_type_coercer.rb +41 -85
  138. data/lib/grape/validations/types/custom_type_collection_coercer.rb +1 -1
  139. data/lib/grape/validations/types/dry_type_coercer.rb +15 -28
  140. data/lib/grape/validations/types/json.rb +0 -2
  141. data/lib/grape/validations/types/primitive_coercer.rb +11 -35
  142. data/lib/grape/validations/types/set_coercer.rb +1 -4
  143. data/lib/grape/validations/types/variant_collection_coercer.rb +11 -0
  144. data/lib/grape/validations/types.rb +29 -54
  145. data/lib/grape/validations/validations_spec.rb +164 -0
  146. data/lib/grape/validations/validators/all_or_none_of_validator.rb +6 -3
  147. data/lib/grape/validations/validators/allow_blank_validator.rb +10 -5
  148. data/lib/grape/validations/validators/at_least_one_of_validator.rb +5 -2
  149. data/lib/grape/validations/validators/base.rb +120 -36
  150. data/lib/grape/validations/validators/coerce_validator.rb +18 -36
  151. data/lib/grape/validations/validators/contract_scope_validator.rb +45 -0
  152. data/lib/grape/validations/validators/default_validator.rb +13 -16
  153. data/lib/grape/validations/validators/exactly_one_of_validator.rb +10 -3
  154. data/lib/grape/validations/validators/except_values_validator.rb +15 -5
  155. data/lib/grape/validations/validators/length_validator.rb +48 -0
  156. data/lib/grape/validations/validators/multiple_params_base.rb +12 -9
  157. data/lib/grape/validations/validators/{mutual_exclusion_validator.rb → mutually_exclusive_validator.rb} +4 -2
  158. data/lib/grape/validations/validators/oneof_validator.rb +49 -0
  159. data/lib/grape/validations/validators/presence_validator.rb +4 -2
  160. data/lib/grape/validations/validators/regexp_validator.rb +11 -3
  161. data/lib/grape/validations/validators/same_as_validator.rb +6 -15
  162. data/lib/grape/validations/validators/values_validator.rb +36 -65
  163. data/lib/grape/validations.rb +8 -21
  164. data/lib/grape/version.rb +1 -2
  165. data/lib/grape/xml.rb +17 -0
  166. data/lib/grape.rb +75 -288
  167. metadata +79 -291
  168. data/lib/grape/api/helpers.rb +0 -9
  169. data/lib/grape/dsl/api.rb +0 -19
  170. data/lib/grape/dsl/configuration.rb +0 -15
  171. data/lib/grape/eager_load.rb +0 -20
  172. data/lib/grape/exceptions/empty_message_body.rb +0 -11
  173. data/lib/grape/exceptions/missing_option.rb +0 -11
  174. data/lib/grape/exceptions/too_many_multipart_files.rb +0 -11
  175. data/lib/grape/exceptions/unknown_options.rb +0 -11
  176. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +0 -27
  177. data/lib/grape/extensions/hash.rb +0 -22
  178. data/lib/grape/extensions/hashie/mash.rb +0 -26
  179. data/lib/grape/http/headers.rb +0 -61
  180. data/lib/grape/middleware/globals.rb +0 -16
  181. data/lib/grape/middleware/helpers.rb +0 -12
  182. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +0 -24
  183. data/lib/grape/router/attribute_translator.rb +0 -63
  184. data/lib/grape/types/invalid_value.rb +0 -8
  185. data/lib/grape/util/json.rb +0 -12
  186. data/lib/grape/util/lazy_block.rb +0 -27
  187. data/lib/grape/util/lazy_object.rb +0 -43
  188. data/lib/grape/util/lazy_value.rb +0 -91
  189. data/lib/grape/util/registrable.rb +0 -15
  190. data/lib/grape/util/strict_hash_configuration.rb +0 -108
  191. data/lib/grape/util/xml.rb +0 -10
  192. data/lib/grape/validations/attributes_doc.rb +0 -58
  193. data/lib/grape/validations/types/build_coercer.rb +0 -94
  194. data/lib/grape/validations/validator_factory.rb +0 -15
  195. data/spec/grape/api/custom_validations_spec.rb +0 -213
  196. data/spec/grape/api/deeply_included_options_spec.rb +0 -56
  197. data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -38
  198. data/spec/grape/api/documentation_spec.rb +0 -59
  199. data/spec/grape/api/inherited_helpers_spec.rb +0 -114
  200. data/spec/grape/api/instance_spec.rb +0 -103
  201. data/spec/grape/api/invalid_format_spec.rb +0 -45
  202. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -38
  203. data/spec/grape/api/nested_helpers_spec.rb +0 -50
  204. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -43
  205. data/spec/grape/api/parameters_modification_spec.rb +0 -41
  206. data/spec/grape/api/patch_method_helpers_spec.rb +0 -79
  207. data/spec/grape/api/recognize_path_spec.rb +0 -21
  208. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -37
  209. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -26
  210. data/spec/grape/api/routes_with_requirements_spec.rb +0 -59
  211. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -41
  212. data/spec/grape/api/shared_helpers_spec.rb +0 -36
  213. data/spec/grape/api_remount_spec.rb +0 -509
  214. data/spec/grape/api_spec.rb +0 -4356
  215. data/spec/grape/dsl/callbacks_spec.rb +0 -45
  216. data/spec/grape/dsl/desc_spec.rb +0 -98
  217. data/spec/grape/dsl/headers_spec.rb +0 -62
  218. data/spec/grape/dsl/helpers_spec.rb +0 -100
  219. data/spec/grape/dsl/inside_route_spec.rb +0 -531
  220. data/spec/grape/dsl/logger_spec.rb +0 -24
  221. data/spec/grape/dsl/middleware_spec.rb +0 -60
  222. data/spec/grape/dsl/parameters_spec.rb +0 -180
  223. data/spec/grape/dsl/request_response_spec.rb +0 -225
  224. data/spec/grape/dsl/routing_spec.rb +0 -275
  225. data/spec/grape/dsl/settings_spec.rb +0 -261
  226. data/spec/grape/dsl/validations_spec.rb +0 -55
  227. data/spec/grape/endpoint/declared_spec.rb +0 -846
  228. data/spec/grape/endpoint_spec.rb +0 -1085
  229. data/spec/grape/entity_spec.rb +0 -336
  230. data/spec/grape/exceptions/base_spec.rb +0 -81
  231. data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -185
  232. data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -358
  233. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -15
  234. data/spec/grape/exceptions/invalid_response_spec.rb +0 -11
  235. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +0 -15
  236. data/spec/grape/exceptions/missing_group_type_spec.rb +0 -17
  237. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -17
  238. data/spec/grape/exceptions/missing_option_spec.rb +0 -15
  239. data/spec/grape/exceptions/unknown_options_spec.rb +0 -15
  240. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -15
  241. data/spec/grape/exceptions/unsupported_group_type_spec.rb +0 -19
  242. data/spec/grape/exceptions/validation_errors_spec.rb +0 -92
  243. data/spec/grape/exceptions/validation_spec.rb +0 -19
  244. data/spec/grape/extensions/param_builders/hash_spec.rb +0 -83
  245. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -105
  246. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -79
  247. data/spec/grape/grape_spec.rb +0 -9
  248. data/spec/grape/integration/global_namespace_function_spec.rb +0 -29
  249. data/spec/grape/integration/rack_sendfile_spec.rb +0 -48
  250. data/spec/grape/integration/rack_spec.rb +0 -51
  251. data/spec/grape/loading_spec.rb +0 -44
  252. data/spec/grape/middleware/auth/base_spec.rb +0 -31
  253. data/spec/grape/middleware/auth/dsl_spec.rb +0 -60
  254. data/spec/grape/middleware/auth/strategies_spec.rb +0 -120
  255. data/spec/grape/middleware/base_spec.rb +0 -221
  256. data/spec/grape/middleware/error_spec.rb +0 -85
  257. data/spec/grape/middleware/exception_spec.rb +0 -294
  258. data/spec/grape/middleware/formatter_spec.rb +0 -461
  259. data/spec/grape/middleware/globals_spec.rb +0 -30
  260. data/spec/grape/middleware/stack_spec.rb +0 -155
  261. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -122
  262. data/spec/grape/middleware/versioner/header_spec.rb +0 -345
  263. data/spec/grape/middleware/versioner/param_spec.rb +0 -171
  264. data/spec/grape/middleware/versioner/path_spec.rb +0 -62
  265. data/spec/grape/middleware/versioner_spec.rb +0 -21
  266. data/spec/grape/named_api_spec.rb +0 -19
  267. data/spec/grape/parser_spec.rb +0 -86
  268. data/spec/grape/path_spec.rb +0 -252
  269. data/spec/grape/presenters/presenter_spec.rb +0 -71
  270. data/spec/grape/request_spec.rb +0 -126
  271. data/spec/grape/util/inheritable_setting_spec.rb +0 -242
  272. data/spec/grape/util/inheritable_values_spec.rb +0 -79
  273. data/spec/grape/util/reverse_stackable_values_spec.rb +0 -134
  274. data/spec/grape/util/stackable_values_spec.rb +0 -128
  275. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -38
  276. data/spec/grape/validations/attributes_doc_spec.rb +0 -153
  277. data/spec/grape/validations/instance_behaivour_spec.rb +0 -43
  278. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -38
  279. data/spec/grape/validations/params_scope_spec.rb +0 -1420
  280. data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -56
  281. data/spec/grape/validations/types/array_coercer_spec.rb +0 -33
  282. data/spec/grape/validations/types/primitive_coercer_spec.rb +0 -150
  283. data/spec/grape/validations/types/set_coercer_spec.rb +0 -32
  284. data/spec/grape/validations/types_spec.rb +0 -111
  285. data/spec/grape/validations/validators/all_or_none_spec.rb +0 -162
  286. data/spec/grape/validations/validators/allow_blank_spec.rb +0 -575
  287. data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -205
  288. data/spec/grape/validations/validators/base_spec.rb +0 -38
  289. data/spec/grape/validations/validators/coerce_spec.rb +0 -1261
  290. data/spec/grape/validations/validators/default_spec.rb +0 -463
  291. data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -233
  292. data/spec/grape/validations/validators/except_values_spec.rb +0 -192
  293. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -214
  294. data/spec/grape/validations/validators/presence_spec.rb +0 -315
  295. data/spec/grape/validations/validators/regexp_spec.rb +0 -161
  296. data/spec/grape/validations/validators/same_as_spec.rb +0 -57
  297. data/spec/grape/validations/validators/values_spec.rb +0 -733
  298. data/spec/grape/validations/validators/zh-CN.yml +0 -10
  299. data/spec/grape/validations_spec.rb +0 -2030
  300. data/spec/integration/eager_load/eager_load_spec.rb +0 -15
  301. data/spec/integration/multi_json/json_spec.rb +0 -7
  302. data/spec/integration/multi_xml/xml_spec.rb +0 -7
  303. data/spec/shared/deprecated_class_examples.rb +0 -16
  304. data/spec/shared/versioning_examples.rb +0 -215
  305. data/spec/spec_helper.rb +0 -52
  306. data/spec/support/basic_auth_encode_helpers.rb +0 -11
  307. data/spec/support/chunks.rb +0 -14
  308. data/spec/support/content_type_helpers.rb +0 -15
  309. data/spec/support/endpoint_faker.rb +0 -25
  310. data/spec/support/file_streamer.rb +0 -13
  311. data/spec/support/integer_helpers.rb +0 -13
  312. data/spec/support/versioned_helpers.rb +0 -55
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Validations
5
+ module Validators
6
+ class LengthValidator < Base
7
+ def initialize(attrs, options, required, scope, opts)
8
+ super
9
+
10
+ @min, @max, @is = options.values_at(:min, :max, :is)
11
+ validate_boundary!(:min, @min)
12
+ validate_boundary!(:max, @max)
13
+ raise ArgumentError, "min #{@min} cannot be greater than max #{@max}" if @min && @max && @min > @max
14
+
15
+ return if @is.nil?
16
+ raise ArgumentError, 'is must be an integer greater than zero' unless @is.is_a?(Integer) && @is.positive?
17
+ raise ArgumentError, 'is cannot be combined with min or max' unless @min.nil? && @max.nil?
18
+ end
19
+
20
+ def validate_param!(attr_name, params)
21
+ param = params[attr_name]
22
+
23
+ return unless param.respond_to?(:length)
24
+
25
+ return unless (!@min.nil? && param.length < @min) || (!@max.nil? && param.length > @max) || (!@is.nil? && param.length != @is)
26
+
27
+ validation_error!(attr_name, message do
28
+ if @min && @max
29
+ translate(:length, min: @min, max: @max)
30
+ elsif @min
31
+ translate(:length_min, min: @min)
32
+ elsif @max
33
+ translate(:length_max, max: @max)
34
+ else
35
+ translate(:length_is, is: @is)
36
+ end
37
+ end)
38
+ end
39
+
40
+ private
41
+
42
+ def validate_boundary!(name, val)
43
+ raise ArgumentError, "#{name} must be an integer greater than or equal to zero" if !val.nil? && (!val.is_a?(Integer) || val.negative?)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -5,28 +5,31 @@ module Grape
5
5
  module Validators
6
6
  class MultipleParamsBase < Base
7
7
  def validate!(params)
8
- attributes = MultipleAttributesIterator.new(self, @scope, params)
9
- array_errors = []
8
+ array_errors = nil
10
9
 
11
- attributes.each do |resource_params|
10
+ @iterator.each(params) do |resource_params|
12
11
  validate_params!(resource_params)
13
12
  rescue Grape::Exceptions::Validation => e
14
- array_errors << e
13
+ (array_errors ||= []) << e
15
14
  end
16
15
 
17
- raise Grape::Exceptions::ValidationArrayErrors.new(array_errors) if array_errors.any?
16
+ raise Grape::Exceptions::ValidationArrayErrors.new(array_errors) if array_errors
18
17
  end
19
18
 
20
19
  private
21
20
 
22
- def keys_in_common(resource_params)
23
- return [] unless resource_params.is_a?(Hash)
21
+ def iterator_class
22
+ MultipleAttributesIterator
23
+ end
24
+
25
+ def keys_in_common(resource_params, known_keys = all_keys)
26
+ return [] unless hash_like?(resource_params)
24
27
 
25
- all_keys & resource_params.keys.map! { |attr| @scope.full_name(attr) }
28
+ known_keys & resource_params.keys.map! { |attr| scope.full_name(attr) }
26
29
  end
27
30
 
28
31
  def all_keys
29
- attrs.map { |attr| @scope.full_name(attr) }
32
+ attrs.map { |attr| scope.full_name(attr) }
30
33
  end
31
34
  end
32
35
  end
@@ -3,12 +3,14 @@
3
3
  module Grape
4
4
  module Validations
5
5
  module Validators
6
- class MutualExclusionValidator < MultipleParamsBase
6
+ class MutuallyExclusiveValidator < MultipleParamsBase
7
+ default_message_key :mutual_exclusion
8
+
7
9
  def validate_params!(params)
8
10
  keys = keys_in_common(params)
9
11
  return if keys.length <= 1
10
12
 
11
- raise Grape::Exceptions::Validation.new(params: keys, message: message(:mutual_exclusion))
13
+ validation_error!(keys)
12
14
  end
13
15
  end
14
16
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Validations
5
+ module Validators
6
+ # Validates that a Hash parameter matches at least one of a set of
7
+ # variant schemas. Each variant is a list of pre-built validators
8
+ # captured by evaluating the variant's block in a {Grape::Validations::OneofCollector}-backed
9
+ # {ParamsScope}. At request time we try each variant in order against
10
+ # a deep-dup of the value; the first variant that produces no errors
11
+ # wins and its (possibly coerced) hash replaces the original.
12
+ class OneofValidator < Base
13
+ default_message_key :oneof
14
+
15
+ def initialize(attrs, options, required, scope, opts)
16
+ super
17
+ @variants = Array(options)
18
+ end
19
+
20
+ def validate_param!(attr_name, params)
21
+ value = params[attr_name]
22
+ return if value.nil? && !required?
23
+
24
+ winning_candidate = nil
25
+ @variants.each do |variant_validators|
26
+ candidate = value.deep_dup
27
+ if variant_matches?(variant_validators, candidate)
28
+ winning_candidate = candidate
29
+ break
30
+ end
31
+ end
32
+
33
+ return params[attr_name] = winning_candidate if winning_candidate
34
+
35
+ validation_error!(attr_name)
36
+ end
37
+
38
+ private
39
+
40
+ def variant_matches?(variant_validators, candidate)
41
+ variant_validators.each { |v| v.validate!(candidate) }
42
+ true
43
+ rescue Grape::Exceptions::Validation, Grape::Exceptions::ValidationArrayErrors
44
+ false
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -4,10 +4,12 @@ module Grape
4
4
  module Validations
5
5
  module Validators
6
6
  class PresenceValidator < Base
7
+ default_message_key :presence
8
+
7
9
  def validate_param!(attr_name, params)
8
- return if params.respond_to?(:key?) && params.key?(attr_name)
10
+ return if hash_like?(params) && params.key?(attr_name)
9
11
 
10
- raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:presence))
12
+ validation_error!(attr_name)
11
13
  end
12
14
  end
13
15
  end
@@ -4,11 +4,19 @@ module Grape
4
4
  module Validations
5
5
  module Validators
6
6
  class RegexpValidator < Base
7
+ default_message_key :regexp
8
+
9
+ def initialize(attrs, options, required, scope, opts)
10
+ super
11
+ @value = option_value
12
+ end
13
+
7
14
  def validate_param!(attr_name, params)
8
- return unless params.respond_to?(:key?) && params.key?(attr_name)
9
- return if Array.wrap(params[attr_name]).all? { |param| param.nil? || param.to_s.match?((options_key?(:value) ? @option[:value] : @option)) }
15
+ return unless hash_like?(params) && params.key?(attr_name)
16
+
17
+ return if Array.wrap(params[attr_name]).all? { |param| param.nil? || scrub(param.to_s).match?(@value) }
10
18
 
11
- raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:regexp))
19
+ validation_error!(attr_name)
12
20
  end
13
21
  end
14
22
  end
@@ -4,24 +4,15 @@ module Grape
4
4
  module Validations
5
5
  module Validators
6
6
  class SameAsValidator < Base
7
- def validate_param!(attr_name, params)
8
- confirmation = options_key?(:value) ? @option[:value] : @option
9
- return if params[attr_name] == params[confirmation]
10
-
11
- raise Grape::Exceptions::Validation.new(
12
- params: [@scope.full_name(attr_name)],
13
- message: build_message
14
- )
7
+ def initialize(attrs, options, required, scope, opts)
8
+ super
9
+ @value = option_value
15
10
  end
16
11
 
17
- private
12
+ def validate_param!(attr_name, params)
13
+ return if params[attr_name] == params[@value]
18
14
 
19
- def build_message
20
- if options_key?(:message)
21
- @option[:message]
22
- else
23
- format I18n.t(:same_as, scope: 'grape.errors.messages'), parameter: @option
24
- end
15
+ validation_error!(attr_name, message { translate(:same_as, parameter: @value) })
25
16
  end
26
17
  end
27
18
  end
@@ -4,92 +4,63 @@ module Grape
4
4
  module Validations
5
5
  module Validators
6
6
  class ValuesValidator < Base
7
- def initialize(attrs, options, required, scope, **opts)
8
- if options.is_a?(Hash)
9
- @excepts = options[:except]
10
- @values = options[:value]
11
- @proc = options[:proc]
7
+ default_message_key :values
12
8
 
13
- ActiveSupport::Deprecation.warn('The values validator except option is deprecated. Use the except validator instead.') if @excepts
14
-
15
- raise ArgumentError, 'proc must be a Proc' if @proc && !@proc.is_a?(Proc)
16
-
17
- ActiveSupport::Deprecation.warn('The values validator proc option is deprecated. The lambda expression can now be assigned directly to values.') if @proc
9
+ def initialize(attrs, options, required, scope, opts)
10
+ super
11
+ values = option_value
12
+
13
+ # Zero-arity procs return a collection per-request (e.g. DB-backed lists).
14
+ # Non-zero-arity procs are per-element predicates, called directly at validation time.
15
+ # Non-Proc values are wrapped in a zero-arity lambda for a uniform call interface.
16
+ if values.is_a?(Proc)
17
+ @values_call = values
18
+ @values_is_predicate = !values.arity.zero?
18
19
  else
19
- @excepts = nil
20
- @values = nil
21
- @proc = nil
22
- @values = options
20
+ @values_call = -> { values }
21
+ @values_is_predicate = false
23
22
  end
24
- super
25
23
  end
26
24
 
27
25
  def validate_param!(attr_name, params)
28
- return unless params.is_a?(Hash)
26
+ return unless hash_like?(params)
29
27
 
30
- val = params[attr_name]
28
+ val = scrub(params[attr_name])
31
29
 
32
30
  return if val.nil? && !required_for_root_scope?
31
+ return if val != false && val.blank? && allow_blank?
32
+ return if check_values?(val, attr_name)
33
33
 
34
- # don't forget that +false.blank?+ is true
35
- return if val != false && val.blank? && @allow_blank
36
-
37
- param_array = val.nil? ? [nil] : Array.wrap(val)
38
-
39
- raise validation_exception(attr_name, except_message) \
40
- unless check_excepts(param_array)
41
-
42
- raise validation_exception(attr_name, message(:values)) \
43
- unless check_values(param_array, attr_name)
44
-
45
- raise validation_exception(attr_name, message(:values)) \
46
- if @proc && !validate_proc(@proc, param_array)
34
+ validation_error!(attr_name)
47
35
  end
48
36
 
49
37
  private
50
38
 
51
- def check_values(param_array, attr_name)
52
- values = @values.is_a?(Proc) && @values.arity.zero? ? @values.call : @values
53
- return true if values.nil?
54
-
55
- begin
56
- return param_array.all? { |param| values.call(param) } if values.is_a? Proc
57
- rescue StandardError => e
58
- warn "Error '#{e}' raised while validating attribute '#{attr_name}'"
59
- return false
60
- end
61
- param_array.all? { |param| values.include?(param) }
62
- end
63
-
64
- def check_excepts(param_array)
65
- excepts = @excepts.is_a?(Proc) ? @excepts.call : @excepts
66
- return true if excepts.nil?
67
-
68
- param_array.none? { |param| excepts.include?(param) }
69
- end
39
+ def check_values?(val, attr_name)
40
+ param_array = val.nil? ? [nil] : Array.wrap(val)
70
41
 
71
- def validate_proc(proc, param_array)
72
- case proc.arity
73
- when 0
74
- param_array.all? { |_param| proc.call }
75
- when 1
76
- param_array.all? { |param| proc.call(param) }
42
+ if @values_is_predicate
43
+ begin
44
+ param_array.all? { |param| @values_call.call(param) }
45
+ rescue StandardError => e
46
+ warn "Error '#{e}' raised while validating attribute '#{attr_name}'"
47
+ false
48
+ end
77
49
  else
78
- raise ArgumentError, 'proc arity must be 0 or 1'
79
- end
80
- end
50
+ values = @values_call.call
51
+ return true if values.nil?
81
52
 
82
- def except_message
83
- options = instance_variable_get(:@option)
84
- options_key?(:except_message) ? options[:except_message] : message(:except_values)
53
+ param_array.all? { |param| values.include?(param) }
54
+ end
85
55
  end
86
56
 
87
57
  def required_for_root_scope?
88
- @required && @scope.root?
89
- end
58
+ return false unless required?
59
+
60
+ current_scope = scope
61
+ current_scope = current_scope.parent while current_scope.lateral?
90
62
 
91
- def validation_exception(attr_name, message)
92
- Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message)
63
+ current_scope.root?
93
64
  end
94
65
  end
95
66
  end
@@ -1,34 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Grape
4
- # Registry to store and locate known Validators.
5
4
  module Validations
5
+ extend Grape::Util::Registry
6
+
6
7
  module_function
7
8
 
8
- def validators
9
- @validators ||= {}
10
- end
9
+ def require_validator(short_name)
10
+ raise Grape::Exceptions::UnknownValidator, short_name unless registry.key?(short_name)
11
11
 
12
- # Register a new validator, so it can be used to validate parameters.
13
- # @param short_name [String] all lower-case, no spaces
14
- # @param klass [Class] the validator class. Should inherit from
15
- # Validations::Base.
16
- def register_validator(short_name, klass)
17
- validators[short_name] = klass
12
+ registry[short_name]
18
13
  end
19
14
 
20
- def deregister_validator(short_name)
21
- validators.delete(short_name)
22
- end
15
+ def build_short_name(klass)
16
+ return if klass.name.blank?
23
17
 
24
- # Find a validator and if not found will try to load it
25
- def require_validator(short_name)
26
- str_name = short_name.to_s
27
- validators.fetch(str_name) do
28
- Grape::Validations::Validators.const_get("#{str_name.camelize}Validator")
29
- end
30
- rescue NameError
31
- raise Grape::Exceptions::UnknownValidator.new(short_name)
18
+ klass.name.demodulize.underscore.delete_suffix('_validator')
32
19
  end
33
20
  end
34
21
  end
data/lib/grape/version.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Grape
4
- # The current version of Grape.
5
- VERSION = '1.8.0'
4
+ VERSION = '3.3.5'
6
5
  end
data/lib/grape/xml.rb ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ # Since multi_xml 0.9.0 the canonical constant is MultiXML; MultiXml is a
5
+ # deprecated alias (removed in v1.0) that warns on use. Prefer MultiXML so
6
+ # Grape::Xml.parse doesn't trip the deprecation, falling back to the legacy
7
+ # constant and then ActiveSupport::XmlMini.
8
+ # https://github.com/sferik/multi_xml/blob/v0.9.1/CHANGELOG.md
9
+ if defined?(::MultiXML)
10
+ Xml = ::MultiXML
11
+ elsif defined?(::MultiXml)
12
+ Xml = ::MultiXml
13
+ else
14
+ Xml = ::ActiveSupport::XmlMini
15
+ Xml::ParseError = StandardError
16
+ end
17
+ end