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
@@ -3,76 +3,95 @@
3
3
  module Grape
4
4
  module DSL
5
5
  module Helpers
6
- extend ActiveSupport::Concern
7
- include Grape::DSL::Configuration
8
-
9
- module ClassMethods
10
- # Add helper methods that will be accessible from any
11
- # endpoint within this namespace (and child namespaces).
12
- #
13
- # When called without a block, all known helpers within this scope
14
- # are included.
15
- #
16
- # @param [Array] new_modules optional array of modules to include
17
- # @param [Block] block optional block of methods to include
18
- #
19
- # @example Define some helpers.
20
- #
21
- # class ExampleAPI < Grape::API
22
- # helpers do
23
- # def current_user
24
- # User.find_by_id(params[:token])
25
- # end
26
- # end
27
- # end
28
- #
29
- # @example Include many modules
30
- #
31
- # class ExampleAPI < Grape::API
32
- # helpers Authentication, Mailer, OtherModule
33
- # end
34
- #
35
- def helpers(*new_modules, &block)
36
- include_new_modules(new_modules) if new_modules.any?
37
- include_block(block) if block
38
- include_all_in_scope if !block && new_modules.empty?
39
- end
6
+ # Add helper methods that will be accessible from any
7
+ # endpoint within this namespace (and child namespaces).
8
+ #
9
+ # When called without a block, all known helpers within this scope
10
+ # are included.
11
+ #
12
+ # @param [Array] new_modules optional array of modules to include
13
+ # @param [Block] block optional block of methods to include
14
+ #
15
+ # @example Define some helpers.
16
+ #
17
+ # class ExampleAPI < Grape::API
18
+ # helpers do
19
+ # def current_user
20
+ # User.find_by_id(params[:token])
21
+ # end
22
+ # end
23
+ # end
24
+ #
25
+ # @example Include many modules
26
+ #
27
+ # class ExampleAPI < Grape::API
28
+ # helpers Authentication, Mailer, OtherModule
29
+ # end
30
+ #
31
+ def helpers(*new_modules, &block)
32
+ include_new_modules(new_modules)
33
+ include_block(block)
34
+ include_all_in_scope if !block && new_modules.empty?
35
+ end
40
36
 
41
- protected
37
+ private
42
38
 
43
- def include_new_modules(modules)
44
- modules.each { |mod| make_inclusion(mod) }
45
- end
39
+ def include_new_modules(modules)
40
+ return if modules.empty?
46
41
 
47
- def include_block(block)
48
- Module.new.tap do |mod|
49
- make_inclusion(mod) { mod.class_eval(&block) }
50
- end
51
- end
42
+ modules.each { |mod| make_inclusion(mod) }
43
+ end
52
44
 
53
- def make_inclusion(mod, &block)
54
- define_boolean_in_mod(mod)
55
- inject_api_helpers_to_mod(mod, &block)
56
- namespace_stackable(:helpers, mod)
57
- end
45
+ def include_block(block)
46
+ return unless block
58
47
 
59
- def include_all_in_scope
60
- Module.new.tap do |mod|
61
- namespace_stackable(:helpers).each { |mod_to_include| mod.send :include, mod_to_include }
62
- change!
63
- end
64
- end
48
+ mod = Module.new
49
+ make_inclusion(mod) { mod.class_eval(&block) }
50
+ end
65
51
 
66
- def define_boolean_in_mod(mod)
67
- return if defined? mod::Boolean
52
+ def make_inclusion(mod, &)
53
+ define_boolean_in_mod(mod)
54
+ inject_api_helpers_to_mod(mod, &)
55
+ inheritable_setting.namespace_stackable[:helpers] = mod
56
+ end
68
57
 
69
- mod.const_set(:Boolean, Grape::API::Boolean)
70
- end
58
+ def include_all_in_scope
59
+ mod = Module.new
60
+ namespace_stackable(:helpers).each { |mod_to_include| mod.include mod_to_include }
61
+ change!
62
+ mod
63
+ end
64
+
65
+ def define_boolean_in_mod(mod)
66
+ return if defined? mod::Boolean
67
+
68
+ mod.const_set(:Boolean, Grape::API::Boolean)
69
+ end
70
+
71
+ def inject_api_helpers_to_mod(mod, &block)
72
+ mod.extend(BaseHelper) unless mod.is_a?(BaseHelper)
73
+ yield if block
74
+ warn_on_endpoint_overrides(mod) if Grape.config.warn_on_helper_overrides
75
+ mod.api_changed(self)
76
+ end
71
77
 
