grape 1.2.5 → 1.3.0

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 (253) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/README.md +5 -3
  4. data/UPGRADING.md +43 -0
  5. data/grape.gemspec +10 -1
  6. data/lib/grape.rb +2 -2
  7. data/lib/grape/api.rb +2 -0
  8. data/lib/grape/api/helpers.rb +2 -0
  9. data/lib/grape/api/instance.rb +4 -2
  10. data/lib/grape/config.rb +2 -0
  11. data/lib/grape/cookies.rb +2 -0
  12. data/lib/grape/dsl/api.rb +2 -0
  13. data/lib/grape/dsl/callbacks.rb +2 -0
  14. data/lib/grape/dsl/configuration.rb +2 -0
  15. data/lib/grape/dsl/desc.rb +2 -0
  16. data/lib/grape/dsl/headers.rb +2 -0
  17. data/lib/grape/dsl/helpers.rb +3 -1
  18. data/lib/grape/dsl/inside_route.rb +7 -4
  19. data/lib/grape/dsl/logger.rb +2 -0
  20. data/lib/grape/dsl/middleware.rb +2 -0
  21. data/lib/grape/dsl/parameters.rb +4 -2
  22. data/lib/grape/dsl/request_response.rb +4 -2
  23. data/lib/grape/dsl/routing.rb +3 -1
  24. data/lib/grape/dsl/settings.rb +7 -1
  25. data/lib/grape/dsl/validations.rb +2 -0
  26. data/lib/grape/eager_load.rb +2 -0
  27. data/lib/grape/endpoint.rb +13 -7
  28. data/lib/grape/error_formatter.rb +3 -1
  29. data/lib/grape/error_formatter/base.rb +2 -0
  30. data/lib/grape/error_formatter/json.rb +2 -0
  31. data/lib/grape/error_formatter/txt.rb +2 -0
  32. data/lib/grape/error_formatter/xml.rb +2 -0
  33. data/lib/grape/exceptions/base.rb +11 -9
  34. data/lib/grape/exceptions/incompatible_option_values.rb +2 -0
  35. data/lib/grape/exceptions/invalid_accept_header.rb +2 -0
  36. data/lib/grape/exceptions/invalid_formatter.rb +2 -0
  37. data/lib/grape/exceptions/invalid_message_body.rb +2 -0
  38. data/lib/grape/exceptions/invalid_response.rb +2 -0
  39. data/lib/grape/exceptions/invalid_version_header.rb +2 -0
  40. data/lib/grape/exceptions/invalid_versioner_option.rb +2 -0
  41. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +2 -0
  42. data/lib/grape/exceptions/method_not_allowed.rb +2 -0
  43. data/lib/grape/exceptions/missing_group_type.rb +2 -0
  44. data/lib/grape/exceptions/missing_mime_type.rb +2 -0
  45. data/lib/grape/exceptions/missing_option.rb +2 -0
  46. data/lib/grape/exceptions/missing_vendor_option.rb +2 -0
  47. data/lib/grape/exceptions/unknown_options.rb +2 -0
  48. data/lib/grape/exceptions/unknown_parameter.rb +2 -0
  49. data/lib/grape/exceptions/unknown_validator.rb +2 -0
  50. data/lib/grape/exceptions/unsupported_group_type.rb +2 -0
  51. data/lib/grape/exceptions/validation.rb +3 -1
  52. data/lib/grape/exceptions/validation_array_errors.rb +2 -0
  53. data/lib/grape/exceptions/validation_errors.rb +2 -0
  54. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +4 -3
  55. data/lib/grape/extensions/deep_mergeable_hash.rb +2 -0
  56. data/lib/grape/extensions/deep_symbolize_hash.rb +2 -0
  57. data/lib/grape/extensions/hash.rb +2 -0
  58. data/lib/grape/extensions/hashie/mash.rb +2 -0
  59. data/lib/grape/formatter.rb +5 -3
  60. data/lib/grape/formatter/json.rb +2 -0
  61. data/lib/grape/formatter/serializable_hash.rb +2 -0
  62. data/lib/grape/formatter/txt.rb +2 -0
  63. data/lib/grape/formatter/xml.rb +2 -0
  64. data/lib/grape/http/headers.rb +23 -17
  65. data/lib/grape/middleware/auth/base.rb +2 -0
  66. data/lib/grape/middleware/auth/dsl.rb +2 -0
  67. data/lib/grape/middleware/auth/strategies.rb +2 -0
  68. data/lib/grape/middleware/auth/strategy_info.rb +2 -0
  69. data/lib/grape/middleware/base.rb +4 -2
  70. data/lib/grape/middleware/error.rb +3 -1
  71. data/lib/grape/middleware/filter.rb +2 -0
  72. data/lib/grape/middleware/formatter.rb +5 -3
  73. data/lib/grape/middleware/globals.rb +2 -0
  74. data/lib/grape/middleware/helpers.rb +2 -0
  75. data/lib/grape/middleware/stack.rb +2 -0
  76. data/lib/grape/middleware/versioner.rb +2 -0
  77. data/lib/grape/middleware/versioner/accept_version_header.rb +2 -0
  78. data/lib/grape/middleware/versioner/header.rb +2 -0
  79. data/lib/grape/middleware/versioner/param.rb +3 -1
  80. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -0
  81. data/lib/grape/middleware/versioner/path.rb +2 -0
  82. data/lib/grape/namespace.rb +2 -0
  83. data/lib/grape/parser.rb +3 -1
  84. data/lib/grape/parser/json.rb +2 -0
  85. data/lib/grape/parser/xml.rb +2 -0
  86. data/lib/grape/path.rb +2 -0
  87. data/lib/grape/presenters/presenter.rb +2 -0
  88. data/lib/grape/request.rb +3 -1
  89. data/lib/grape/router.rb +11 -6
  90. data/lib/grape/router/attribute_translator.rb +18 -8
  91. data/lib/grape/router/pattern.rb +6 -3
  92. data/lib/grape/router/route.rb +7 -2
  93. data/lib/grape/serve_file/file_body.rb +2 -0
  94. data/lib/grape/serve_file/file_response.rb +2 -0
  95. data/lib/grape/serve_file/sendfile_response.rb +2 -0
  96. data/lib/grape/util/base_inheritable.rb +2 -0
  97. data/lib/grape/util/content_types.rb +2 -0
  98. data/lib/grape/util/endpoint_configuration.rb +2 -0
  99. data/lib/grape/util/env.rb +19 -17
  100. data/lib/grape/util/inheritable_setting.rb +2 -0
  101. data/lib/grape/util/inheritable_values.rb +2 -0
  102. data/lib/grape/util/json.rb +2 -0
  103. data/lib/grape/util/lazy_block.rb +2 -0
  104. data/lib/grape/util/lazy_value.rb +2 -0
  105. data/lib/grape/util/registrable.rb +2 -0
  106. data/lib/grape/util/reverse_stackable_values.rb +2 -0
  107. data/lib/grape/util/stackable_values.rb +3 -0
  108. data/lib/grape/util/strict_hash_configuration.rb +2 -0
  109. data/lib/grape/util/xml.rb +2 -0
  110. data/lib/grape/validations.rb +2 -0
  111. data/lib/grape/validations/attributes_iterator.rb +3 -3
  112. data/lib/grape/validations/multiple_attributes_iterator.rb +2 -0
  113. data/lib/grape/validations/params_scope.rb +23 -10
  114. data/lib/grape/validations/single_attribute_iterator.rb +13 -2
  115. data/lib/grape/validations/types.rb +7 -30
  116. data/lib/grape/validations/types/array_coercer.rb +56 -0
  117. data/lib/grape/validations/types/build_coercer.rb +49 -48
  118. data/lib/grape/validations/types/custom_type_coercer.rb +15 -49
  119. data/lib/grape/validations/types/custom_type_collection_coercer.rb +10 -25
  120. data/lib/grape/validations/types/dry_type_coercer.rb +41 -0
  121. data/lib/grape/validations/types/file.rb +10 -9
  122. data/lib/grape/validations/types/json.rb +11 -8
  123. data/lib/grape/validations/types/multiple_type_coercer.rb +14 -33
  124. data/lib/grape/validations/types/primitive_coercer.rb +58 -0
  125. data/lib/grape/validations/types/set_coercer.rb +38 -0
  126. data/lib/grape/validations/types/variant_collection_coercer.rb +4 -12
  127. data/lib/grape/validations/validator_factory.rb +2 -0
  128. data/lib/grape/validations/validators/all_or_none.rb +3 -1
  129. data/lib/grape/validations/validators/allow_blank.rb +3 -1
  130. data/lib/grape/validations/validators/as.rb +2 -0
  131. data/lib/grape/validations/validators/at_least_one_of.rb +3 -1
  132. data/lib/grape/validations/validators/base.rb +8 -5
  133. data/lib/grape/validations/validators/coerce.rb +43 -26
  134. data/lib/grape/validations/validators/default.rb +2 -0
  135. data/lib/grape/validations/validators/exactly_one_of.rb +3 -1
  136. data/lib/grape/validations/validators/except_values.rb +3 -1
  137. data/lib/grape/validations/validators/multiple_params_base.rb +2 -0
  138. data/lib/grape/validations/validators/mutual_exclusion.rb +3 -1
  139. data/lib/grape/validations/validators/presence.rb +3 -1
  140. data/lib/grape/validations/validators/regexp.rb +3 -1
  141. data/lib/grape/validations/validators/same_as.rb +6 -3
  142. data/lib/grape/validations/validators/values.rb +17 -5
  143. data/lib/grape/version.rb +3 -1
  144. data/spec/grape/api/custom_validations_spec.rb +5 -3
  145. data/spec/grape/api/deeply_included_options_spec.rb +2 -0
  146. data/spec/grape/api/defines_boolean_in_params_spec.rb +5 -3
  147. data/spec/grape/api/inherited_helpers_spec.rb +2 -0
  148. data/spec/grape/api/instance_spec.rb +54 -0
  149. data/spec/grape/api/invalid_format_spec.rb +2 -0
  150. data/spec/grape/api/namespace_parameters_in_route_spec.rb +2 -0
  151. data/spec/grape/api/nested_helpers_spec.rb +2 -0
  152. data/spec/grape/api/optional_parameters_in_route_spec.rb +2 -0
  153. data/spec/grape/api/parameters_modification_spec.rb +3 -1
  154. data/spec/grape/api/patch_method_helpers_spec.rb +2 -0
  155. data/spec/grape/api/recognize_path_spec.rb +2 -0
  156. data/spec/grape/api/required_parameters_in_route_spec.rb +2 -0
  157. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +2 -0
  158. data/spec/grape/api/routes_with_requirements_spec.rb +2 -0
  159. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +2 -0
  160. data/spec/grape/api/shared_helpers_spec.rb +2 -0
  161. data/spec/grape/api_remount_spec.rb +2 -0
  162. data/spec/grape/api_spec.rb +27 -5
  163. data/spec/grape/config_spec.rb +2 -0
  164. data/spec/grape/dsl/callbacks_spec.rb +2 -0
  165. data/spec/grape/dsl/configuration_spec.rb +2 -0
  166. data/spec/grape/dsl/desc_spec.rb +2 -0
  167. data/spec/grape/dsl/headers_spec.rb +2 -0
  168. data/spec/grape/dsl/helpers_spec.rb +4 -2
  169. data/spec/grape/dsl/inside_route_spec.rb +2 -0
  170. data/spec/grape/dsl/logger_spec.rb +2 -0
  171. data/spec/grape/dsl/middleware_spec.rb +2 -0
  172. data/spec/grape/dsl/parameters_spec.rb +2 -0
  173. data/spec/grape/dsl/request_response_spec.rb +2 -0
  174. data/spec/grape/dsl/routing_spec.rb +2 -0
  175. data/spec/grape/dsl/settings_spec.rb +2 -0
  176. data/spec/grape/dsl/validations_spec.rb +2 -0
  177. data/spec/grape/endpoint_spec.rb +3 -1
  178. data/spec/grape/entity_spec.rb +2 -0
  179. data/spec/grape/exceptions/base_spec.rb +3 -1
  180. data/spec/grape/exceptions/body_parse_errors_spec.rb +2 -0
  181. data/spec/grape/exceptions/invalid_accept_header_spec.rb +2 -0
  182. data/spec/grape/exceptions/invalid_formatter_spec.rb +2 -0
  183. data/spec/grape/exceptions/invalid_response_spec.rb +2 -0
  184. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +2 -0
  185. data/spec/grape/exceptions/missing_mime_type_spec.rb +2 -0
  186. data/spec/grape/exceptions/missing_option_spec.rb +2 -0
  187. data/spec/grape/exceptions/unknown_options_spec.rb +2 -0
  188. data/spec/grape/exceptions/unknown_validator_spec.rb +2 -0
  189. data/spec/grape/exceptions/validation_errors_spec.rb +2 -0
  190. data/spec/grape/exceptions/validation_spec.rb +3 -1
  191. data/spec/grape/extensions/param_builders/hash_spec.rb +2 -0
  192. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +2 -0
  193. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +2 -0
  194. data/spec/grape/integration/global_namespace_function_spec.rb +2 -0
  195. data/spec/grape/integration/rack_sendfile_spec.rb +2 -0
  196. data/spec/grape/integration/rack_spec.rb +3 -1
  197. data/spec/grape/loading_spec.rb +2 -0
  198. data/spec/grape/middleware/auth/base_spec.rb +2 -0
  199. data/spec/grape/middleware/auth/dsl_spec.rb +2 -0
  200. data/spec/grape/middleware/auth/strategies_spec.rb +2 -0
  201. data/spec/grape/middleware/base_spec.rb +2 -0
  202. data/spec/grape/middleware/error_spec.rb +2 -0
  203. data/spec/grape/middleware/exception_spec.rb +3 -1
  204. data/spec/grape/middleware/formatter_spec.rb +17 -10
  205. data/spec/grape/middleware/globals_spec.rb +2 -0
  206. data/spec/grape/middleware/stack_spec.rb +2 -0
  207. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -1
  208. data/spec/grape/middleware/versioner/header_spec.rb +3 -1
  209. data/spec/grape/middleware/versioner/param_spec.rb +3 -1
  210. data/spec/grape/middleware/versioner/path_spec.rb +3 -1
  211. data/spec/grape/middleware/versioner_spec.rb +2 -0
  212. data/spec/grape/named_api_spec.rb +2 -0
  213. data/spec/grape/parser_spec.rb +7 -5
  214. data/spec/grape/path_spec.rb +2 -0
  215. data/spec/grape/presenters/presenter_spec.rb +2 -0
  216. data/spec/grape/request_spec.rb +2 -0
  217. data/spec/grape/util/inheritable_setting_spec.rb +2 -0
  218. data/spec/grape/util/inheritable_values_spec.rb +2 -0
  219. data/spec/grape/util/reverse_stackable_values_spec.rb +2 -0
  220. data/spec/grape/util/stackable_values_spec.rb +3 -1
  221. data/spec/grape/util/strict_hash_configuration_spec.rb +2 -0
  222. data/spec/grape/validations/attributes_iterator_spec.rb +2 -0
  223. data/spec/grape/validations/instance_behaivour_spec.rb +4 -2
  224. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +2 -0
  225. data/spec/grape/validations/params_scope_spec.rb +3 -1
  226. data/spec/grape/validations/single_attribute_iterator_spec.rb +18 -4
  227. data/spec/grape/validations/types_spec.rb +8 -35
  228. data/spec/grape/validations/validators/all_or_none_spec.rb +2 -0
  229. data/spec/grape/validations/validators/allow_blank_spec.rb +2 -0
  230. data/spec/grape/validations/validators/at_least_one_of_spec.rb +2 -0
  231. data/spec/grape/validations/validators/coerce_spec.rb +43 -66
  232. data/spec/grape/validations/validators/default_spec.rb +2 -0
  233. data/spec/grape/validations/validators/exactly_one_of_spec.rb +2 -0
  234. data/spec/grape/validations/validators/except_values_spec.rb +3 -1
  235. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +2 -0
  236. data/spec/grape/validations/validators/presence_spec.rb +30 -0
  237. data/spec/grape/validations/validators/regexp_spec.rb +2 -0
  238. data/spec/grape/validations/validators/same_as_spec.rb +2 -0
  239. data/spec/grape/validations/validators/values_spec.rb +29 -4
  240. data/spec/grape/validations_spec.rb +61 -3
  241. data/spec/integration/multi_json/json_spec.rb +2 -0
  242. data/spec/integration/multi_xml/xml_spec.rb +2 -0
  243. data/spec/shared/versioning_examples.rb +2 -0
  244. data/spec/spec_helper.rb +15 -0
  245. data/spec/support/basic_auth_encode_helpers.rb +2 -0
  246. data/spec/support/content_type_helpers.rb +2 -0
  247. data/spec/support/endpoint_faker.rb +2 -0
  248. data/spec/support/file_streamer.rb +2 -0
  249. data/spec/support/integer_helpers.rb +2 -0
  250. data/spec/support/versioned_helpers.rb +4 -2
  251. metadata +119 -111
  252. data/lib/grape/extensions/deep_hash_with_indifferent_access.rb +0 -18
  253. data/lib/grape/validations/types/virtus_collection_patch.rb +0 -16
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Grape::Validations::AllOrNoneOfValidator do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Grape::Validations::AllowBlankValidator do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Grape::Validations::AtLeastOneOfValidator do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Grape::Validations::CoerceValidator do
@@ -10,11 +12,13 @@ describe Grape::Validations::CoerceValidator do
10
12
  end
