grape 1.1.0 → 1.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (286) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +278 -44
  3. data/LICENSE +1 -1
  4. data/README.md +514 -69
  5. data/UPGRADING.md +424 -17
  6. data/grape.gemspec +13 -2
  7. data/lib/grape.rb +104 -71
  8. data/lib/grape/api.rb +138 -175
  9. data/lib/grape/api/helpers.rb +2 -0
  10. data/lib/grape/api/instance.rb +283 -0
  11. data/lib/grape/config.rb +34 -0
  12. data/lib/grape/content_types.rb +34 -0
  13. data/lib/grape/cookies.rb +2 -0
  14. data/lib/grape/dsl/api.rb +2 -0
  15. data/lib/grape/dsl/callbacks.rb +22 -0
  16. data/lib/grape/dsl/configuration.rb +2 -0
  17. data/lib/grape/dsl/desc.rb +41 -7
  18. data/lib/grape/dsl/headers.rb +2 -0
  19. data/lib/grape/dsl/helpers.rb +5 -2
  20. data/lib/grape/dsl/inside_route.rb +92 -49
  21. data/lib/grape/dsl/logger.rb +2 -0
  22. data/lib/grape/dsl/middleware.rb +9 -0
  23. data/lib/grape/dsl/parameters.rb +25 -14
  24. data/lib/grape/dsl/request_response.rb +4 -2
  25. data/lib/grape/dsl/routing.rb +17 -10
  26. data/lib/grape/dsl/settings.rb +7 -1
  27. data/lib/grape/dsl/validations.rb +24 -4
  28. data/lib/grape/eager_load.rb +20 -0
  29. data/lib/grape/endpoint.rb +59 -35
  30. data/lib/grape/error_formatter.rb +4 -2
  31. data/lib/grape/error_formatter/base.rb +2 -0
  32. data/lib/grape/error_formatter/json.rb +2 -0
  33. data/lib/grape/error_formatter/txt.rb +2 -0
  34. data/lib/grape/error_formatter/xml.rb +2 -0
  35. data/lib/grape/exceptions/base.rb +20 -14
  36. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  37. data/lib/grape/exceptions/incompatible_option_values.rb +2 -0
  38. data/lib/grape/exceptions/invalid_accept_header.rb +2 -0
  39. data/lib/grape/exceptions/invalid_formatter.rb +2 -0
  40. data/lib/grape/exceptions/invalid_message_body.rb +2 -0
  41. data/lib/grape/exceptions/invalid_response.rb +11 -0
  42. data/lib/grape/exceptions/invalid_version_header.rb +2 -0
  43. data/lib/grape/exceptions/invalid_versioner_option.rb +2 -0
  44. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +2 -0
  45. data/lib/grape/exceptions/method_not_allowed.rb +2 -0
  46. data/lib/grape/exceptions/missing_group_type.rb +2 -0
  47. data/lib/grape/exceptions/missing_mime_type.rb +2 -0
  48. data/lib/grape/exceptions/missing_option.rb +2 -0
  49. data/lib/grape/exceptions/missing_vendor_option.rb +2 -0
  50. data/lib/grape/exceptions/unknown_options.rb +2 -0
  51. data/lib/grape/exceptions/unknown_parameter.rb +2 -0
  52. data/lib/grape/exceptions/unknown_validator.rb +2 -0
  53. data/lib/grape/exceptions/unsupported_group_type.rb +2 -0
  54. data/lib/grape/exceptions/validation.rb +4 -2
  55. data/lib/grape/exceptions/validation_array_errors.rb +2 -0
  56. data/lib/grape/exceptions/validation_errors.rb +16 -13
  57. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +4 -3
  58. data/lib/grape/extensions/deep_mergeable_hash.rb +2 -0
  59. data/lib/grape/extensions/deep_symbolize_hash.rb +2 -0
  60. data/lib/grape/extensions/hash.rb +2 -0
  61. data/lib/grape/extensions/hashie/mash.rb +2 -0
  62. data/lib/grape/formatter.rb +5 -3
  63. data/lib/grape/formatter/json.rb +2 -0
  64. data/lib/grape/formatter/serializable_hash.rb +2 -0
  65. data/lib/grape/formatter/txt.rb +2 -0
  66. data/lib/grape/formatter/xml.rb +2 -0
  67. data/lib/grape/http/headers.rb +50 -18
  68. data/lib/grape/locale/en.yml +3 -1
  69. data/lib/grape/middleware/auth/base.rb +7 -7
  70. data/lib/grape/middleware/auth/dsl.rb +2 -0
  71. data/lib/grape/middleware/auth/strategies.rb +2 -0
  72. data/lib/grape/middleware/auth/strategy_info.rb +2 -0
  73. data/lib/grape/middleware/base.rb +10 -7
  74. data/lib/grape/middleware/error.rb +21 -16
  75. data/lib/grape/middleware/filter.rb +2 -0
  76. data/lib/grape/middleware/formatter.rb +8 -6
  77. data/lib/grape/middleware/globals.rb +2 -0
  78. data/lib/grape/middleware/helpers.rb +12 -0
  79. data/lib/grape/middleware/stack.rb +13 -3
  80. data/lib/grape/middleware/versioner.rb +2 -0
  81. data/lib/grape/middleware/versioner/accept_version_header.rb +2 -0
  82. data/lib/grape/middleware/versioner/header.rb +10 -8
  83. data/lib/grape/middleware/versioner/param.rb +3 -1
  84. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +4 -1
  85. data/lib/grape/middleware/versioner/path.rb +3 -1
  86. data/lib/grape/namespace.rb +14 -2
  87. data/lib/grape/parser.rb +4 -2
  88. data/lib/grape/parser/json.rb +3 -1
  89. data/lib/grape/parser/xml.rb +3 -1
  90. data/lib/grape/path.rb +15 -3
  91. data/lib/grape/presenters/presenter.rb +2 -0
  92. data/lib/grape/request.rb +19 -10
  93. data/lib/grape/router.rb +30 -29
  94. data/lib/grape/router/attribute_translator.rb +41 -8
  95. data/lib/grape/router/pattern.rb +20 -16
  96. data/lib/grape/router/route.rb +14 -28
  97. data/lib/grape/{serve_file → serve_stream}/file_body.rb +3 -1
  98. data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +3 -1
  99. data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +10 -8
  100. data/lib/grape/util/base_inheritable.rb +43 -0
  101. data/lib/grape/util/cache.rb +20 -0
  102. data/lib/grape/util/endpoint_configuration.rb +8 -0
  103. data/lib/grape/util/env.rb +19 -17
  104. data/lib/grape/util/inheritable_setting.rb +2 -0
  105. data/lib/grape/util/inheritable_values.rb +7 -25
  106. data/lib/grape/util/json.rb +2 -0
  107. data/lib/grape/util/lazy_block.rb +27 -0
  108. data/lib/grape/util/lazy_object.rb +43 -0
  109. data/lib/grape/util/lazy_value.rb +98 -0
  110. data/lib/grape/util/registrable.rb +2 -0
  111. data/lib/grape/util/reverse_stackable_values.rb +10 -35
  112. data/lib/grape/util/stackable_values.rb +21 -34
  113. data/lib/grape/util/strict_hash_configuration.rb +2 -0
  114. data/lib/grape/util/xml.rb +2 -0
  115. data/lib/grape/validations.rb +2 -0
  116. data/lib/grape/validations/attributes_iterator.rb +16 -6
  117. data/lib/grape/validations/multiple_attributes_iterator.rb +13 -0
  118. data/lib/grape/validations/params_scope.rb +51 -30
  119. data/lib/grape/validations/single_attribute_iterator.rb +24 -0
  120. data/lib/grape/validations/types.rb +13 -38
  121. data/lib/grape/validations/types/array_coercer.rb +65 -0
  122. data/lib/grape/validations/types/build_coercer.rb +47 -49
  123. data/lib/grape/validations/types/custom_type_coercer.rb +29 -51
  124. data/lib/grape/validations/types/custom_type_collection_coercer.rb +10 -25
  125. data/lib/grape/validations/types/dry_type_coercer.rb +76 -0
  126. data/lib/grape/validations/types/file.rb +22 -18
  127. data/lib/grape/validations/types/invalid_value.rb +24 -0
  128. data/lib/grape/validations/types/json.rb +46 -39
  129. data/lib/grape/validations/types/multiple_type_coercer.rb +14 -33
  130. data/lib/grape/validations/types/primitive_coercer.rb +67 -0
  131. data/lib/grape/validations/types/set_coercer.rb +40 -0
  132. data/lib/grape/validations/types/variant_collection_coercer.rb +5 -13
  133. data/lib/grape/validations/validator_factory.rb +8 -11
  134. data/lib/grape/validations/validators/all_or_none.rb +8 -13
  135. data/lib/grape/validations/validators/allow_blank.rb +3 -1
  136. data/lib/grape/validations/validators/as.rb +5 -4
  137. data/lib/grape/validations/validators/at_least_one_of.rb +7 -13
  138. data/lib/grape/validations/validators/base.rb +20 -16
  139. data/lib/grape/validations/validators/coerce.rb +46 -29
  140. data/lib/grape/validations/validators/default.rb +6 -6
  141. data/lib/grape/validations/validators/exactly_one_of.rb +10 -23
  142. data/lib/grape/validations/validators/except_values.rb +4 -2
  143. data/lib/grape/validations/validators/multiple_params_base.rb +17 -10
  144. data/lib/grape/validations/validators/mutual_exclusion.rb +8 -18
  145. data/lib/grape/validations/validators/presence.rb +3 -1
  146. data/lib/grape/validations/validators/regexp.rb +4 -2
  147. data/lib/grape/validations/validators/same_as.rb +26 -0
  148. data/lib/grape/validations/validators/values.rb +18 -6
  149. data/lib/grape/version.rb +3 -1
  150. data/spec/grape/api/custom_validations_spec.rb +5 -3
  151. data/spec/grape/api/deeply_included_options_spec.rb +2 -0
  152. data/spec/grape/api/defines_boolean_in_params_spec.rb +39 -0
  153. data/spec/grape/api/inherited_helpers_spec.rb +2 -0
  154. data/spec/grape/api/instance_spec.rb +104 -0
  155. data/spec/grape/api/invalid_format_spec.rb +2 -0
  156. data/spec/grape/api/namespace_parameters_in_route_spec.rb +2 -0
  157. data/spec/grape/api/nested_helpers_spec.rb +2 -0
  158. data/spec/grape/api/optional_parameters_in_route_spec.rb +2 -0
  159. data/spec/grape/api/parameters_modification_spec.rb +3 -1
  160. data/spec/grape/api/patch_method_helpers_spec.rb +2 -0
  161. data/spec/grape/api/recognize_path_spec.rb +2 -0
  162. data/spec/grape/api/required_parameters_in_route_spec.rb +2 -0
  163. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +2 -0
  164. data/spec/grape/api/routes_with_requirements_spec.rb +61 -0
  165. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +2 -0
  166. data/spec/grape/api/shared_helpers_spec.rb +2 -0
  167. data/spec/grape/api_remount_spec.rb +473 -0
  168. data/spec/grape/api_spec.rb +565 -12
  169. data/spec/grape/config_spec.rb +19 -0
  170. data/spec/grape/dsl/callbacks_spec.rb +2 -0
  171. data/spec/grape/dsl/configuration_spec.rb +2 -0
  172. data/spec/grape/dsl/desc_spec.rb +42 -16
  173. data/spec/grape/dsl/headers_spec.rb +2 -0
  174. data/spec/grape/dsl/helpers_spec.rb +4 -2
  175. data/spec/grape/dsl/inside_route_spec.rb +184 -33
  176. data/spec/grape/dsl/logger_spec.rb +2 -0
  177. data/spec/grape/dsl/middleware_spec.rb +10 -0
  178. data/spec/grape/dsl/parameters_spec.rb +2 -0
  179. data/spec/grape/dsl/request_response_spec.rb +2 -0
  180. data/spec/grape/dsl/routing_spec.rb +12 -0
  181. data/spec/grape/dsl/settings_spec.rb +2 -0
  182. data/spec/grape/dsl/validations_spec.rb +2 -0
  183. data/spec/grape/endpoint/declared_spec.rb +601 -0
  184. data/spec/grape/endpoint_spec.rb +53 -523
  185. data/spec/grape/entity_spec.rb +9 -1
  186. data/spec/grape/exceptions/base_spec.rb +67 -0
  187. data/spec/grape/exceptions/body_parse_errors_spec.rb +2 -0
  188. data/spec/grape/exceptions/invalid_accept_header_spec.rb +2 -0
  189. data/spec/grape/exceptions/invalid_formatter_spec.rb +2 -0
  190. data/spec/grape/exceptions/invalid_response_spec.rb +13 -0
  191. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +2 -0
  192. data/spec/grape/exceptions/missing_mime_type_spec.rb +2 -0
  193. data/spec/grape/exceptions/missing_option_spec.rb +2 -0
  194. data/spec/grape/exceptions/unknown_options_spec.rb +2 -0
  195. data/spec/grape/exceptions/unknown_validator_spec.rb +2 -0
  196. data/spec/grape/exceptions/validation_errors_spec.rb +8 -4
  197. data/spec/grape/exceptions/validation_spec.rb +3 -1
  198. data/spec/grape/extensions/param_builders/hash_spec.rb +2 -0
  199. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +2 -0
  200. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +2 -0
  201. data/spec/grape/integration/global_namespace_function_spec.rb +2 -0
  202. data/spec/grape/integration/rack_sendfile_spec.rb +14 -8
  203. data/spec/grape/integration/rack_spec.rb +25 -7
  204. data/spec/grape/loading_spec.rb +2 -0
  205. data/spec/grape/middleware/auth/base_spec.rb +2 -0
  206. data/spec/grape/middleware/auth/dsl_spec.rb +5 -3
  207. data/spec/grape/middleware/auth/strategies_spec.rb +3 -1
  208. data/spec/grape/middleware/base_spec.rb +10 -0
  209. data/spec/grape/middleware/error_spec.rb +3 -1
  210. data/spec/grape/middleware/exception_spec.rb +4 -2
  211. data/spec/grape/middleware/formatter_spec.rb +33 -16
  212. data/spec/grape/middleware/globals_spec.rb +2 -0
  213. data/spec/grape/middleware/stack_spec.rb +12 -0
  214. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -1
  215. data/spec/grape/middleware/versioner/header_spec.rb +9 -1
  216. data/spec/grape/middleware/versioner/param_spec.rb +3 -1
  217. data/spec/grape/middleware/versioner/path_spec.rb +3 -1
  218. data/spec/grape/middleware/versioner_spec.rb +2 -0
  219. data/spec/grape/named_api_spec.rb +21 -0
  220. data/spec/grape/parser_spec.rb +7 -5
  221. data/spec/grape/path_spec.rb +6 -4
  222. data/spec/grape/presenters/presenter_spec.rb +2 -0
  223. data/spec/grape/request_spec.rb +26 -0
  224. data/spec/grape/util/inheritable_setting_spec.rb +2 -0
  225. data/spec/grape/util/inheritable_values_spec.rb +2 -0
  226. data/spec/grape/util/reverse_stackable_values_spec.rb +2 -0
  227. data/spec/grape/util/stackable_values_spec.rb +3 -1
  228. data/spec/grape/util/strict_hash_configuration_spec.rb +2 -0
  229. data/spec/grape/validations/attributes_iterator_spec.rb +2 -0
  230. data/spec/grape/validations/instance_behaivour_spec.rb +5 -3
  231. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +41 -0
  232. data/spec/grape/validations/params_scope_spec.rb +213 -9
  233. data/spec/grape/validations/single_attribute_iterator_spec.rb +58 -0
  234. data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
  235. data/spec/grape/validations/types/primitive_coercer_spec.rb +135 -0
  236. data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
  237. data/spec/grape/validations/types_spec.rb +9 -36
  238. data/spec/grape/validations/validators/all_or_none_spec.rb +140 -30
  239. data/spec/grape/validations/validators/allow_blank_spec.rb +2 -0
  240. data/spec/grape/validations/validators/at_least_one_of_spec.rb +175 -29
  241. data/spec/grape/validations/validators/coerce_spec.rb +476 -135
  242. data/spec/grape/validations/validators/default_spec.rb +172 -0
  243. data/spec/grape/validations/validators/exactly_one_of_spec.rb +204 -38
  244. data/spec/grape/validations/validators/except_values_spec.rb +4 -1
  245. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +186 -27
  246. data/spec/grape/validations/validators/presence_spec.rb +30 -0
  247. data/spec/grape/validations/validators/regexp_spec.rb +2 -0
  248. data/spec/grape/validations/validators/same_as_spec.rb +65 -0
  249. data/spec/grape/validations/validators/values_spec.rb +30 -5
  250. data/spec/grape/validations_spec.rb +388 -50
  251. data/spec/integration/eager_load/eager_load_spec.rb +15 -0
  252. data/spec/integration/multi_json/json_spec.rb +2 -0
  253. data/spec/integration/multi_xml/xml_spec.rb +2 -0
  254. data/spec/shared/versioning_examples.rb +22 -20
  255. data/spec/spec_helper.rb +12 -1
  256. data/spec/support/basic_auth_encode_helpers.rb +2 -0
  257. data/spec/support/chunks.rb +14 -0
  258. data/spec/support/content_type_helpers.rb +2 -0
  259. data/spec/support/eager_load.rb +19 -0
  260. data/spec/support/endpoint_faker.rb +2 -0
  261. data/spec/support/file_streamer.rb +2 -0
  262. data/spec/support/integer_helpers.rb +2 -0
  263. data/spec/support/versioned_helpers.rb +8 -8
  264. metadata +86 -48
  265. data/Appraisals +0 -32
  266. data/Dangerfile +0 -2
  267. data/Gemfile +0 -33
  268. data/Gemfile.lock +0 -231
  269. data/Guardfile +0 -10
  270. data/RELEASING.md +0 -111
  271. data/Rakefile +0 -25
  272. data/benchmark/simple.rb +0 -27
  273. data/benchmark/simple_with_type_coercer.rb +0 -22
  274. data/gemfiles/multi_json.gemfile +0 -35
  275. data/gemfiles/multi_xml.gemfile +0 -35
  276. data/gemfiles/rack_1.5.2.gemfile +0 -35
  277. data/gemfiles/rack_edge.gemfile +0 -35
  278. data/gemfiles/rails_3.gemfile +0 -36
  279. data/gemfiles/rails_4.gemfile +0 -35
  280. data/gemfiles/rails_5.gemfile +0 -35
  281. data/gemfiles/rails_edge.gemfile +0 -35
  282. data/lib/grape/extensions/deep_hash_with_indifferent_access.rb +0 -18
  283. data/lib/grape/util/content_types.rb +0 -26
  284. data/lib/grape/validations/types/virtus_collection_patch.rb +0 -16
  285. data/pkg/grape-0.17.0.gem +0 -0
  286. data/pkg/grape-0.19.0.gem +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/concern'