72
- def inject_api_helpers_to_mod(mod, &block)
73
- mod.extend(BaseHelper) unless mod.is_a?(BaseHelper)
74
- yield if block
75
- mod.api_changed(self)
78
+ # When +Grape.config.warn_on_helper_overrides+ is enabled, emit a
79
+ # warning to +$stderr+ for any helper method that masks an instance
80
+ # method on +Grape::Endpoint+. Helpers are mixed into the endpoint's
81
+ # singleton class and therefore take precedence over +Endpoint+
82
+ # instance methods — usually intentional, but a common source of
83
+ # surprise when the framework gains a method that already collides
84
+ # with an existing helper name.
85
+ def warn_on_endpoint_overrides(mod)
86
+ overridden = mod.instance_methods(false).select { |m| Grape::Endpoint.method_defined?(m) }
87
+ return if overridden.empty?
88
+
89
+ overridden.each do |name|
90
+ warn(
91
+ "Grape: helper method `#{name}` overrides Grape::Endpoint##{name}. " \
92
+ 'The helper takes precedence. To use the framework implementation, remove the helper. ' \
93
+ 'Silence this warning by setting Grape.config.warn_on_helper_overrides = false.'
94
+ )
76
95
  end
77
96
  end
78
97
 
@@ -94,9 +113,9 @@ module Grape
94
113
  protected
95
114
 
96
115
  def process_named_params
97
- return unless instance_variable_defined?(:@named_params) && @named_params && @named_params.any?
116
+ return if @named_params.blank?
98
117
 
99
- api.namespace_stackable(:named_params, @named_params)
118
+ api.inheritable_setting.namespace_stackable[:named_params] = @named_params
100
119
  end
101
120
  end
102
121
  end
@@ -1,150 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'grape/dsl/headers'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  module InsideRoute
8
- extend ActiveSupport::Concern
9
- include Grape::DSL::Settings
10
- include Grape::DSL::Headers
11
-
12
- # Denotes a situation where a DSL method has been invoked in a
13
- # filter which it should not yet be available in
14
- class MethodNotYetAvailable < StandardError; end
15
-
16
- # @param type [Symbol] The type of filter for which evaluation has been
17
- # completed
18
- # @return [Module] A module containing method overrides suitable for the
19
- # position in the filter evaluation sequence denoted by +type+. This
20
- # defaults to an empty module if no overrides are defined for the given
21
- # filter +type+.
22
- def self.post_filter_methods(type)
23
- @post_filter_modules ||= { before: PostBeforeFilter }
24
- @post_filter_modules[type]
25
- end
26
-
27
- # Methods which should not be available in filters until the before filter
28
- # has completed
29
- module PostBeforeFilter
30
- def declared(passed_params, options = {}, declared_params = nil, params_nested_path = [])
31
- options = options.reverse_merge(include_missing: true, include_parent_namespaces: true, evaluate_given: false)
32
- declared_params ||= optioned_declared_params(**options)
33
-
34
- if passed_params.is_a?(Array)
35
- declared_array(passed_params, options, declared_params, params_nested_path)
36
- else
37
- declared_hash(passed_params, options, declared_params, params_nested_path)
38
- end
39
- end
40
-
41
- private
42
-
43
- def declared_array(passed_params, options, declared_params, params_nested_path)
44
- passed_params.map do |passed_param|
45
- declared(passed_param || {}, options, declared_params, params_nested_path)
46
- end
47
- end
6
+ include Declared
7
+ include Entity
48
8
 