11
13
 
12
14
  describe 'coerce' do
13
- module CoerceValidatorSpec
14
- class User
15
- include Virtus.model
16
- attribute :id, Integer
17
- attribute :name, String
15
+ class SecureURIOnly
16
+ def self.parse(value)
17
+ URI.parse(value)
18
+ end
19
+
20
+ def self.parsed?(value)
21
+ value.is_a? URI::HTTPS
18
22
  end
19
23
  end
20
24
 
@@ -96,6 +100,7 @@ describe Grape::Validations::CoerceValidator do
96
100
 
97
101
  it 'respects :coerce_with' do
98
102
  get '/', a: 'yup'
103
+
99
104
  expect(last_response.status).to eq(200)
100
105
  expect(last_response.body).to eq('TrueClass')
101
106
  end
@@ -148,25 +153,6 @@ describe Grape::Validations::CoerceValidator do
148
153
  expect(last_response.body).to eq('array int works')
149
154
  end
150
155
 
151
- context 'complex objects' do
152
- it 'error on malformed input for complex objects' do
153
- subject.params do
154
- requires :user, type: CoerceValidatorSpec::User
155
- end
156
- subject.get '/user' do
157
- 'complex works'
158
- end
159
-
160
- get '/user', user: '32'
161
- expect(last_response.status).to eq(400)
162
- expect(last_response.body).to eq('user is invalid')
163
-
164
- get '/user', user: { id: 32, name: 'Bob' }
165
- expect(last_response.status).to eq(200)
166
- expect(last_response.body).to eq('complex works')
167
- end
168
- end
169
-
170
156
  context 'coerces' do