2
4
 
3
5
  module Grape
@@ -49,7 +51,7 @@ module Grape
49
51
  end
50
52
  end
51
53
 
52
- @versions.last unless @versions.nil?
54
+ @versions.last if instance_variable_defined?(:@versions) && @versions
53
55
  end
54
56
 
55
57
  # Define a root URL prefix for your entire API.
@@ -77,9 +79,14 @@ module Grape
77
79
  namespace_inheritable(:do_not_route_options, true)
78
80
  end
79
81
 
80
- def mount(mounts)
82
+ def mount(mounts, *opts)
81
83
  mounts = { mounts => '/' } unless mounts.respond_to?(:each_pair)
82
84
  mounts.each_pair do |app, path|
85
+ if app.respond_to?(:mount_instance)
86
+ opts_with = opts.any? ? opts.shift[:with] : {}
87
+ mount({ app.mount_instance(configuration: opts_with) => path })
88
+ next
89
+ end
83
90
  in_setting = inheritable_setting
84
91
 
85
92
  if app.respond_to?(:inheritable_setting, true)
@@ -136,16 +143,16 @@ module Grape
136
143
  reset_validations!
137
144
  end
138
145
 
139
- %w[get post put head delete options patch].each do |meth|
140
- define_method meth do |*args, &block|
146
+ Grape::Http::Headers::SUPPORTED_METHODS.each do |supported_method|
147
+ define_method supported_method.downcase do |*args, &block|
141
148
  options = args.extract_options!