49
- def declared_hash(passed_params, options, declared_params, params_nested_path)
50
- declared_params.each_with_object(passed_params.class.new) do |declared_param_attr, memo|
51
- next if options[:evaluate_given] && !declared_param_attr.scope.attr_meets_dependency?(passed_params)
52
-
53
- declared_hash_attr(passed_params, options, declared_param_attr.key, params_nested_path, memo)
54
- end
55
- end
56
-
57
- def declared_hash_attr(passed_params, options, declared_param, params_nested_path, memo)
58
- renamed_params = route_setting(:renamed_params) || {}
59
- if declared_param.is_a?(Hash)
60
- declared_param.each_pair do |declared_parent_param, declared_children_params|
61
- params_nested_path_dup = params_nested_path.dup
62
- params_nested_path_dup << declared_parent_param.to_s
63
- next unless options[:include_missing] || passed_params.key?(declared_parent_param)
64
-
65
- rename_path = params_nested_path + [declared_parent_param.to_s]
66
- renamed_param_name = renamed_params[rename_path]
67
-
68
- memo_key = optioned_param_key(renamed_param_name || declared_parent_param, options)
69
- passed_children_params = passed_params[declared_parent_param] || passed_params.class.new
70
-
71
- memo[memo_key] = handle_passed_param(params_nested_path_dup, passed_children_params.any?) do
72
- declared(passed_children_params, options, declared_children_params, params_nested_path_dup)
73
- end
74
- end
75
- else
76
- # If it is not a Hash then it does not have children.
77
- # Find its value or set it to nil.
78
- return unless options[:include_missing] || passed_params.key?(declared_param)
79
-
80
- rename_path = params_nested_path + [declared_param.to_s]
81
- renamed_param_name = renamed_params[rename_path]
82
-
83
- memo_key = optioned_param_key(renamed_param_name || declared_param, options)
84
- passed_param = passed_params[declared_param]
85
-
86
- params_nested_path_dup = params_nested_path.dup
87
- params_nested_path_dup << declared_param.to_s
88
- memo[memo_key] = passed_param || handle_passed_param(params_nested_path_dup) do
89
- passed_param
90
- end
91
- end
92
- end
93
-
94
- def handle_passed_param(params_nested_path, has_passed_children = false, &_block)
95
- return yield if has_passed_children
96
-
97
- key = params_nested_path[0]
98
- key += "[#{params_nested_path[1..].join('][')}]" if params_nested_path.size > 1
99
-
100
- route_options_params = options[:route_options][:params] || {}
101
- type = route_options_params.dig(key, :type)
102
- has_children = route_options_params.keys.any? { |k| k != key && k.start_with?(key) }
103
-
104
- if type == 'Hash' && !has_children
105
- {}
106
- elsif type == 'Array' || (type&.start_with?('[') && type&.exclude?(','))
107
- []
108
- elsif type == 'Set' || type&.start_with?('#<Set')
109
- Set.new
110
- else
111
- yield
112
- end
113
- end
114
-
115
- def optioned_param_key(declared_param, options)
116
- options[:stringify] ? declared_param.to_s : declared_param.to_sym
117
- end
118
-
119
- def optioned_declared_params(**options)
120
- declared_params = if options[:include_parent_namespaces]
121
- # Declared params including parent namespaces
122
- route_setting(:declared_params)
123
- else
124
- # Declared params at current namespace
125
- namespace_stackable(:declared_params).last || []
126
- end
127
-
128
- raise ArgumentError, 'Tried to filter for declared parameters but none exist.' unless declared_params
129
-
130
- declared_params
131
- end
132
- end
133
-
134
- # A filtering method that will return a hash
135
- # consisting only of keys that have been declared by a
136
- # `params` statement against the current/target endpoint or parent
137
- # namespaces.
138
- #
139
- # @see +PostBeforeFilter#declared+
140
- #
141
- # @param params [Hash] The initial hash to filter. Usually this will just be `params`
142
- # @param options [Hash] Can pass `:include_missing`, `:stringify` and `:include_parent_namespaces`
143
- # options. `:include_parent_namespaces` defaults to true, hence must be set to false if
144
- # you want only to return params declared against the current/target endpoint.
145
- def declared(*)
146
- raise MethodNotYetAvailable, '#declared is not available prior to parameter validation.'
147
- end
9
+ # Backward compatibility: alias exception class to previous location
10
+ MethodNotYetAvailable = Declared::MethodNotYetAvailable
148
11
 
149
12
  # The API version as specified in the URL.
150
13
  def version