171
157
  it 'Integer' do
172
158
  subject.params do
@@ -181,6 +167,25 @@ describe Grape::Validations::CoerceValidator do
181
167
  expect(last_response.body).to eq(integer_class_name)
182
168
  end
183
169
 
170
+ it 'is a custom type' do
171
+ subject.params do
172
+ requires :uri, coerce: SecureURIOnly
173
+ end
174
+ subject.get '/secure_uri' do
175
+ params[:uri].class
176
+ end
177
+
178
+ get 'secure_uri', uri: 'https://www.example.com'
179
+
180
+ expect(last_response.status).to eq(200)
181
+ expect(last_response.body).to eq('URI::HTTPS')
182
+
183
+ get 'secure_uri', uri: 'http://www.example.com'
184
+
185
+ expect(last_response.status).to eq(400)
186
+ expect(last_response.body).to eq('uri is invalid')
187
+ end
188
+
184
189
  context 'Array' do
185
190
  it 'Array of Integers' do
186
191
  subject.params do
@@ -197,7 +202,7 @@ describe Grape::Validations::CoerceValidator do
197
202
 
198
203
  it 'Array of Bools' do
199
204
  subject.params do
200
- requires :arry, coerce: Array[Virtus::Attribute::Boolean]
205
+ requires :arry, coerce: Array[Grape::API::Boolean]
201
206
  end
