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,37 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_inheritable'
4
+
1
5
  module Grape
2
6
  module Util
3
- class StackableValues
4
- attr_accessor :inherited_values
5
- attr_accessor :new_values
6
- attr_reader :frozen_values
7
-
8
- def initialize(inherited_values = {})
9
- @inherited_values = inherited_values
10
- @new_values = {}
11
- @frozen_values = {}
12
- end
13
-
7
+ class StackableValues < BaseInheritable
8
+ # Even if there is no value, an empty array will be returned.
14
9
  def [](name)
15
- return @frozen_values[name] if @frozen_values.key? name
16
-
17
- value = []
18
- value.concat(@inherited_values[name] || [])
19
- value.concat(@new_values[name] || [])
20
- value
21
- end
10
+ inherited_value = inherited_values[name]
11
+ new_value = new_values[name]
22
12
 
23
- def []=(name, value)
24
- raise if @frozen_values.key? name
25
- @new_values[name] ||= []
26
- @new_values[name].push value
27
- end
13
+ return new_value || [] unless inherited_value
28
14
 
29
- def delete(key)
30
- new_values.delete key
15
+ concat_values(inherited_value, new_value)
31
16
  end
32
17
 
33
- def keys
34
- (@new_values.keys + @inherited_values.keys).sort.uniq
18
+ def []=(name, value)
19
+ new_values[name] ||= []
20
+ new_values[name].push value
35
21
  end
36
22
 
37
23
  def to_hash
@@ -40,14 +26,15 @@ module Grape
40
26
  end
41
27
  end
42
28
 
43
- def freeze_value(key)
44
- @frozen_values[key] = self[key].freeze
45
- end
29
+ protected
30
+
31
+ def concat_values(inherited_value, new_value)
32
+ return inherited_value unless new_value
46
33
 
47
- def initialize_copy(other)
48
- super
49
- self.inherited_values = other.inherited_values
50
- self.new_values = other.new_values.dup
34
+ [].tap do |value|
35
+ value.concat(inherited_value)
36
+ value.concat(new_value)
37
+ end
51
38
  end
52
39
  end
53
40
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Util
3
5
  module StrictHashConfiguration
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  if Object.const_defined? :MultiXml
3
5
  Xml = ::MultiXml
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  # Registry to store and locate known Validators.
3
5
  module Validations
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  class AttributesIterator
@@ -29,9 +31,7 @@ module Grape
29
31
 
30
32
  if @scope.type == Array
31
33
  next unless @original_params.is_a?(Array) # do not validate content of array if it isn't array
32
- inside_array = true
33
- end
34
- if inside_array
34
+
35
35
  # fill current and parent scopes with correct array indicies
36
36
  parent_scope = @scope.parent
37
37
  parent_indicies.each do |parent_index|
@@ -41,11 +41,21 @@ module Grape
41
41
  @scope.index = index
42
42
  end
43
43
 
44
- @attrs.each do |attr_name|
45
- yield resource_params, attr_name, inside_array
46
- end
44
+ yield_attributes(resource_params, @attrs, &block)
47
45
  end
48
46
  end
47
+
48
+ def yield_attributes(_resource_params, _attrs)
49
+ raise NotImplementedError
50
+ end
51
+
52
+ # This is a special case so that we can ignore tree's where option
53
+ # values are missing lower down. Unfortunately we can remove this
54
+ # are the parameter parsing stage as they are required to ensure
55
+ # the correct indexing is maintained
56
+ def skip?(val)
57
+ val == Grape::DSL::Parameters::EmptyOptionalValue
58
+ end
49
59
  end
50
60
  end
51
61
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Validations
5
+ class MultipleAttributesIterator < AttributesIterator
6
+ private
7
+
8
+ def yield_attributes(resource_params, _attrs)
9
+ yield resource_params, skip?(resource_params)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  class ParamsScope
@@ -36,23 +38,32 @@ module Grape
36
38
  configure_declared_params
37
39
  end
38
40
 
41
+ def configuration
42
+ @api.configuration.respond_to?(:evaluate) ? @api.configuration.evaluate : @api.configuration
43
+ end
44
+
39
45
  # @return [Boolean] whether or not this entire scope needs to be