@@ -152,33 +15,36 @@ module Grape
152
15
  end
153
16
 
154
17
  def configuration
155
- options[:for].configuration.evaluate
18
+ config.for.configuration.evaluate
156
19
  end
157
20
 
158
21
  # End the request and display an error to the
159
22
  # end user with the specified message.
160
23
  #
161
24
  # @param message [String] The message to display.
162
- # @param status [Integer] the HTTP Status Code. Defaults to default_error_status, 500 if not set.
25
+ # @param status [Integer] The HTTP Status Code. Defaults to default_error_status, 500 if not set.
163
26
  # @param additional_headers [Hash] Addtional headers for the response.
164
- def error!(message, status = nil, additional_headers = nil)
165
- self.status(status || namespace_inheritable(:default_error_status))
27
+ # @param backtrace [Array<String>] The backtrace of the exception that caused the error.
28
+ # @param original_exception [Exception] The original exception that caused the error.
29
+ def error!(message, status = nil, additional_headers = nil, backtrace = nil, original_exception = nil)
30
+ status = self.status(status || inheritable_setting.namespace_inheritable[:default_error_status])
166
31
  headers = additional_headers.present? ? header.merge(additional_headers) : header
167
- throw :error, message: message, status: self.status, headers: headers
32
+ throw :error, Grape::Exceptions::ErrorResponse.new(
33
+ message:, status:, headers:, backtrace:, original_exception:
34
+ )
168
35
  end
169
36
 
170
37
  # Redirect to a new url.
171
38
  #
172
39
  # @param url [String] The url to be redirect.
173
- # @param options [Hash] The options used when redirect.
174
- # :permanent, default false.
175
- # :body, default a short message including the URL.
176
- def redirect(url, permanent: false, body: nil, **_options)
40
+ # @param permanent [Boolean] default false.
41
+ # @param body default a short message including the URL.
42
+ def redirect(url, permanent: false, body: nil)
177
43
  body_message = body
178
44
  if permanent
179
45
  status 301
180
46
  body_message ||= "This resource has been moved permanently to #{url}."
181
- elsif env[Grape::Http::Headers::HTTP_VERSION] == 'HTTP/1.1' && request.request_method.to_s.upcase != Grape::Http::Headers::GET
47
+ elsif http_version == 'HTTP/1.1' && !request.get?
182
48
  status 303
183
49
  body_message ||= "An alternate resource is located at #{url}."
184
50
  else
@@ -194,28 +60,11 @@ module Grape
194
60
  #
195
61
  # @param status [Integer] The HTTP Status Code to return for this request.
196
62
  def status(status = nil)
197
- case status
198
- when Symbol
199
- raise ArgumentError, "Status code :#{status} is invalid." unless Rack::Utils::SYMBOL_TO_STATUS_CODE.key?(status)
63
+ return @status || default_status if status.nil?
200
64
 
65
+ case status
66
+ when Symbol, Integer
201
67
  @status = Rack::Utils.status_code(status)
202
- when Integer
203
- @status = status
204
- when nil
205
- return @status if instance_variable_defined?(:@status) && @status
206
-
207
- case request.request_method.to_s.upcase
208
- when Grape::Http::Headers::POST
209
- 201
210
- when Grape::Http::Headers::DELETE
211
- if instance_variable_defined?(:@body) && @body.present?
212
- 200
213
- else
214
- 204
215
- end
216
- else
217
- 200
218
- end
219
68
  else
220
69
  raise ArgumentError, 'Status code must be Integer or Symbol.'
221
70
  end
@@ -223,23 +72,9 @@ module Grape
223
72
 
224
73
  # Set response content-type
225
74
  def content_type(val = nil)
226
- if val
227
- header(Grape::Http::Headers::CONTENT_TYPE, val)
228
- else
229
- header[Grape::Http::Headers::CONTENT_TYPE]
230
- end
231
- end
75
+ return header(Rack::CONTENT_TYPE, val) if val
232
76
 
233
- # Set or get a cookie
234
- #
235
- # @example
236
- # cookies[:mycookie] = 'mycookie val'
237
- # cookies['mycookie-string'] = 'mycookie string val'
238
- # cookies[:more] = { value: '123', expires: Time.at(0) }
239
- # cookies.delete :more
240
- #
241
- def cookies
242
- @cookies ||= Cookies.new
77
+ header[Rack::CONTENT_TYPE]
243
78
  end