202
207
  subject.get '/array' do
203
208
  params[:arry][0].class
@@ -208,27 +213,6 @@ describe Grape::Validations::CoerceValidator do
208
213
  expect(last_response.body).to eq('TrueClass')
209
214
  end
210
215
 
211
- it 'Array of Complex' do
212
- subject.params do
213
- requires :arry, coerce: Array[CoerceValidatorSpec::User]
214
- end
215
- subject.get '/array' do
216
- params[:arry].size
217
- end
218
-
219
- get 'array', arry: [31]
220
- expect(last_response.status).to eq(400)
221
- expect(last_response.body).to eq('arry is invalid')
222
-
223
- get 'array', arry: { id: 31, name: 'Alice' }
224
- expect(last_response.status).to eq(400)
225
- expect(last_response.body).to eq('arry is invalid')
226
-
227
- get 'array', arry: [{ id: 31, name: 'Alice' }]
228
- expect(last_response.status).to eq(200)
229
- expect(last_response.body).to eq('1')
230
- end
231
-
232
216
  it 'Array of type implementing parse' do
233
217
  subject.params do
234
218
  requires :uri, type: Array[URI]
@@ -253,17 +237,7 @@ describe Grape::Validations::CoerceValidator do
253
237
  expect(last_response.body).to eq('Set,URI::HTTP,1')
