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
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Grape::Validations::SingleAttributeIterator do
4
- describe '#each' do
5
- subject(:iterator) { described_class.new(validator, scope, params) }
6
-
7
- let(:scope) { Grape::Validations::ParamsScope.new(api: Class.new(Grape::API)) }
8
- let(:validator) { double(attrs: %i[first second]) }
9
-
10
- context 'when params is a hash' do
11
- let(:params) do
12
- { first: 'string', second: 'string' }
13
- end
14
-
15
- it 'yields params and every single attribute from the list' do
16
- expect { |b| iterator.each(&b) }
17
- .to yield_successive_args([params, :first, false], [params, :second, false])
18
- end
19
- end
20
-
21
- context 'when params is an array' do
22
- let(:params) do
23
- [{ first: 'string1', second: 'string1' }, { first: 'string2', second: 'string2' }]
24
- end
25
-
26
- it 'yields every single attribute from the list for each of the array elements' do
27
- expect { |b| iterator.each(&b) }.to yield_successive_args(
28
- [params[0], :first, false], [params[0], :second, false],
29
- [params[1], :first, false], [params[1], :second, false]
30
- )
31
- end
32
-
33
- context 'empty values' do
34
- let(:params) { [{}, '', 10] }
35
-
36
- it 'marks params with empty values' do
37
- expect { |b| iterator.each(&b) }.to yield_successive_args(
38
- [params[0], :first, true], [params[0], :second, true],
39
- [params[1], :first, true], [params[1], :second, true],
40
- [params[2], :first, false], [params[2], :second, false]
41
- )
42
- end
43
- end
44
-
45
- context 'when missing optional value' do
46
- let(:params) { [Grape::DSL::Parameters::EmptyOptionalValue, 10] }
47
-
48
- it 'does not yield skipped values' do
49
- expect { |b| iterator.each(&b) }.to yield_successive_args(
50
- [params[1], :first, false], [params[1], :second, false]
51
- )
52
- end
53
- end
54
- end
55
- end
56
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Grape::Validations::Types::ArrayCoercer do
4
- subject { described_class.new(type) }
5
-
6
- describe '#call' do
7
- context 'an array of primitives' do
8
- let(:type) { Array[String] }
9
-
10
- it 'coerces elements in the array' do
11
- expect(subject.call([10, 20])).to eq(%w[10 20])
12
- end
13
- end
14
-
15
- context 'an array of arrays' do
16
- let(:type) { Array[Array[Integer]] }
17
-
18
- it 'coerces elements in the nested array' do
19
- expect(subject.call([%w[10 20]])).to eq([[10, 20]])
20
- expect(subject.call([['10'], ['20']])).to eq([[10], [20]])
21
- end
22
- end
23
-
24
- context 'an array of sets' do
25
- let(:type) { Array[Set[Integer]] }
26
-
27
- it 'coerces elements in the nested set' do
28
- expect(subject.call([%w[10 20]])).to eq([Set[10, 20]])
29
- expect(subject.call([['10'], ['20']])).to eq([Set[10], Set[20]])
30
- end
31
- end
32
- end
33
- end
@@ -1,150 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Grape::Validations::Types::PrimitiveCoercer do
4
- subject { described_class.new(type, strict) }
5
-
6
- let(:strict) { false }
7
-
8
- describe '#call' do
9
- context 'BigDecimal' do
10
- let(:type) { BigDecimal }
11
-
12
- it 'coerces to BigDecimal' do
13
- expect(subject.call(5)).to eq(BigDecimal('5'))
14
- end
15
-
16
- it 'coerces an empty string to nil' do
17
- expect(subject.call('')).to be_nil
18
- end
19
- end
20
-
21
- context 'Boolean' do
22
- let(:type) { Grape::API::Boolean }
23
-
24
- [true, 'true', 1].each do |val|
25
- it "coerces '#{val}' to true" do
26
- expect(subject.call(val)).to be(true)
27
- end
28
- end
29
-
30
- [false, 'false', 0].each do |val|
31
- it "coerces '#{val}' to false" do
32
- expect(subject.call(val)).to be(false)
33
- end
34
- end
35
-
36
- it 'returns an error when the given value cannot be coerced' do
37
- expect(subject.call(123)).to be_instance_of(Grape::Validations::Types::InvalidValue)
38
- end
39
-
40
- it 'coerces an empty string to nil' do
41
- expect(subject.call('')).to be_nil
42
- end
43
- end
44
-
45
- context 'DateTime' do
46
- let(:type) { DateTime }
47
-
48
- it 'coerces an empty string to nil' do
49
- expect(subject.call('')).to be_nil
50
- end
51
- end
52
-
53
- context 'Float' do
54
- let(:type) { Float }
55
-
56
- it 'coerces an empty string to nil' do
57
- expect(subject.call('')).to be_nil
58
- end
59
- end
60
-
61
- context 'Integer' do
62
- let(:type) { Integer }
63
-
64
- it 'coerces an empty string to nil' do
65
- expect(subject.call('')).to be_nil
66
- end
67
-
68
- it 'accepts non-nil value' do
69
- expect(subject.call(42)).to be_a(Integer)
70
- end
71
- end
72
-
73
- context 'Numeric' do
74
- let(:type) { Numeric }
75
-
76
- it 'coerces an empty string to nil' do
77
- expect(subject.call('')).to be_nil
78
- end
79
-
80
- it 'accepts a non-nil value' do
81
- expect(subject.call(42)).to be_a(Numeric) # in fact Integer
82
- end
83
- end
84
-
85
- context 'Time' do
86
- let(:type) { Time }
87
-
88
- it 'coerces an empty string to nil' do
89
- expect(subject.call('')).to be_nil
90
- end
91
- end
92
-
93
- context 'String' do
94
- let(:type) { String }
95
-
96
- it 'coerces to String' do
97
- expect(subject.call(10)).to eq('10')
98
- end
99
-
100
- it 'does not coerce an empty string to nil' do
101
- expect(subject.call('')).to eq('')
102
- end
103
- end
104
-
105
- context 'Symbol' do
106
- let(:type) { Symbol }
107
-
108
- it 'coerces an empty string to nil' do
109
- expect(subject.call('')).to be_nil
110
- end
111
- end
112
-
113
- context 'a type unknown in Dry-types' do
114
- let(:type) { Complex }
115
-
116
- it 'raises error on init' do
117
- expect(DryTypes::Params.constants).not_to include(type.name.to_sym)
118
- expect { subject }.to raise_error(/type Complex should support coercion/)
119
- end
120
- end
121
-
122
- context 'the strict mode' do
123
- let(:strict) { true }
124
-
125
- context 'Boolean' do
126
- let(:type) { Grape::API::Boolean }
127
-
128
- it 'returns an error when the given value is not Boolean' do
129
- expect(subject.call(1)).to be_instance_of(Grape::Validations::Types::InvalidValue)
130
- end
131
-
132
- it 'returns a value as it is when the given value is Boolean' do
133
- expect(subject.call(true)).to be(true)
134
- end
135
- end
136
-
137
- context 'BigDecimal' do
138
- let(:type) { BigDecimal }
139
-
140
- it 'returns an error when the given value is not BigDecimal' do
141
- expect(subject.call(1)).to be_instance_of(Grape::Validations::Types::InvalidValue)
142
- end
143
-
144
- it 'returns a value as it is when the given value is BigDecimal' do
145
- expect(subject.call(BigDecimal('0'))).to eq(BigDecimal('0'))
146
- end
147
- end
148
- end
149
- end
150
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Grape::Validations::Types::SetCoercer do
4
- subject { described_class.new(type) }
5
-
6
- describe '#call' do
7
- context 'a set of primitives' do
8
- let(:type) { Set[String] }
9
-
10
- it 'coerces elements to the set' do
11
- expect(subject.call([10, 20])).to eq(Set['10', '20'])
12
- end
13
- end
14
-
15
- context 'a set of sets' do
16
- let(:type) { Set[Set[Integer]] }
17
-
18
- it 'coerces elements in the nested set' do
19
- expect(subject.call([%w[10 20]])).to eq(Set[Set[10, 20]])
20
- expect(subject.call([['10'], ['20']])).to eq(Set[Set[10], Set[20]])
21
- end
22
- end
23
-
24
- context 'a set of sets of arrays' do
25
- let(:type) { Set[Set[Array[Integer]]] }
26
-
27
- it 'coerces elements in the nested set' do
28
- expect(subject.call([[['10'], ['20']]])).to eq(Set[Set[Array[10], Array[20]]])
29
- end
30
- end
31
- end
32
- end
@@ -1,111 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Grape::Validations::Types do
4
- module TypesSpec
5
- class FooType
6
- def self.parse(_); end
7
- end
8
-
9
- class BarType
10
- def self.parse; end
11
- end
12
- end
13
-
14
- describe '::primitive?' do
15
- [
16
- Integer, Float, Numeric, BigDecimal,
17
- Grape::API::Boolean, String, Symbol,
18
- Date, DateTime, Time
19
- ].each do |type|
20
- it "recognizes #{type} as a primitive" do
21
- expect(described_class).to be_primitive(type)
22
- end
23
- end
24
-
25
- it 'identifies unknown types' do
26
- expect(described_class).not_to be_primitive(Object)
27
- expect(described_class).not_to be_primitive(TypesSpec::FooType)
28
- end
29
- end
30
-
31
- describe '::structure?' do
32
- [
33
- Hash, Array, Set
34
- ].each do |type|
35
- it "recognizes #{type} as a structure" do
36
- expect(described_class).to be_structure(type)
37
- end
38
- end
39
- end
40
-
41
- describe '::special?' do
42
- [
43
- JSON, Array[JSON], File, Rack::Multipart::UploadedFile
44
- ].each do |type|
45
- it "provides special handling for #{type.inspect}" do
46
- expect(described_class).to be_special(type)
47
- end
48
- end
49
- end
50
-
51
- describe 'special types' do
52
- subject { described_class::SPECIAL[type] }
53
-
54
- context 'when JSON' do
55
- let(:type) { JSON }
56
-
57
- it { is_expected.to eq(Grape::Validations::Types::Json) }
58
- end
59
-
60
- context 'when Array[JSON]' do
61
- let(:type) { Array[JSON] }
62
-
63
- it { is_expected.to eq(Grape::Validations::Types::JsonArray) }
64
- end
65
-
66
- context 'when File' do
67
- let(:type) { File }
68
-
69
- it { is_expected.to eq(Grape::Validations::Types::File) }
70
- end
71
-
72
- context 'when Rack::Multipart::UploadedFile' do
73
- let(:type) { Rack::Multipart::UploadedFile }
74
-
75
- it { is_expected.to eq(Grape::Validations::Types::File) }
76
- end
77
- end
78
-
79
- describe '::custom?' do
80
- it 'returns false if the type does not respond to :parse' do
81
- expect(described_class).not_to be_custom(Object)
82
- end
83
-
84
- it 'returns true if the type responds to :parse with one argument' do
85
- expect(described_class).to be_custom(TypesSpec::FooType)
86
- end
87
-
88
- it 'returns false if the type\'s #parse method takes other than one argument' do
89
- expect(described_class).not_to be_custom(TypesSpec::BarType)
90
- end
91
- end
92
-
93
- describe '::build_coercer' do
94
- it 'has internal cache variables' do
95
- expect(described_class.instance_variable_get(:@__cache)).to be_a(Hash)
96
- expect(described_class.instance_variable_get(:@__cache_write_lock)).to be_a(Mutex)
97
- end
98
-
99
- it 'caches the result of the build_coercer method' do
100
- original_cache = described_class.instance_variable_get(:@__cache)
101
- described_class.instance_variable_set(:@__cache, {})
102
-
103
- a_coercer = described_class.build_coercer(Array[String])
104
- b_coercer = described_class.build_coercer(Array[String])
105
-
106
- expect(a_coercer.object_id).to eq(b_coercer.object_id)
107
-
108
- described_class.instance_variable_set(:@__cache, original_cache)
109
- end
110
- end
111
- end
@@ -1,162 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Grape::Validations::Validators::AllOrNoneOfValidator do
4
- let_it_be(:app) do
5
- Class.new(Grape::API) do
6
- rescue_from Grape::Exceptions::ValidationErrors do |e|
7
- error!(e.errors.transform_keys! { |key| key.join(',') }, 400)
8
- end
9
-
10
- params do
11
- optional :beer, :wine, type: Grape::API::Boolean
12
- all_or_none_of :beer, :wine
13
- end
14
- post do
15
- end
16
-
17
- params do
18
- optional :beer, :wine, :other, type: Grape::API::Boolean
19
- all_or_none_of :beer, :wine
20
- end
21
- post 'mixed-params' do
22
- end
23
-
24
- params do
25
- optional :beer, :wine, type: Grape::API::Boolean
26
- all_or_none_of :beer, :wine, message: 'choose all or none'
27
- end
28
- post '/custom-message' do
29
- end
30
-
31
- params do
32
- requires :item, type: Hash do
33
- optional :beer, :wine, type: Grape::API::Boolean
34
- all_or_none_of :beer, :wine
35
- end
36
- end
37
- post '/nested-hash' do
38
- end
39
-
40
- params do
41
- requires :items, type: Array do
42
- optional :beer, :wine, type: Grape::API::Boolean
43
- all_or_none_of :beer, :wine
44
- end
45
- end
46
- post '/nested-array' do
47
- end
48
-
49
- params do
50
- requires :items, type: Array do
51
- requires :nested_items, type: Array do
52
- optional :beer, :wine, type: Grape::API::Boolean
53
- all_or_none_of :beer, :wine
54
- end
55
- end
56
- end
57
- post '/deeply-nested-array' do
58
- end
59
- end
60
- end
61
-
62
- describe '#validate!' do
63
- subject(:validate) { post path, params }
64
-
65
- context 'when all restricted params are present' do
66
- let(:path) { '/' }
67
- let(:params) { { beer: true, wine: true } }
68
-
69
- it 'does not return a validation error' do
70
- validate
71
- expect(last_response.status).to eq 201
72
- end
73
-
74
- context 'mixed with other params' do
75
- let(:path) { '/mixed-params' }
76
- let(:params) { { beer: true, wine: true, other: true } }
77
-
78
- it 'does not return a validation error' do
79
- validate
80
- expect(last_response.status).to eq 201
81
- end
82
- end
83
- end
84
-
85
- context 'when a subset of restricted params are present' do
86
- let(:path) { '/' }
87
- let(:params) { { beer: true } }
88
-
89
- it 'returns a validation error' do
90
- validate
91
- expect(last_response.status).to eq 400
92
- expect(JSON.parse(last_response.body)).to eq(
93
- 'beer,wine' => ['provide all or none of parameters']
94
- )
95
- end
96
- end
97
-
98
- context 'when custom message is specified' do
99
- let(:path) { '/custom-message' }
100
- let(:params) { { beer: true } }
101
-
102
- it 'returns a validation error' do
103
- validate
104
- expect(last_response.status).to eq 400
105
- expect(JSON.parse(last_response.body)).to eq(
106
- 'beer,wine' => ['choose all or none']
107
- )
108
- end
109
- end
110
-
111
- context 'when no restricted params are present' do
112
- let(:path) { '/' }
113
- let(:params) { { somethingelse: true } }
114
-
115
- it 'does not return a validation error' do
116
- validate
117
- expect(last_response.status).to eq 201
118
- end
119
- end
120
-
121
- context 'when restricted params are nested inside required hash' do
122
- let(:path) { '/nested-hash' }
123
- let(:params) { { item: { beer: true } } }
124
-
125
- it 'returns a validation error with full names of the params' do
126
- validate
127
- expect(last_response.status).to eq 400
128
- expect(JSON.parse(last_response.body)).to eq(
129
- 'item[beer],item[wine]' => ['provide all or none of parameters']
130
- )
131
- end
132
- end
133
-
134
- context 'when mutually exclusive params are nested inside array' do
135
- let(:path) { '/nested-array' }
136
- let(:params) { { items: [{ beer: true, wine: true }, { wine: true }] } }
137
-
138
- it 'returns a validation error with full names of the params' do
139
- validate
140
- expect(last_response.status).to eq 400
141
- expect(JSON.parse(last_response.body)).to eq(
142
- 'items[1][beer],items[1][wine]' => ['provide all or none of parameters']
143
- )
144
- end
145
- end
146
-
147
- context 'when mutually exclusive params are deeply nested' do
148
- let(:path) { '/deeply-nested-array' }
149
- let(:params) { { items: [{ nested_items: [{ beer: true }] }] } }
150
-
151
- it 'returns a validation error with full names of the params' do
152
- validate
153
- expect(last_response.status).to eq 400
154
- expect(JSON.parse(last_response.body)).to eq(
155
- 'items[0][nested_items][0][beer],items[0][nested_items][0][wine]' => [
156
- 'provide all or none of parameters'
157
- ]
158
- )
159
- end
160
- end
161
- end
162
- end