142
149
  paths = args.first || ['/']
143
- route(meth.upcase, paths, options, &block)
150
+ route(supported_method, paths, options, &block)
144
151
  end
145
152
  end
146
153
 
147
154
  # Declare a "namespace", which prefixes all subordinate routes with its
148
- # name. Any endpoints within a namespace, or group, resource, segment,
155
+ # name. Any endpoints within a namespace, group, resource or segment,
149
156
  # etc., will share their parent context as well as any configuration
150
157
  # done in the namespace context.
151
158
  #
@@ -157,14 +164,14 @@ module Grape
157
164
  # end
158
165
  # end
159
166
  def namespace(space = nil, options = {}, &block)
167
+ @namespace_description = nil unless instance_variable_defined?(:@namespace_description) && @namespace_description
168
+
160
169
  if space || block_given?
161
170
  within_namespace do
162
171
  previous_namespace_description = @namespace_description
163
172
  @namespace_description = (@namespace_description || {}).deep_merge(namespace_setting(:description) || {})
164
173
  nest(block) do
165
- if space
166
- namespace_stackable(:namespace, Namespace.new(space, options))
167
- end
174
+ namespace_stackable(:namespace, Namespace.new(space, **options)) if space
168
175
  end
169
176
  @namespace_description = previous_namespace_description