254
238
  end
255
239
 
256
- it 'Array of class implementing parse and parsed?' do
257
- class SecureURIOnly
258
- def self.parse(value)
259
- URI.parse(value)
260
- end
261
-
262
- def self.parsed?(value)
263
- value.is_a? URI::HTTPS
264
- end
265
- end
266
-
240
+ it 'Array of a custom type' do
267
241
  subject.params do
268
242
  requires :uri, type: Array[SecureURIOnly]
269
243
  end
@@ -295,7 +269,7 @@ describe Grape::Validations::CoerceValidator do
295
269
 
296
270
  it 'Set of Bools' do
297
271
  subject.params do
298
- requires :set, coerce: Set[Virtus::Attribute::Boolean]
272
+ requires :set, coerce: Set[Grape::API::Boolean]
299
273
  end
300
274
  subject.get '/set' do
301
275
  params[:set].first.class
@@ -309,7 +283,7 @@ describe Grape::Validations::CoerceValidator do
309
283
 
310
284
  it 'Bool' do
311
285
  subject.params do
312
- requires :bool, coerce: Virtus::Attribute::Boolean
286
+ requires :bool, coerce: Grape::API::Boolean
313
287
  end
314
288
  subject.get '/bool' do
315
289
  params[:bool].class
@@ -443,19 +417,19 @@ describe Grape::Validations::CoerceValidator do
443
417
 