244
79
 
245
80
  # Allows you to define the response body as something other than the
@@ -259,7 +94,7 @@ module Grape
259
94
  @body = ''
260
95
  status 204
261
96
  else
262
- instance_variable_defined?(:@body) ? @body : nil
97
+ @body
263
98
  end
264
99
  end
265
100
 
@@ -273,24 +108,9 @@ module Grape
273
108
  #
274
109
  # DELETE /12 # => 204 No Content, ""
275
110
  def return_no_content
276
- status 204
277
111
  body false
278
112
  end
279
113
 
280
- # Deprecated method to send files to the client. Use `sendfile` or `stream`
281
- def file(value = nil)
282
- if value.is_a?(String)
283
- ActiveSupport::Deprecation.warn('Use sendfile or stream to send files.')
284
- sendfile(value)
285
- elsif !value.is_a?(NilClass)
286
- ActiveSupport::Deprecation.warn('Use stream to use a Stream object.')
287
- stream(value)
288
- else
289
- ActiveSupport::Deprecation.warn('Use sendfile or stream to send files.')
290
- sendfile
291
- end
292
- end
293
-
294
114
  # Allows you to send a file to the client via sendfile.
295
115
  #
296
116
  # @example
@@ -300,14 +120,12 @@ module Grape
300
120
  #
301
121
  # GET /file # => "contents of file"
302
122
  def sendfile(value = nil)
303
- if value.is_a?(String)
304
- file_body = Grape::ServeStream::FileBody.new(value)
305
- @stream = Grape::ServeStream::StreamResponse.new(file_body)
306
- elsif !value.is_a?(NilClass)
307
- raise ArgumentError, 'Argument must be a file path'
308
- else
309
- stream
310
- end
123
+ return stream if value.nil?
124
+
125
+ raise ArgumentError, 'Argument must be a file path' unless value.is_a?(String)
126
+
127
+ file_body = Grape::ServeStream::FileBody.new(value)
128
+ @stream = Grape::ServeStream::StreamResponse.new(file_body)
311
129
  end
312
130
 
313
131
  # Allows you to define the response as a streamable object.
@@ -328,64 +146,13 @@ module Grape
328
146
  def stream(value = nil)
329
147
  return if value.nil? && @stream.nil?
330
148
 
331
- header 'Content-Length', nil
149
+ header Rack::CONTENT_LENGTH, nil
332
150
  header 'Transfer-Encoding', nil
333
- header 'Cache-Control', 'no-cache' # Skips ETag generation (reading the response up front)
334
- if value.is_a?(String)
335
- file_body = Grape::ServeStream::FileBody.new(value)
336
- @stream = Grape::ServeStream::StreamResponse.new(file_body)
337
- elsif value.respond_to?(:each)
338
- @stream = Grape::ServeStream::StreamResponse.new(value)
339
- elsif !value.is_a?(NilClass)
340
- raise ArgumentError, 'Stream object must respond to :each.'
341
- else
342
- @stream
343
- end
344
- end
345
-
346
- # Allows you to make use of Grape Entities by setting
347
- # the response body to the serializable hash of the
348
- # entity provided in the `:with` option. This has the
349
- # added benefit of automatically passing along environment
350
- # and version information to the serialization, making it
351
- # very easy to do conditional exposures. See Entity docs
352
- # for more info.
353
- #
354
- # @example
355
- #
356
- # get '/users/:id' do
357
- # present User.find(params[:id]),
358
- # with: API::Entities::User,
359
- # admin: current_user.admin?
360
- # end
361
- def present(*args)
362
- options = args.count > 1 ? args.extract_options! : {}
363
- key, object = if args.count == 2 && args.first.is_a?(Symbol)
364
- args
365
- else
366
- [nil, args.first]
367
- end
368
- entity_class = entity_class_for_obj(object, options)
369
-
370
- root = options.delete(:root)
371
-
372
- representation = if entity_class
373
- entity_representation_for(entity_class, object, options)
374
- else
375
- object
376
- end
377
-
378
- representation = { root => representation } if root
151
+ header Rack::CACHE_CONTROL, 'no-cache' # Skips ETag generation (reading the response up front)
379
152
 