170
177
  end
@@ -193,7 +200,7 @@ module Grape
193
200
  @endpoints = []
194
201
  end
195
202
 
196
- # Thie method allows you to quickly define a parameter route segment
203
+ # This method allows you to quickly define a parameter route segment
197
204
  # in your API.
198
205
  #
199
206
  # @param param [Symbol] The name of the parameter you wish to declare.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/concern'
2
4
 
3
5
  module Grape
@@ -169,7 +171,11 @@ module Grape
169
171
  # the superclass's :inheritable_setting.
170
172
  def build_top_level_setting
171
173
  Grape::Util::InheritableSetting.new.tap do |setting|
172
- if defined?(superclass) && superclass.respond_to?(:inheritable_setting) && superclass != Grape::API
174
+ # Doesn't try to inherit settings from +Grape::API::Instance+ which also responds to
175
+ # +inheritable_setting+, however, it doesn't contain any user-defined settings.
176
+ # Otherwise, it would lead to an extra instance of +Grape::Util::InheritableSetting+
177
+ # in the chain for every endpoint.
178
+ if defined?(superclass) && superclass.respond_to?(:inheritable_setting) && superclass != Grape::API::Instance
173
179
  setting.inherit_from superclass.inheritable_setting
174
180
  end
175
181
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/concern'
2
4
 