444
418
  it 'parses parameters with Array[String] type' do
445
419
  subject.params do
446
- requires :values, type: Array[String], coerce_with: ->(val) { val.split(/\s+/).map(&:to_i) }
420
+ requires :values, type: Array[String], coerce_with: ->(val) { val.split(/\s+/) }
447
421
  end
448
- subject.get '/ints' do
422
+ subject.get '/strings' do
449
423
  params[:values]
450
424
  end
451
425
 
452
- get '/ints', values: '1 2 3 4'
426
+ get '/strings', values: '1 2 3 4'
453
427
  expect(last_response.status).to eq(200)
454
428
  expect(JSON.parse(last_response.body)).to eq(%w[1 2 3 4])
455
429
 
456
- get '/ints', values: 'a b c d'
430
+ get '/strings', values: 'a b c d'
457
431
  expect(last_response.status).to eq(200)
458
- expect(JSON.parse(last_response.body)).to eq(%w[0 0 0 0])
432
+ expect(JSON.parse(last_response.body)).to eq(%w[a b c d])
459
433
  end
460
434
 
461
435
  it 'parses parameters with Array[Integer] type' do
@@ -914,14 +888,17 @@ describe Grape::Validations::CoerceValidator do
914
888
  end
915
889
 
916
890
  context 'converter' do