40
46
  # validated
41
47
  def should_validate?(parameters)
42
- return false if @optional && (params(parameters).blank? || all_element_blank?(parameters))
43
- return false unless meets_dependency?(params(parameters), parameters)
48
+ scoped_params = params(parameters)
49
+
50
+ return false if @optional && (scoped_params.blank? || all_element_blank?(scoped_params))
51
+ return false unless meets_dependency?(scoped_params, parameters)
44
52
  return true if parent.nil?
45
53
  parent.should_validate?(parameters)
46
54
  end
47
55
 
48
56
  def meets_dependency?(params, request_params)
57
+ return true unless @dependent_on
58
+
49
59
  if @parent.present? && !@parent.meets_dependency?(@parent.params(request_params), request_params)
50
60
  return false
51
61
  end
52
62
 
53
- return true unless @dependent_on
54
63
  return params.any? { |param| meets_dependency?(param, request_params) } if params.is_a?(Array)
55
- params = params.with_indifferent_access
64
+
65
+ # params might be anything what looks like a hash, so it must implement a `key?` method
66
+ return false unless params.respond_to?(:key?)
56
67
 
57
68
  @dependent_on.each do |dependency|
58
69
  if dependency.is_a?(Hash)
@@ -71,7 +82,7 @@ module Grape
71
82
  def full_name(name, index: nil)
72
83
  if nested?
73
84
  # Find our containing element's name, and append ours.
74
- [@parent.full_name(@element), [@index || index, name].map(&method(:brackets))].compact.join
85
+ "#{@parent.full_name(@element)}#{brackets(@index || index)}#{brackets(name)}"
75
86
  elsif lateral?
76
87
  # Find the name of the element as if it was at the same nesting level
77
88
  # as our parent. We need to forward our index upward to achieve this.
@@ -116,11 +127,12 @@ module Grape
116
127
  # @param attrs [Array] (see Grape::DSL::Parameters#requires)
117
128
  def push_declared_params(attrs, **opts)
118
129
  if lateral?
119
- @parent.push_declared_params(attrs, opts)
130
+ @parent.push_declared_params(attrs, **opts)
120
131
  else
121
132
  if opts && opts[:as]
122
- @api.route_setting(:aliased_params, @api.route_setting(:aliased_params) || [])
123
- @api.route_setting(:aliased_params) << { attrs.first => opts[:as] }
133
+ @api.route_setting(:renamed_params, @api.route_setting(:renamed_params) || [])
134
+ @api.route_setting(:renamed_params) << { attrs.first => opts[:as] }
135
+ attrs = [opts[:as]]
124
136
  end
125
137
 
126
138
  @declared_params.concat attrs
@@ -178,14 +190,12 @@ module Grape
178
190
  raise Grape::Exceptions::UnsupportedGroupTypeError.new unless Grape::Validations::Types.group?(type)
179
191
  end
180
192
 
181
- opts = attrs[1] || { type: Array }
182
-
183
193
  self.class.new(
184
194
  api: @api,
185
- element: attrs.first,
195
+ element: attrs[1][:as] || attrs.first,
186
196
  parent: self,
187
197
  optional: optional,
188
- type: opts[:type],
198
+ type: type || Array,
189
199
  &block
190
200
  )
191
201
  end
@@ -229,14 +239,14 @@ module Grape
229
239
  @parent.push_declared_params [element => @declared_params]
230
240
  else
231
241
  @api.namespace_stackable(:declared_params, @declared_params)
232
-
233
- @api.route_setting(:declared_params, []) unless @api.route_setting(:declared_params)
234
- @api.route_setting(:declared_params, @api.namespace_stackable(:declared_params).flatten)
235
242
  end
243
+
244
+ # params were stored in settings, it can be cleaned from the params scope
245
+ @declared_params = nil
236
246
  end
237
247
 
238
248
  def validates(attrs, validations)
239
- doc_attrs = { required: validations.keys.include?(:presence) }
249
+ doc_attrs = { required: validations.key?(:presence) }
240
250
 