380
- if key
381
- representation = (body || {}).merge(key => representation)
382
- elsif entity_class.present? && body
383
- raise ArgumentError, "Representation of type #{representation.class} cannot be merged." unless representation.respond_to?(:merge)
153
+ return @stream if value.nil?
384
154
 
385
- representation = body.merge(representation)
386
- end
387
-
388
- body representation
155
+ @stream = Grape::ServeStream::StreamResponse.new(stream_body(value))
389
156
  end
390
157
 
391
158
  # Returns route information for the current request.
@@ -400,41 +167,35 @@ module Grape
400
167
  env[Grape::Env::GRAPE_ROUTING_ARGS][:route_info]
401
168
  end
402
169
 
403
- # Attempt to locate the Entity class for a given object, if not given
404
- # explicitly. This is done by looking for the presence of Klass::Entity,
405
- # where Klass is the class of the `object` parameter, or one of its
406
- # ancestors.
407
- # @param object [Object] the object to locate the Entity class for
408
- # @param options [Hash]
409
- # @option options :with [Class] the explicit entity class to use
410
- # @return [Class] the located Entity class, or nil if none is found
411
- def entity_class_for_obj(object, options)
412
- entity_class = options.delete(:with)
170
+ def http_version
171
+ env.fetch('HTTP_VERSION') { env[Rack::SERVER_PROTOCOL] }
172
+ end
413
173
 
414
- if entity_class.nil?
415
- # entity class not explicitly defined, auto-detect from relation#klass or first object in the collection
416
- object_class = if object.respond_to?(:klass)
417
- object.klass
418
- else
419
- object.respond_to?(:first) ? object.first.class : object.class
420
- end
174
+ def api_format(format)
175
+ env[Grape::Env::API_FORMAT] = format
176
+ end
421
177
 
422
- object_class.ancestors.each do |potential|
423
- entity_class ||= (namespace_stackable_with_hash(:representations) || {})[potential]
424
- end
178
+ def context
179
+ self
180
+ end
425
181
 
426
- entity_class ||= object_class.const_get(:Entity) if object_class.const_defined?(:Entity) && object_class.const_get(:Entity).respond_to?(:represent)
427
- end
182
+ private
183
+
184
+ # Wraps a stream +value+ into a body that responds to +:each+.
185
+ def stream_body(value)
186
+ return Grape::ServeStream::FileBody.new(value) if value.is_a?(String)
428
187
 
429
- entity_class
188
+ raise ArgumentError, 'Stream object must respond to :each.' unless value.respond_to?(:each)
189
+
190
+ value
430
191
  end
431
192
 
432
- # @return the representation of the given object as done through
433
- # the given entity_class.
434
- def entity_representation_for(entity_class, object, options)
435
- embeds = { env: env }
436
- embeds[:version] = env[Grape::Env::API_VERSION] if env.key?(Grape::Env::API_VERSION)
437
- entity_class.represent(object, **embeds.merge(options))
193
+ # The default HTTP status when none has been set explicitly.
194
+ def default_status
195
+ return 201 if request.post?
196
+ return 204 if request.delete? && @body.blank?
197
+
198
+ 200
438
199
  end
439
200
  end
440
201
  end
@@ -3,19 +3,14 @@
3
3
  module Grape
4
4
  module DSL
5
5
  module Logger
6
- include Grape::DSL::Settings
7
-
8
- attr_writer :logger
9
-
10
6
  # Set or retrive the configured logger. If none was configured, this
11
7
  # method will create a new one, logging to stdout.
12
8
  # @param logger [Object] the new logger to use
13
9
  def logger(logger = nil)
14
- if logger
15
- global_setting(:logger, logger)
16
- else
17
- global_setting(:logger) || global_setting(:logger, ::Logger.new($stdout))
18
- end
10
+ global_settings = inheritable_setting.global
11
+ return global_settings[:logger] = logger if logger
12
+
13
+ global_settings[:logger] || global_settings[:logger] = ::Logger.new($stdout)
19
14
  end
20
15
  end
21
16
  end