917
- it 'does not build Virtus::Attribute multiple times' do
891
+ it 'does not build a coercer multiple times' do
918
892
  subject.params do
919
893
  requires :something, type: Array[String]
920
894
  end
921
895
  subject.get do
922
896
  end
923
897
 
924
- expect(Virtus::Attribute).to receive(:build).at_most(2).times.and_call_original
898
+ expect(Grape::Validations::Types::ArrayCoercer).to(
899
+ receive(:new).at_most(:once).and_call_original
900
+ )
901
+
925
902
  10.times { get '/' }
926
903
  end
927
904
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Grape::Validations::DefaultValidator do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Grape::Validations::ExactlyOneOfValidator do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Grape::Validations::ExceptValuesValidator do
@@ -110,7 +112,7 @@ describe Grape::Validations::ExceptValuesValidator do
110
112
  optional: { type: Array[Integer], except_values: [10, 11], default: 12 },
111
113
  tests: [
112
114
  { value: 'invalid-type1', rc: 400, body: { error: 'type is invalid' }.to_json },
113
- { value: 10, rc: 400, body: { error: 'type has a value not allowed' }.to_json },
115
+ { value: 10, rc: 400, body: { error: 'type is invalid' }.to_json },
114
116
  { value: [10], rc: 400, body: { error: 'type has a value not allowed' }.to_json },
115
117
  { value: ['3'], rc: 200, body: { type: [3] }.to_json },
116
118
  { value: [3], rc: 200, body: { type: [3] }.to_json },
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Grape::Validations::MutualExclusionValidator do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Grape::Validations::PresenceValidator do
@@ -269,4 +271,32 @@ describe Grape::Validations::PresenceValidator do
269
271
  expect(last_response.body).to eq('Hello optional'.to_json)
270
272
  end
271
273
  end
274
+
275
+ context 'with a custom type' do
276
+ it 'does not validate their type when it is missing' do
277
+ class CustomType
278
+ def self.parse(value)
279
+ return if value.blank?
280
+
281
+ new
282
+ end
283
+ end
284
+
285
+ subject.params do
286
+ requires :custom, type: CustomType
287
+ end
288
+ subject.get '/custom' do
289
+ 'custom'
290
+ end
291
+
292
+ get 'custom'
293
+
294
+ expect(last_response.status).to eq(400)
295
+ expect(last_response.body).to eq('{"error":"custom is missing"}')
296
+
297
+ get 'custom', custom: 'filled'
298
+
299
+ expect(last_response.status).to eq(200)
300
+ end
301
+ end
272
302
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Grape::Validations::RegexpValidator do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Grape::Validations::SameAsValidator do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Grape::Validations::ValuesValidator do
@@ -222,6 +224,11 @@ describe Grape::Validations::ValuesValidator do
222
224
  requires :type, values: { proc: ->(v) { ValuesModel.values.include? v }, message: 'failed check' }
223
225
  end
224
226
  get '/proc/message'
227
+
228
+ params do
229
+ optional :name, type: String, values: %w[a b], allow_blank: true
230
+ end
231
+ get '/allow_blank'
225
232
  end
226
233
  end
227
234
  end
@@ -431,11 +438,21 @@ describe Grape::Validations::ValuesValidator do
431
438
  end.to raise_error Grape::Exceptions::IncompatibleOptionValues
432
439
  end
433
440
 
434
- it 'allows values to be true or false when setting the type to boolean' do
435
- get('/values/optional_boolean', type: true)
436
- expect(last_response.status).to eq 200
437
- expect(last_response.body).to eq({ type: true }.to_json)
441
+ context 'boolean values' do
442
+ it 'allows a value from the list' do
443
+ get('/values/optional_boolean', type: true)
444
+
445
+ expect(last_response.status).to eq 200
446
+ expect(last_response.body).to eq({ type: true }.to_json)
447
+ end
448
+
449
+ it 'rejects a value which is not in the list' do
450
+ get('/values/optional_boolean', type: false)
451
+
452
+ expect(last_response.body).to eq({ error: 'type does not have a valid value' }.to_json)
453
+ end
438
454
  end
455
+
439
456
  it 'allows values to be a kind of the coerced type not just an instance of it' do
440
457
  get('/values/coercion', type: 10)
441
458
  expect(last_response.status).to eq 200
@@ -462,6 +479,14 @@ describe Grape::Validations::ValuesValidator do
462
479
  end.to raise_error Grape::Exceptions::IncompatibleOptionValues
463
480
  end
464
481
 
482
+ it 'allows a blank value when the allow_blank option is true' do
483
+ get 'allow_blank', name: nil
484
+ expect(last_response.status).to eq(200)
485
+
486
+ get 'allow_blank', name: ''
487
+ expect(last_response.status).to eq(200)
488
+ end
489
+
465
490
  context 'with a lambda values' do
466
491
  subject do
467
492
  Class.new(Grape::API) do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Grape::Validations do
@@ -120,6 +122,62 @@ describe Grape::Validations do
120
122
  end
121
123
  end
122
124
 
125
+ context 'requires with nested params' do
126
+ before do
127
+ subject.params do
128
+ requires :first_level, type: Hash do
129
+ optional :second_level, type: Array do
130
+ requires :value, type: Integer
131
+ optional :name, type: String
132
+ optional :third_level, type: Array do
133
+ requires :value, type: Integer
134
+ optional :name, type: String
135
+ optional :fourth_level, type: Array do
136
+ requires :value, type: Integer
137
+ optional :name, type: String
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ subject.put('/required') { 'required works' }
144
+ end
145
+
146
+ let(:request_params) do
147
+ {
148
+ first_level: {
149
+ second_level: [
150
+ { value: 1, name: 'Lisa' },
151
+ {
152
+ value: 2,
153
+ name: 'James',
154
+ third_level: [
155
+ { value: 'three', name: 'Sophie' },
156
+ {
157
+ value: 4,
158
+ name: 'Jenny',
159
+ fourth_level: [
160
+ { name: 'Samuel' }, { value: 6, name: 'Jane' }
161
+ ]
162
+ }
163
+ ]
164
+ }
165
+ ]
166
+ }
167
+ }
168
+ end
169
+
170
+ it 'validates correctly in deep nested params' do
171
+ put '/required', request_params.to_json, 'CONTENT_TYPE' => 'application/json'
172
+
173
+ expect(last_response.status).to eq(400)
174
+ expect(last_response.body).to eq(
175
+ 'first_level[second_level][1][third_level][0][value] is invalid, ' \
176
+ 'first_level[second_level][1][third_level][1][fourth_level][0][value] is missing'
177
+ )
178
+ end
179
+ end
180
+
123
181
  context 'requires :all using Grape::Entity documentation' do
124
182
  def define_requires_all
125
183
  documentation = {
@@ -436,7 +494,7 @@ describe Grape::Validations do
436
494
  class DateRangeValidator < Grape::Validations::Base
437
495
  def validate_param!(attr_name, params)
438
496
  return if params[attr_name][:from] <= params[attr_name][:to]
439
- raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: "'from' must be lower or equal to 'to'"
497
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: "'from' must be lower or equal to 'to'")
440
498
  end
441
499
  end
442
500
  end
@@ -851,7 +909,7 @@ describe Grape::Validations do
851
909
  class Customvalidator < Grape::Validations::Base
852
910
  def validate_param!(attr_name, params)
853
911
  return if params[attr_name] == 'im custom'
854
- raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: 'is not custom!'
912
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: 'is not custom!')
855
913
  end
856
914
  end
857
915
  end
@@ -999,7 +1057,7 @@ describe Grape::Validations do
999
1057
  class CustomvalidatorWithOptions < Grape::Validations::Base
1000
1058
  def validate_param!(attr_name, params)
1001
1059
  return if params[attr_name] == @option[:text]
1002
- raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message
1060
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message)
1003
1061
  end
1004
1062
  end
1005
1063
  end