3
5
  module Grape
@@ -8,7 +10,24 @@ module Grape
8
10
  include Grape::DSL::Configuration
9
11
 
10
12
  module ClassMethods
11
- # Clears all defined parameters and validations.
13
+ # Clears all defined parameters and validations. The main purpose of it is to clean up
14
+ # settings, so next endpoint won't interfere with previous one.
15
+ #
16
+ # params do
17
+ # # params for the endpoint below this block
18
+ # end
19
+ # post '/current' do
20
+ # # whatever
21
+ # end
22
+ #
23
+ # # somewhere between them the reset_validations! method gets called
24
+ #
25
+ # params do
26
+ # # params for the endpoint below this block
27
+ # end
28
+ # post '/next' do
29
+ # # whatever
30
+ # end
12
31
  def reset_validations!
13
32
  unset_namespace_stackable :declared_params
14
33
  unset_namespace_stackable :validations
@@ -27,10 +46,11 @@ module Grape
27
46
  setting = description_field(:params)
28
47
  setting ||= description_field(:params, {})
29
48
  Array(names).each do |name|
30
- setting[name[:full_name].to_s] ||= {}
31
- setting[name[:full_name].to_s].merge!(opts)
49
+ full_name = name[:full_name].to_s
50
+ setting[full_name] ||= {}
51
+ setting[full_name].merge!(opts)
32
52
 
