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,94 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'array_coercer'
4
- require_relative 'set_coercer'
5
- require_relative 'primitive_coercer'
6
-
7
- module Grape
8
- module Validations
9
- module Types
10
- # Chooses the best coercer for the given type. For example, if the type
11
- # is Integer, it will return a coercer which will be able to coerce a value
12
- # to the integer.
13
- #
14
- # There are a few very special coercers which might be returned.
15
- #
16
- # +Grape::Types::MultipleTypeCoercer+ is a coercer which is returned when
17
- # the given type implies values in an array with different types.
18
- # For example, +[Integer, String]+ allows integer and string values in
19
- # an array.
20
- #
21
- # +Grape::Types::CustomTypeCoercer+ is a coercer which is returned when
22
- # a method is specified by a user with +coerce_with+ option or the user
23
- # specifies a custom type which implements requirments of
24
- # +Grape::Types::CustomTypeCoercer+.
25
- #
26
- # +Grape::Types::CustomTypeCollectionCoercer+ is a very similar to the
27
- # previous one, but it expects an array or set of values having a custom
28
- # type implemented by the user.
29
- #
30
- # There is also a group of custom types implemented by Grape, check
31
- # +Grape::Validations::Types::SPECIAL+ to get the full list.
32
- #
33
- # @param type [Class] the type to which input strings
34
- # should be coerced
35
- # @param method [Class,#call] the coercion method to use
36
- # @return [Object] object to be used
37
- # for coercion and type validation
38
- def self.build_coercer(type, method: nil, strict: false)
39
- cache_instance(type, method, strict) do
40
- create_coercer_instance(type, method, strict)
41
- end
42
- end
43
-
44
- def self.create_coercer_instance(type, method, strict)
45
- # Maps a custom type provided by Grape, it doesn't map types wrapped by collections!!!
46
- type = Types.map_special(type)
47
-
48
- # Use a special coercer for multiply-typed parameters.
49
- if Types.multiple?(type)
50
- MultipleTypeCoercer.new(type, method)
51
-
52
- # Use a special coercer for custom types and coercion methods.
53
- elsif method || Types.custom?(type)
54
- CustomTypeCoercer.new(type, method)
55
-
56
- # Special coercer for collections of types that implement a parse method.
57
- # CustomTypeCoercer (above) already handles such types when an explicit coercion
58
- # method is supplied.
59
- elsif Types.collection_of_custom?(type)
60
- Types::CustomTypeCollectionCoercer.new(
61
- Types.map_special(type.first), type.is_a?(Set)
62
- )
63
- else
64
- DryTypeCoercer.coercer_instance_for(type, strict)
65
- end
66
- end
67
-
68
- def self.cache_instance(type, method, strict, &_block)
69
- key = cache_key(type, method, strict)
70
-
71
- return @__cache[key] if @__cache.key?(key)
72
-
73
- instance = yield
74
-
75
- @__cache_write_lock.synchronize do
76
- @__cache[key] = instance
77
- end
78
-
79
- instance
80
- end
81
-
82
- def self.cache_key(type, method, strict)
83
- [type, method, strict].each_with_object(+'_') do |val, memo|
84
- next if val.nil?
85
-
86
- memo << '_' << val.to_s
87
- end
88
- end
89
-
90
- instance_variable_set(:@__cache, {})
91
- instance_variable_set(:@__cache_write_lock, Mutex.new)
92
- end
93
- end
94
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Grape
4
- module Validations
5
- class ValidatorFactory
6
- def self.create_validator(**options)
7
- options[:validator_class].new(options[:attributes],
8
- options[:options],
9
- options[:required],
10
- options[:params_scope],
11
- **options[:opts])
12
- end
13
- end
14
- end
15
- end
@@ -1,213 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'shared/deprecated_class_examples'
4
-
5
- describe Grape::Validations do
6
- describe 'Grape::Validations::Base' do
7
- let(:deprecated_class) do
8
- Class.new(Grape::Validations::Base)
9
- end
10
-
11
- it_behaves_like 'deprecated class'
12
- end
13
-
14
- describe 'using a custom length validator' do
15
- subject do
16
- Class.new(Grape::API) do
17
- params do
18
- requires :text, default_length: 140
19
- end
20
- get do
21
- 'bacon'
22
- end
23
- end
24
- end
25
-
26
- let(:default_length_validator) do
27
- Class.new(Grape::Validations::Validators::Base) do
28
- def validate_param!(attr_name, params)
29
- @option = params[:max].to_i if params.key?(:max)
30
- return if params[attr_name].length <= @option
31
-
32
- raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long")
33
- end
34
- end
35
- end
36
- let(:app) { Rack::Builder.new(subject) }
37
-
38
- before do
39
- described_class.register_validator('default_length', default_length_validator)
40
- end
41
-
42
- after do
43
- described_class.deregister_validator('default_length')
44
- end
45
-
46
- it 'under 140 characters' do
47
- get '/', text: 'abc'
48
- expect(last_response.status).to eq 200
49
- expect(last_response.body).to eq 'bacon'
50
- end
51
-
52
- it 'over 140 characters' do
53
- get '/', text: 'a' * 141
54
- expect(last_response.status).to eq 400
55
- expect(last_response.body).to eq 'text must be at the most 140 characters long'
56
- end
57
-
58
- it 'specified in the query string' do
59
- get '/', text: 'a' * 141, max: 141
60
- expect(last_response.status).to eq 200
61
- expect(last_response.body).to eq 'bacon'
62
- end
63
- end
64
-
65
- describe 'using a custom body-only validator' do
66
- subject do
67
- Class.new(Grape::API) do
68
- params do
69
- requires :text, in_body: true
70
- end
71
- get do
72
- 'bacon'
73
- end
74
- end
75
- end
76
-
77
- let(:in_body_validator) do
78
- Class.new(Grape::Validations::Validators::PresenceValidator) do
79
- def validate(request)
80
- validate!(request.env['api.request.body'])
81
- end
82
- end
83
- end
84
- let(:app) { Rack::Builder.new(subject) }
85
-
86
- before do
87
- described_class.register_validator('in_body', in_body_validator)
88
- end
89
-
90
- after do
91
- described_class.deregister_validator('in_body')
92
- end
93
-
94
- it 'allows field in body' do
95
- get '/', text: 'abc'
96
- expect(last_response.status).to eq 200
97
- expect(last_response.body).to eq 'bacon'
98
- end
99
-
100
- it 'ignores field in query' do
101
- get '/', nil, text: 'abc'
102
- expect(last_response.status).to eq 400
103
- expect(last_response.body).to eq 'text is missing'
104
- end
105
- end
106
-
107
- describe 'using a custom validator with message_key' do
108
- subject do
109
- Class.new(Grape::API) do
110
- params do
111
- requires :text, with_message_key: true
112
- end
113
- get do
114
- 'bacon'
115
- end
116
- end
117
- end
118
-
119
- let(:message_key_validator) do
120
- Class.new(Grape::Validations::Validators::PresenceValidator) do
121
- def validate_param!(attr_name, _params)
122
- raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: :presence)
123
- end
124
- end
125
- end
126
- let(:app) { Rack::Builder.new(subject) }
127
-
128
- before do
129
- described_class.register_validator('with_message_key', message_key_validator)
130
- end
131
-
132
- after do
133
- described_class.deregister_validator('with_message_key')
134
- end
135
-
136
- it 'fails with message' do
137
- get '/', text: 'foobar'
138
- expect(last_response.status).to eq 400
139
- expect(last_response.body).to eq 'text is missing'
140
- end
141
- end
142
-
143
- describe 'using a custom request/param validator' do
144
- subject do
145
- Class.new(Grape::API) do
146
- params do
147
- optional :admin_field, type: String, admin: true
148
- optional :non_admin_field, type: String
149
- optional :admin_false_field, type: String, admin: false
150
- end
151
- get do
152
- 'bacon'
153
- end
154
- end
155
- end
156
-
157
- let(:admin_validator) do
158
- Class.new(Grape::Validations::Validators::Base) do
159
- def validate(request)
160
- # return if the param we are checking was not in request
161
- # @attrs is a list containing the attribute we are currently validating
162
- return unless request.params.key? @attrs.first
163
- # check if admin flag is set to true
164
- return unless @option
165
- # check if user is admin or not
166
- # as an example get a token from request and check if it's admin or not
167
- raise Grape::Exceptions::Validation.new(params: @attrs, message: 'Can not set Admin only field.') unless request.headers['X-Access-Token'] == 'admin'
168
- end
169
- end
170
- end
171
- let(:app) { Rack::Builder.new(subject) }
172
-
173
- before do
174
- described_class.register_validator('admin', admin_validator)
175
- end
176
-
177
- after do
178
- described_class.deregister_validator('admin')
179
- end
180
-
181
- it 'fail when non-admin user sets an admin field' do
182
- get '/', admin_field: 'tester', non_admin_field: 'toaster'
183
- expect(last_response.status).to eq 400
184
- expect(last_response.body).to include 'Can not set Admin only field.'
185
- end
186
-
187
- it 'does not fail when we send non-admin fields only' do
188
- get '/', non_admin_field: 'toaster'
189
- expect(last_response.status).to eq 200
190
- expect(last_response.body).to eq 'bacon'
191
- end
192
-
193
- it 'does not fail when we send non-admin and admin=false fields only' do
194
- get '/', non_admin_field: 'toaster', admin_false_field: 'test'
195
- expect(last_response.status).to eq 200
196
- expect(last_response.body).to eq 'bacon'
197
- end
198
-
199
- it 'does not fail when we send admin fields and we are admin' do
200
- header 'X-Access-Token', 'admin'
201
- get '/', admin_field: 'tester', non_admin_field: 'toaster', admin_false_field: 'test'
202
- expect(last_response.status).to eq 200
203
- expect(last_response.body).to eq 'bacon'
204
- end
205
-
206
- it 'fails when we send admin fields and we are not admin' do
207
- header 'X-Access-Token', 'user'
208
- get '/', admin_field: 'tester', non_admin_field: 'toaster', admin_false_field: 'test'
209
- expect(last_response.status).to eq 400
210
- expect(last_response.body).to include 'Can not set Admin only field.'
211
- end
212
- end
213
- end
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DeeplyIncludedOptionsSpec
4
- module Defaults
5
- extend ActiveSupport::Concern
6
- included do
7
- format :json
8
- end
9
- end
10
-
11
- module Admin
12
- module Defaults
13
- extend ActiveSupport::Concern
14
- include DeeplyIncludedOptionsSpec::Defaults
15
- end
16
-
17
- class Users < Grape::API
18
- include DeeplyIncludedOptionsSpec::Admin::Defaults
19
-
20
- resource :users do
21
- get do
22
- status 200
23
- end
24
- end
25
- end
26
- end
27
-
28
- class Main < Grape::API
29
- mount DeeplyIncludedOptionsSpec::Admin::Users
30
- end
31
- end
32
-
33
- describe Grape::API do
34
- subject { DeeplyIncludedOptionsSpec::Main }
35
-
36
- def app
37
- subject
38
- end
39
-
40
- it 'works for unspecified format' do
41
- get '/users'
42
- expect(last_response.status).to be 200
43
- expect(last_response.content_type).to eql 'application/json'
44
- end
45
-
46
- it 'works for specified format' do
47
- get '/users.json'
48
- expect(last_response.status).to be 200
49
- expect(last_response.content_type).to eql 'application/json'
50
- end
51
-
52
- it "doesn't work for format different than specified" do
53
- get '/users.txt'
54
- expect(last_response.status).to be 404
55
- end
56
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Grape::API::Instance do
4
- describe 'boolean constant' do
5
- module DefinesBooleanInstanceSpec
6
- class API < Grape::API
7
- params do
8
- requires :message, type: Boolean
9
- end
10
- post :echo do
11
- { class: params[:message].class.name, value: params[:message] }
12
- end
13
- end
14
- end
15
-
16
- def app
17
- DefinesBooleanInstanceSpec::API
18
- end
19
-
20
- let(:expected_body) do
21
- { class: 'TrueClass', value: true }.to_s
22
- end
23
-
24
- it 'sets Boolean as a type' do
25
- post '/echo?message=true'
26
- expect(last_response.status).to eq(201)
27
- expect(last_response.body).to eq expected_body
28
- end
29
-
30
- context 'Params endpoint type' do
31
- subject { DefinesBooleanInstanceSpec::API.new.router.map['POST'].first.options[:params]['message'][:type] }
32
-
33
- it 'params type is a boolean' do
34
- expect(subject).to eq 'Grape::API::Boolean'
35
- end
36
- end
37
- end
38
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Grape::API do
6
- subject { Class.new(described_class) }
7
-
8
- let(:app) { subject }
9
-
10
- context 'an endpoint with documentation' do
11
- it 'documents parameters' do
12
- subject.params do
13
- requires 'price', type: Float, desc: 'Sales price'
14
- end
15
- subject.get '/'
16
-
17
- expect(subject.routes.first.params['price']).to eq(required: true,
18
- type: 'Float',
19
- desc: 'Sales price')
20
- end
21
-
22
- it 'allows documentation with a hash' do
23
- documentation = { example: 'Joe' }
24
-
25
- subject.params do
26
- requires 'first_name', documentation: documentation
27
- end
28
- subject.get '/'
29
-
30
- expect(subject.routes.first.params['first_name'][:documentation]).to eq(documentation)
31
- end
32
- end
33
-
34
- context 'an endpoint without documentation' do
35
- before do
36
- subject.do_not_document!
37
-
38
- subject.params do
39
- requires :city, type: String, desc: 'Should be ignored'
40
- optional :postal_code, type: Integer
41
- end
42
- subject.post '/' do
43
- declared(params).to_json
44
- end
45
- end
46
-
47
- it 'does not document parameters for the endpoint' do
48
- expect(subject.routes.first.params).to eq({})
49
- end
50
-
51
- it 'still declares params internally' do
52
- data = { city: 'Berlin', postal_code: 10_115 }
53
-
54
- post '/', data
55
-
56
- expect(last_response.body).to eq(data.to_json)
57
- end
58
- end
59
- end
@@ -1,114 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Grape::API::Helpers do
4
- let(:user) { 'Miguel Caneo' }
5
- let(:id) { '42' }
6
-
7
- module InheritedHelpersSpec
8
- class SuperClass < Grape::API
9
- helpers do
10
- params(:superclass_params) { requires :id, type: String }
11
-
12
- def current_user
13
- params[:user]
14
- end
15
- end
16
- end
17
-
18
- class OverriddenSubClass < SuperClass
19
- params { use :superclass_params }
20
-
21
- helpers do
22
- def current_user
23
- "#{params[:user]} with id"
24
- end
25
- end
26
-
27
- get 'resource' do
28
- "#{current_user}: #{params['id']}"
29
- end
30
- end
31
-
32
- class SubClass < SuperClass
33
- params { use :superclass_params }
34
-
35
- get 'resource' do
36
- "#{current_user}: #{params['id']}"
37
- end
38
- end
39
-
40
- class Example < SubClass
41
- params { use :superclass_params }
42
-
43
- get 'resource' do
44
- "#{current_user}: #{params['id']}"
45
- end
46
- end
47
- end
48
-
49
- context 'non overriding subclass' do
50
- subject { InheritedHelpersSpec::SubClass }
51
-
52
- def app
53
- subject
54
- end
55
-
56
- context 'given expected params' do
57
- it 'inherits helpers from a superclass' do
58
- get '/resource', id: id, user: user
59
- expect(last_response.body).to eq("#{user}: #{id}")
60
- end
61
- end
62
-
63
- context 'with lack of expected params' do
64
- it 'returns missing error' do
65
- get '/resource'
66
- expect(last_response.body).to eq('id is missing')
67
- end
68
- end
69
- end
70
-
71
- context 'overriding subclass' do
72
- subject { InheritedHelpersSpec::OverriddenSubClass }
73
-
74
- def app
75
- subject
76
- end
77
-
78
- context 'given expected params' do
79
- it 'overrides helpers from a superclass' do
80
- get '/resource', id: id, user: user
81
- expect(last_response.body).to eq("#{user} with id: #{id}")
82
- end
83
- end
84
-
85
- context 'with lack of expected params' do
86
- it 'returns missing error' do
87
- get '/resource'
88
- expect(last_response.body).to eq('id is missing')
89
- end
90
- end
91
- end
92
-
93
- context 'example subclass' do
94
- subject { InheritedHelpersSpec::Example }
95
-
96
- def app
97
- subject
98
- end
99
-
100
- context 'given expected params' do
101
- it 'inherits helpers from a superclass' do
102
- get '/resource', id: id, user: user
103
- expect(last_response.body).to eq("#{user}: #{id}")
104
- end
105
- end
106
-
107
- context 'with lack of expected params' do
108
- it 'returns missing error' do
109
- get '/resource'
110
- expect(last_response.body).to eq('id is missing')
111
- end
112
- end
113
- end
114
- end
@@ -1,103 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'shared/versioning_examples'
4
-
5
- describe Grape::API::Instance do
6
- subject(:an_instance) do
7
- Class.new(Grape::API::Instance) do
8
- namespace :some_namespace do
9
- get 'some_endpoint' do
10
- 'success'
11
- end
12
- end
13
- end
14
- end
15
-
16
- let(:root_api) do
17
- to_mount = an_instance
18
- Class.new(Grape::API) do
19
- mount to_mount
20
- end
21
- end
22
-
23
- def app
24
- root_api
25
- end
26
-
27
- context 'when an instance is mounted on the root' do
28
- it 'can call the instance endpoint' do
29
- get '/some_namespace/some_endpoint'
30
- expect(last_response.body).to eq 'success'
31
- end
32
- end
33
-
34
- context 'when an instance is the root' do
35
- let(:root_api) do
36
- to_mount = an_instance
37
- Class.new(Grape::API::Instance) do
38
- mount to_mount
39
- end
40
- end
41
-
42
- it 'can call the instance endpoint' do
43
- get '/some_namespace/some_endpoint'
44
- expect(last_response.body).to eq 'success'
45
- end
46
- end
47
-
48
- context 'top level setting' do
49
- it 'does not inherit settings from the superclass (Grape::API::Instance)' do
50
- expect(an_instance.top_level_setting.parent).to be_nil
51
- end
52
- end
53
-
54
- context 'with multiple moutes' do
55
- let(:first) do
56
- Class.new(Grape::API::Instance) do
57
- namespace(:some_namespace) do
58
- route :any, '*path' do
59
- error!('Not found! (1)', 404)
60
- end
61
- end
62
- end
63
- end
64
- let(:second) do
65
- Class.new(Grape::API::Instance) do
66
- namespace(:another_namespace) do
67
- route :any, '*path' do
68
- error!('Not found! (2)', 404)
69
- end
70
- end
71
- end
72
- end
73
- let(:root_api) do
74
- first_instance = first
75
- second_instance = second
76
- Class.new(Grape::API) do
77
- mount first_instance
78
- mount first_instance
79
- mount second_instance
80
- end
81
- end
82
-
83
- it 'does not raise a FrozenError on first instance' do
84
- expect { patch '/some_namespace/anything' }.not_to \
85
- raise_error
86
- end
87
-
88
- it 'responds the correct body at the first instance' do
89
- patch '/some_namespace/anything'
90
- expect(last_response.body).to eq 'Not found! (1)'
91
- end
92
-
93
- it 'does not raise a FrozenError on second instance' do
94
- expect { get '/another_namespace/other' }.not_to \
95
- raise_error
96
- end
97
-
98
- it 'responds the correct body at the second instance' do
99
- get '/another_namespace/foobar'
100
- expect(last_response.body).to eq 'Not found! (2)'
101
- end
102
- end
103
- end