241
251
  coerce_type = infer_coercion(validations)
242
252
 
@@ -276,9 +286,7 @@ module Grape
276
286
  full_attrs = attrs.collect { |name| { name: name, full_name: full_name(name) } }
277
287
  @api.document_attribute(full_attrs, doc_attrs)
278
288
 
279
- # slice out fail_fast attribute
280
- opts = {}
281
- opts[:fail_fast] = validations.delete(:fail_fast) || false
289
+ opts = derive_validator_options(validations)
282
290
 
283
291
  # Validate for presence before any other validators
284
292
  if validations.key?(:presence) && validations[:presence]
@@ -406,13 +414,15 @@ module Grape
406
414
 
407
415
  raise Grape::Exceptions::UnknownValidator.new(type) unless validator_class
408
416
 
409
- factory = Grape::Validations::ValidatorFactory.new(attributes: attrs,
410
- options: options,
411
- required: doc_attrs[:required],
412
- params_scope: self,
413
- opts: opts,
414
- validator_class: validator_class)
415
- @api.namespace_stackable(:validations, factory)
417
+ validator_options = {
418
+ attributes: attrs,
419
+ options: options,
420
+ required: doc_attrs[:required],
421
+ params_scope: self,
422
+ opts: opts,
423
+ validator_class: validator_class
424
+ }
425
+ @api.namespace_stackable(:validations, validator_options)
416
426
  end
417
427
 
418
428
  def validate_value_coercion(coerce_type, *values_list)
@@ -421,8 +431,8 @@ module Grape
421
431
  values_list.each do |values|
422
432
  next if !values || values.is_a?(Proc)
423
433
  value_types = values.is_a?(Range) ? [values.begin, values.end] : values
424
- if coerce_type == Virtus::Attribute::Boolean
425
- value_types = value_types.map { |type| Virtus::Attribute.build(type) }
434
+ if coerce_type == Grape::API::Boolean
435
+ value_types = value_types.map { |type| Grape::API::Boolean.build(type) }
426
436
  end
427
437
  unless value_types.all? { |v| v.is_a? coerce_type }
428
438
  raise Grape::Exceptions::IncompatibleOptionValues.new(:type, coerce_type, :values, values)
@@ -440,8 +450,19 @@ module Grape
440
450
  validations[type].respond_to?(:key?) && validations[type].key?(key) && !validations[type][key].nil?
441
451
  end
442
452
 
443
- def all_element_blank?(parameters)
444
- params(parameters).respond_to?(:all?) && params(parameters).all?(&:blank?)
453
+ def all_element_blank?(scoped_params)
454
+ scoped_params.respond_to?(:all?) && scoped_params.all?(&:blank?)
455
+ end
456
+
457
+ # Validators don't have access to each other and they don't need, however,
458
+ # some validators might influence others, so their options should be shared
459
+ def derive_validator_options(validations)
460
+ allow_blank = validations[:allow_blank]
461
+
462
+ {
463
+ allow_blank: allow_blank.is_a?(Hash) ? allow_blank[:value] : allow_blank,
464
+ fail_fast: validations.delete(:fail_fast) || false
465
+ }
445
466
  end
446
467
  end
447
468
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Validations
5
+ class SingleAttributeIterator < AttributesIterator
6
+ private
7
+
8
+ def yield_attributes(val, attrs)
9
+ attrs.each do |attr_name|
10
+ yield val, attr_name, empty?(val), skip?(val)
11
+ end
12
+ end
13
+
14
+ # Primitives like Integers and Booleans don't respond to +empty?+.
15
+ # It could be possible to use +blank?+ instead, but
16
+ #
17
+ # false.blank?
18
+ # => true
19
+ def empty?(val)
20
+ val.respond_to?(:empty?) ? val.empty? : val.nil?
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'types/build_coercer'
2
4
  require_relative 'types/custom_type_coercer'
3
5
  require_relative 'types/custom_type_collection_coercer'
@@ -5,10 +7,7 @@ require_relative 'types/multiple_type_coercer'
5
7
  require_relative 'types/variant_collection_coercer'