33
- namespace_stackable(:params, name[:full_name].to_s => opts)
53
+ namespace_stackable(:params, full_name => opts)
34
54
  end
35
55
  end
36
56
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ Grape.eager_load!
4
+ Grape::Http.eager_load!
5
+ Grape::Exceptions.eager_load!
6
+ Grape::Extensions.eager_load!
7
+ Grape::Extensions::ActiveSupport.eager_load!
8
+ Grape::Extensions::Hashie.eager_load!
9
+ Grape::Middleware.eager_load!
10
+ Grape::Middleware::Auth.eager_load!
11
+ Grape::Middleware::Versioner.eager_load!
12
+ Grape::Util.eager_load!
13
+ Grape::ErrorFormatter.eager_load!
14
+ Grape::Formatter.eager_load!
15
+ Grape::Parser.eager_load!
16
+ Grape::DSL.eager_load!
17
+ Grape::API.eager_load!
18
+ Grape::Presenters.eager_load!
19
+ Grape::ServeStream.eager_load!
20
+ Rack::Head # AutoLoads the Rack::Head
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  # An Endpoint is the proxy scope in which all routing
3
5
  # blocks are executed. In other words, any methods
@@ -78,7 +80,10 @@ module Grape
78
80
 
79
81
  self.inheritable_setting = new_settings.point_in_time_copy
80
82
 
81
- route_setting(:saved_declared_params, namespace_stackable(:declared_params))
83
+ # now +namespace_stackable(:declared_params)+ contains all params defined for
84
+ # this endpoint and its parents, but later it will be cleaned up,
85
+ # see +reset_validations!+ in lib/grape/dsl/validations.rb
86
+ route_setting(:declared_params, namespace_stackable(:declared_params).flatten)
82
87
  route_setting(:saved_validations, namespace_stackable(:validations))
83
88
 
84
89
  namespace_stackable(:representations, []) unless namespace_stackable(:representations)
@@ -97,7 +102,7 @@ module Grape
97
102
  @block = nil
98
103
 
99
104
  @status = nil
100
- @file = nil
105
+ @stream = nil
101
106
  @body = nil
102
107
  @proc = nil
103
108
 
@@ -114,7 +119,6 @@ module Grape
114
119
  parent_declared_params = namespace_stackable[:declared_params]
115
120
 
116
121
  if parent_declared_params
117
- inheritable_setting.route[:declared_params] ||= []
118
122
  inheritable_setting.route[:declared_params].concat(parent_declared_params.flatten)
119
123
  end
120
124
 
@@ -154,8 +158,8 @@ module Grape
154
158
  methods << Grape::Http::Headers::HEAD
155
159
  end
156
160
  methods.each do |method|
157
- unless route.request_method.to_s.upcase == method
158
- route = Grape::Router::Route.new(method, route.origin, route.attributes.to_h)
161
+ unless route.request_method == method
162
+ route = Grape::Router::Route.new(method, route.origin, **route.attributes.to_h)
159
163
  end
160
164
  router.append(route.apply(self))
161
165
  end
@@ -167,8 +171,8 @@ module Grape
167
171
  route_options = prepare_default_route_attributes
168
172
  map_routes do |method, path|
169
173
  path = prepare_path(path)
170
- params = merge_route_options(route_options.merge(suffix: path.suffix))
171
- route = Router::Route.new(method, path.path, params)
174
+ params = merge_route_options(**route_options.merge(suffix: path.suffix))
175
+ route = Router::Route.new(method, path.path, **params)
172
176
  route.apply(self)
173
177
  end.flatten
174
178
  end
@@ -188,7 +192,7 @@ module Grape
188
192
  requirements: prepare_routes_requirements,
189
193
  prefix: namespace_inheritable(:root_prefix),
190
194
  anchor: options[:route_options].fetch(:anchor, true),
191
- settings: inheritable_setting.route.except(:saved_declared_params, :saved_validations),
195
+ settings: inheritable_setting.route.except(:declared_params, :saved_validations),
192
196
  forward_match: options[:forward_match]
193
197
  }
194
198
  end
@@ -200,7 +204,7 @@ module Grape
200
204
  end
201
205
 
202
206
  def merge_route_options(**default)
203
- options[:route_options].clone.reverse_merge(**default)
207
+ options[:route_options].clone.merge!(**default)
204
208
  end
205
209
 
206
210
  def map_routes
@@ -245,32 +249,37 @@ module Grape
245
249
  @request = Grape::Request.new(env, build_params_with: namespace_inheritable(:build_params_with))
246
250
  @params = @request.params
247
251
  @headers = @request.headers
252
+ begin
253
+ cookies.read(@request)
254
+ self.class.run_before_each(self)
255
+ run_filters befores, :before
256
+
257
+ if (allowed_methods = env[Grape::Env::GRAPE_ALLOWED_METHODS])
258
+ raise Grape::Exceptions::MethodNotAllowed.new(header.merge('Allow' => allowed_methods)) unless options?
259
+ header 'Allow', allowed_methods
260
+ response_object = ''
261
+ status 204
262
+ else
263
+ run_filters before_validations, :before_validation
264
+ run_validators validations, request
265
+ remove_renamed_params
266
+ run_filters after_validations, :after_validation
267
+ response_object = execute
268
+ end
248
269
 
249
- cookies.read(@request)
250
- self.class.run_before_each(self)
251
- run_filters befores, :before
270
+ run_filters afters, :after
271
+ cookies.write(header)
252
272
 
253
- if (allowed_methods = env[Grape::Env::GRAPE_ALLOWED_METHODS])
254
- raise Grape::Exceptions::MethodNotAllowed, header.merge('Allow' => allowed_methods) unless options?
255
- header 'Allow', allowed_methods
256
- response_object = ''
257
- status 204
258
- else
259
- run_filters before_validations, :before_validation
260
- run_validators validations, request
261
- run_filters after_validations, :after_validation
262
- response_object = @block ? @block.call(self) : nil
263
- end
273
+ # status verifies body presence when DELETE
274
+ @body ||= response_object
264
275
 
265
- run_filters afters, :after
266
- cookies.write(header)
276
+ # The body commonly is an Array of Strings, the application instance itself, or a Stream-like object
277
+ response_object = stream || [body]
267
278
 
268
- # status verifies body presence when DELETE
269
- @body ||= response_object
270
-
271
- # The Body commonly is an Array of Strings, the application instance itself, or a File-like object
272
- response_object = file || [body]
273
- [status, header, response_object]
279
+ [status, header, response_object]
280
+ ensure
281
+ run_filters finallies, :finally
282
+ end
274
283
  end
275
284
  end
276
285
 
@@ -319,7 +328,18 @@ module Grape
319
328
  Module.new { helpers.each { |mod_to_include| include mod_to_include } }
320
329
  end
321
330
 
322
- private :build_stack, :build_helpers
331
+ def remove_renamed_params
332
+ return unless route_setting(:renamed_params)
333
+ route_setting(:renamed_params).flat_map(&:keys).each do |renamed_param|
334
+ @params.delete(renamed_param)
335
+ end
336
+ end
337
+
338
+ private :build_stack, :build_helpers, :remove_renamed_params
339
+
340
+ def execute
341
+ @block ? @block.call(self) : nil
342
+ end
323
343
 
324
344
  def helpers
325
345
  lazy_initialize! && @helpers
@@ -341,7 +361,7 @@ module Grape
341
361
  def run_validators(validator_factories, request)
342
362
  validation_errors = []
343
363
 
344
- validators = validator_factories.map(&:create_validator)
364
+ validators = validator_factories.map { |options| Grape::Validations::ValidatorFactory.create_validator(**options) }
345
365
 
346
366
  ActiveSupport::Notifications.instrument('endpoint_run_validators.grape', endpoint: self, validators: validators, request: request) do
347
367
  validators.each do |validator|
@@ -351,13 +371,13 @@ module Grape
351
371
  validation_errors << e
352
372
  break if validator.fail_fast?