6
8
  require_relative 'types/json'
7
9
  require_relative 'types/file'
8
-
9
- # Patch for Virtus::Attribute::Collection
10
- # See the file for more details
11
- require_relative 'types/virtus_collection_patch'
10
+ require_relative 'types/invalid_value'
12
11
 
13
12
  module Grape
14
13
  module Validations
@@ -23,12 +22,7 @@ module Grape
23
22
  # and {Grape::Dsl::Parameters#optional}. The main
24
23
  # entry point for this process is {Types.build_coercer}.
25
24
  module Types
26
- # Instances of this class may be used as tokens to denote that
27
- # a parameter value could not be coerced.
28
- class InvalidValue; end
29
-
30
- # Types representing a single value, which are coerced through Virtus
31
- # or special logic in Grape.
25
+ # Types representing a single value, which are coerced.
32
26
  PRIMITIVES = [
33
27
  # Numerical
34
28
  Integer,
@@ -42,10 +36,11 @@ module Grape
42
36
  Time,
43
37
 
44
38
  # Misc
45
- Virtus::Attribute::Boolean,
39
+ Grape::API::Boolean,
46
40
  String,
47
41
  Symbol,
48
- Rack::Multipart::UploadedFile
42
+ TrueClass,
43
+ FalseClass
49
44
  ].freeze
50
45
 
51
46
  # Types representing data structures.
@@ -55,8 +50,7 @@ module Grape
55
50
  Set
56
51
  ].freeze
57
52
 
58
- # Types for which Grape provides special coercion
59
- # and type-checking logic.
53
+ # Special custom types provided by Grape.
60
54
  SPECIAL = {
61
55
  JSON => Json,
62
56
  Array[JSON] => JsonArray,
@@ -86,8 +80,6 @@ module Grape
86
80
  # @param type [Class] type to check
87
81
  # @return [Boolean] whether or not the type is known by Grape as a valid
88
82
  # data structure type
89
- # @note This method does not yet consider 'complex types', which inherit
90
- # Virtus.model.
91
83
  def self.structure?(type)
92
84
  STRUCTURES.include?(type)
93
85
  end
@@ -104,25 +96,6 @@ module Grape
104
96
  (type.is_a?(Array) || type.is_a?(Set)) && type.size > 1
105
97
  end
106
98
 
107
- # Does the given class implement a type system that Grape
108
- # (i.e. the underlying virtus attribute system) supports
109
- # out-of-the-box? Currently supported are +axiom-types+
110
- # and +virtus+.
111
- #
112
- # The type will be passed to +Virtus::Attribute.build+,
113
- # and the resulting attribute object will be expected to
114
- # respond correctly to +coerce+ and +value_coerced?+.
115
- #
116
- # @param type [Class] type to check
117
- # @return [Boolean] +true+ where the type is recognized
118
- def self.recognized?(type)
119
- return false if type.is_a?(Array) || type.is_a?(Set)
120
-
121
- type.is_a?(Virtus::Attribute) ||
122
- type.ancestors.include?(Axiom::Types::Type) ||
123
- type.include?(Virtus::Model::Core)
124
- end
125
-
126
99
  # Does Grape provide special coercion and validation
127
100
  # routines for the given class? This does not include
128
101
  # automatic handling for primitives, structures and
@@ -152,8 +125,6 @@ module Grape
152
125
  !primitive?(type) &&
153
126
  !structure?(type) &&
154
127
  !multiple?(type) &&
155
- !recognized?(type) &&
156
- !special?(type) &&
157
128
  type.respond_to?(:parse) &&
158
129
  type.method(:parse).arity == 1
159
130
  end
@@ -166,7 +137,11 @@ module Grape
166
137
  def self.collection_of_custom?(type)
167
138
  (type.is_a?(Array) || type.is_a?(Set)) &&
168
139
  type.length == 1 &&
169
- custom?(type.first)
140
+ (custom?(type.first) || special?(type.first))
141
+ end
142
+
143
+ def self.map_special(type)
144
+ SPECIAL.fetch(type, type)
170
145
  end
171
146
  end
172
147
  end