353
373
  rescue Grape::Exceptions::ValidationArrayErrors => e
354
- validation_errors += e.errors
374
+ validation_errors.concat e.errors
355
375
  break if validator.fail_fast?
356
376
  end
357
377
  end
358
378
  end
359
379
 
360
- validation_errors.any? && raise(Grape::Exceptions::ValidationErrors, errors: validation_errors, headers: header)
380
+ validation_errors.any? && raise(Grape::Exceptions::ValidationErrors.new(errors: validation_errors, headers: header))
361
381
  end
362
382
 
363
383
  def run_filters(filters, type = :other)
@@ -384,6 +404,10 @@ module Grape
384
404
  namespace_stackable(:afters) || []
385
405
  end
386
406
 
407
+ def finallies
408
+ namespace_stackable(:finallies) || []
409
+ end
410
+
387
411
  def validations
388
412
  route_setting(:saved_validations) || []
389
413
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module ErrorFormatter
3
5
  extend Util::Registrable
@@ -13,8 +15,8 @@ module Grape
13
15
  }
14
16
  end
15
17
 
16
- def formatters(options)
17
- builtin_formatters.merge(default_elements).merge(options[:error_formatters] || {})
18
+ def formatters(**options)
19
+ builtin_formatters.merge(default_elements).merge!(options[:error_formatters] || {})
18
20
  end
19
21
 
20
22
  def formatter_for(api_format, **options)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module ErrorFormatter
3
5
  module Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module ErrorFormatter
3
5
  module Json
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module ErrorFormatter
3
5
  module Txt
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module ErrorFormatter
3
5
  module Xml
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Exceptions
3
5
  class Base < StandardError
4
- BASE_MESSAGES_KEY = 'grape.errors.messages'.freeze
5
- BASE_ATTRIBUTES_KEY = 'grape.errors.attributes'.freeze
6
+ BASE_MESSAGES_KEY = 'grape.errors.messages'
7
+ BASE_ATTRIBUTES_KEY = 'grape.errors.attributes'
6
8
  FALLBACK_LOCALE = :en
7
9
 
8
10
  attr_reader :status, :message, :headers
@@ -28,7 +30,7 @@ module Grape
28
30
  @problem = problem(key, **attributes)
29
31
  @summary = summary(key, **attributes)
30
32
  @resolution = resolution(key, **attributes)
31
- [['Problem', @problem], ['Summary', @summary], ['Resolution', @resolution]].reduce('') do |message, detail_array|
33
+ [['Problem', @problem], ['Summary', @summary], ['Resolution', @resolution]].each_with_object(+'') do |detail_array, message|
32
34
  message << "\n#{detail_array[0]}:\n #{detail_array[1]}" unless detail_array[1].blank?
33
35
  message
34
36
  end
@@ -37,16 +39,16 @@ module Grape
37
39
  end
38
40
  end
39
41
 
40
- def problem(key, attributes)
41
- translate_message("#{key}.problem".to_sym, attributes)
42
+ def problem(key, **attributes)
43
+ translate_message("#{key}.problem".to_sym, **attributes)
42
44
  end
43
45
 
44
- def summary(key, attributes)
45
- translate_message("#{key}.summary".to_sym, attributes)
46
+ def summary(key, **attributes)
47
+ translate_message("#{key}.summary".to_sym, **attributes)
46
48
  end
47
49
 
48
- def resolution(key, attributes)
49
- translate_message("#{key}.resolution".to_sym, attributes)
50
+ def resolution(key, **attributes)
51
+ translate_message("#{key}.resolution".to_sym, **attributes)
50
52
  end
51
53
 
52
54
  def translate_attributes(keys, **options)
@@ -55,10 +57,6 @@ module Grape
55
57
  end.join(', ')
56
58
  end
57
59
 
58
- def translate_attribute(key, **options)
59
- translate("#{BASE_ATTRIBUTES_KEY}.#{key}", default: key, **options)
60
- end
61
-
62
60
  def translate_message(key, **options)
63
61
  case key
64
62
  when Symbol
@@ -74,7 +72,15 @@ module Grape
74
72
  options = options.dup
75
73
  options[:default] &&= options[:default].to_s
76
74
  message = ::I18n.translate(key, **options)
77
- message.present? ? message : ::I18n.translate(key, locale: FALLBACK_LOCALE, **options)
75
+ message.present? ? message : fallback_message(key, **options)
76
+ end
77
+
78
+ def fallback_message(key, **options)
79
+ if ::I18n.enforce_available_locales && !::I18n.available_locales.include?(FALLBACK_LOCALE)
80
+ key
81
+ else
82
+ ::I18n.translate(key, locale: FALLBACK_LOCALE, **options)
83
+ end
78
84
  end
79
85
  end
80
86
  end