grape 1.2.5 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +97 -0
- data/LICENSE +1 -1
- data/README.md +53 -16
- data/UPGRADING.md +231 -23
- data/grape.gemspec +10 -1
- data/lib/grape.rb +6 -7
- data/lib/grape/api.rb +4 -2
- data/lib/grape/api/helpers.rb +2 -0
- data/lib/grape/api/instance.rb +36 -33
- data/lib/grape/config.rb +2 -0
- data/lib/grape/content_types.rb +34 -0
- data/lib/grape/cookies.rb +2 -0
- data/lib/grape/dsl/api.rb +2 -0
- data/lib/grape/dsl/callbacks.rb +2 -0
- data/lib/grape/dsl/configuration.rb +2 -0
- data/lib/grape/dsl/desc.rb +2 -0
- data/lib/grape/dsl/headers.rb +2 -0
- data/lib/grape/dsl/helpers.rb +4 -2
- data/lib/grape/dsl/inside_route.rb +83 -34
- data/lib/grape/dsl/logger.rb +2 -0
- data/lib/grape/dsl/middleware.rb +2 -0
- data/lib/grape/dsl/parameters.rb +8 -6
- data/lib/grape/dsl/request_response.rb +4 -2
- data/lib/grape/dsl/routing.rb +9 -5
- data/lib/grape/dsl/settings.rb +7 -1
- data/lib/grape/dsl/validations.rb +20 -1
- data/lib/grape/eager_load.rb +3 -1
- data/lib/grape/endpoint.rb +21 -13
- data/lib/grape/error_formatter.rb +3 -1
- data/lib/grape/error_formatter/base.rb +2 -0
- data/lib/grape/error_formatter/json.rb +2 -0
- data/lib/grape/error_formatter/txt.rb +2 -0
- data/lib/grape/error_formatter/xml.rb +2 -0
- data/lib/grape/exceptions/base.rb +11 -13
- data/lib/grape/exceptions/incompatible_option_values.rb +2 -0
- data/lib/grape/exceptions/invalid_accept_header.rb +2 -0
- data/lib/grape/exceptions/invalid_formatter.rb +2 -0
- data/lib/grape/exceptions/invalid_message_body.rb +2 -0
- data/lib/grape/exceptions/invalid_response.rb +2 -0
- data/lib/grape/exceptions/invalid_version_header.rb +2 -0
- data/lib/grape/exceptions/invalid_versioner_option.rb +2 -0
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +2 -0
- data/lib/grape/exceptions/method_not_allowed.rb +2 -0
- data/lib/grape/exceptions/missing_group_type.rb +2 -0
- data/lib/grape/exceptions/missing_mime_type.rb +2 -0
- data/lib/grape/exceptions/missing_option.rb +2 -0
- data/lib/grape/exceptions/missing_vendor_option.rb +2 -0
- data/lib/grape/exceptions/unknown_options.rb +2 -0
- data/lib/grape/exceptions/unknown_parameter.rb +2 -0
- data/lib/grape/exceptions/unknown_validator.rb +2 -0
- data/lib/grape/exceptions/unsupported_group_type.rb +2 -0
- data/lib/grape/exceptions/validation.rb +3 -1
- data/lib/grape/exceptions/validation_array_errors.rb +2 -0
- data/lib/grape/exceptions/validation_errors.rb +13 -12
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +4 -3
- data/lib/grape/extensions/deep_mergeable_hash.rb +2 -0
- data/lib/grape/extensions/deep_symbolize_hash.rb +2 -0
- data/lib/grape/extensions/hash.rb +2 -0
- data/lib/grape/extensions/hashie/mash.rb +2 -0
- data/lib/grape/formatter.rb +5 -3
- data/lib/grape/formatter/json.rb +2 -0
- data/lib/grape/formatter/serializable_hash.rb +2 -0
- data/lib/grape/formatter/txt.rb +2 -0
- data/lib/grape/formatter/xml.rb +2 -0
- data/lib/grape/http/headers.rb +50 -18
- data/lib/grape/middleware/auth/base.rb +2 -0
- data/lib/grape/middleware/auth/dsl.rb +2 -0
- data/lib/grape/middleware/auth/strategies.rb +2 -0
- data/lib/grape/middleware/auth/strategy_info.rb +2 -0
- data/lib/grape/middleware/base.rb +7 -7
- data/lib/grape/middleware/error.rb +3 -1
- data/lib/grape/middleware/filter.rb +2 -0
- data/lib/grape/middleware/formatter.rb +8 -6
- data/lib/grape/middleware/globals.rb +2 -0
- data/lib/grape/middleware/helpers.rb +2 -0
- data/lib/grape/middleware/stack.rb +4 -1
- data/lib/grape/middleware/versioner.rb +2 -0
- data/lib/grape/middleware/versioner/accept_version_header.rb +2 -0
- data/lib/grape/middleware/versioner/header.rb +6 -4
- data/lib/grape/middleware/versioner/param.rb +3 -1
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +4 -1
- data/lib/grape/middleware/versioner/path.rb +3 -1
- data/lib/grape/namespace.rb +14 -2
- data/lib/grape/parser.rb +3 -1
- data/lib/grape/parser/json.rb +2 -0
- data/lib/grape/parser/xml.rb +2 -0
- data/lib/grape/path.rb +15 -3
- data/lib/grape/presenters/presenter.rb +2 -0
- data/lib/grape/request.rb +15 -8
- data/lib/grape/router.rb +30 -29
- data/lib/grape/router/attribute_translator.rb +39 -8
- data/lib/grape/router/pattern.rb +20 -16
- data/lib/grape/router/route.rb +12 -26
- data/lib/grape/{serve_file → serve_stream}/file_body.rb +3 -1
- data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +3 -1
- data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +10 -8
- data/lib/grape/util/base_inheritable.rb +15 -6
- data/lib/grape/util/cache.rb +20 -0
- data/lib/grape/util/endpoint_configuration.rb +2 -0
- data/lib/grape/util/env.rb +19 -17
- data/lib/grape/util/inheritable_setting.rb +2 -0
- data/lib/grape/util/inheritable_values.rb +2 -0
- data/lib/grape/util/json.rb +2 -0
- data/lib/grape/util/lazy_block.rb +2 -0
- data/lib/grape/util/lazy_object.rb +43 -0
- data/lib/grape/util/lazy_value.rb +2 -0
- data/lib/grape/util/registrable.rb +2 -0
- data/lib/grape/util/reverse_stackable_values.rb +4 -0
- data/lib/grape/util/stackable_values.rb +10 -20
- data/lib/grape/util/strict_hash_configuration.rb +2 -0
- data/lib/grape/util/xml.rb +2 -0
- data/lib/grape/validations.rb +2 -0
- data/lib/grape/validations/attributes_iterator.rb +3 -3
- data/lib/grape/validations/multiple_attributes_iterator.rb +2 -0
- data/lib/grape/validations/params_scope.rb +27 -14
- data/lib/grape/validations/single_attribute_iterator.rb +13 -2
- data/lib/grape/validations/types.rb +12 -34
- data/lib/grape/validations/types/array_coercer.rb +65 -0
- data/lib/grape/validations/types/build_coercer.rb +47 -49
- data/lib/grape/validations/types/custom_type_coercer.rb +15 -49
- data/lib/grape/validations/types/custom_type_collection_coercer.rb +10 -25
- data/lib/grape/validations/types/dry_type_coercer.rb +76 -0
- data/lib/grape/validations/types/file.rb +22 -18
- data/lib/grape/validations/types/json.rb +46 -39
- data/lib/grape/validations/types/multiple_type_coercer.rb +14 -33
- data/lib/grape/validations/types/primitive_coercer.rb +67 -0
- data/lib/grape/validations/types/set_coercer.rb +40 -0
- data/lib/grape/validations/types/variant_collection_coercer.rb +5 -13
- data/lib/grape/validations/validator_factory.rb +2 -0
- data/lib/grape/validations/validators/all_or_none.rb +3 -1
- data/lib/grape/validations/validators/allow_blank.rb +3 -1
- data/lib/grape/validations/validators/as.rb +2 -0
- data/lib/grape/validations/validators/at_least_one_of.rb +3 -1
- data/lib/grape/validations/validators/base.rb +8 -5
- data/lib/grape/validations/validators/coerce.rb +39 -29
- data/lib/grape/validations/validators/default.rb +2 -1
- data/lib/grape/validations/validators/exactly_one_of.rb +6 -2
- data/lib/grape/validations/validators/except_values.rb +3 -1
- data/lib/grape/validations/validators/multiple_params_base.rb +2 -0
- data/lib/grape/validations/validators/mutual_exclusion.rb +3 -1
- data/lib/grape/validations/validators/presence.rb +3 -1
- data/lib/grape/validations/validators/regexp.rb +4 -2
- data/lib/grape/validations/validators/same_as.rb +6 -3
- data/lib/grape/validations/validators/values.rb +17 -5
- data/lib/grape/version.rb +3 -1
- data/spec/grape/api/custom_validations_spec.rb +5 -3
- data/spec/grape/api/deeply_included_options_spec.rb +2 -0
- data/spec/grape/api/defines_boolean_in_params_spec.rb +5 -3
- data/spec/grape/api/inherited_helpers_spec.rb +2 -0
- data/spec/grape/api/instance_spec.rb +104 -0
- data/spec/grape/api/invalid_format_spec.rb +2 -0
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/nested_helpers_spec.rb +2 -0
- data/spec/grape/api/optional_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/parameters_modification_spec.rb +3 -1
- data/spec/grape/api/patch_method_helpers_spec.rb +2 -0
- data/spec/grape/api/recognize_path_spec.rb +2 -0
- data/spec/grape/api/required_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +2 -0
- data/spec/grape/api/routes_with_requirements_spec.rb +2 -0
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +2 -0
- data/spec/grape/api/shared_helpers_spec.rb +2 -0
- data/spec/grape/api_remount_spec.rb +2 -0
- data/spec/grape/api_spec.rb +99 -11
- data/spec/grape/config_spec.rb +2 -0
- data/spec/grape/dsl/callbacks_spec.rb +2 -0
- data/spec/grape/dsl/configuration_spec.rb +2 -0
- data/spec/grape/dsl/desc_spec.rb +2 -0
- data/spec/grape/dsl/headers_spec.rb +2 -0
- data/spec/grape/dsl/helpers_spec.rb +4 -2
- data/spec/grape/dsl/inside_route_spec.rb +177 -33
- data/spec/grape/dsl/logger_spec.rb +2 -0
- data/spec/grape/dsl/middleware_spec.rb +2 -0
- data/spec/grape/dsl/parameters_spec.rb +2 -0
- data/spec/grape/dsl/request_response_spec.rb +2 -0
- data/spec/grape/dsl/routing_spec.rb +2 -0
- data/spec/grape/dsl/settings_spec.rb +2 -0
- data/spec/grape/dsl/validations_spec.rb +2 -0
- data/spec/grape/endpoint_spec.rb +21 -6
- data/spec/grape/entity_spec.rb +2 -0
- data/spec/grape/exceptions/base_spec.rb +3 -1
- data/spec/grape/exceptions/body_parse_errors_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_formatter_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_response_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +2 -0
- data/spec/grape/exceptions/missing_mime_type_spec.rb +2 -0
- data/spec/grape/exceptions/missing_option_spec.rb +2 -0
- data/spec/grape/exceptions/unknown_options_spec.rb +2 -0
- data/spec/grape/exceptions/unknown_validator_spec.rb +2 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +4 -2
- data/spec/grape/exceptions/validation_spec.rb +3 -1
- data/spec/grape/extensions/param_builders/hash_spec.rb +2 -0
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +2 -0
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +2 -0
- data/spec/grape/integration/global_namespace_function_spec.rb +2 -0
- data/spec/grape/integration/rack_sendfile_spec.rb +14 -8
- data/spec/grape/integration/rack_spec.rb +3 -1
- data/spec/grape/loading_spec.rb +2 -0
- data/spec/grape/middleware/auth/base_spec.rb +2 -0
- data/spec/grape/middleware/auth/dsl_spec.rb +2 -0
- data/spec/grape/middleware/auth/strategies_spec.rb +3 -1
- data/spec/grape/middleware/base_spec.rb +2 -0
- data/spec/grape/middleware/error_spec.rb +2 -0
- data/spec/grape/middleware/exception_spec.rb +3 -1
- data/spec/grape/middleware/formatter_spec.rb +19 -12
- data/spec/grape/middleware/globals_spec.rb +2 -0
- data/spec/grape/middleware/stack_spec.rb +11 -0
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -1
- data/spec/grape/middleware/versioner/header_spec.rb +3 -1
- data/spec/grape/middleware/versioner/param_spec.rb +3 -1
- data/spec/grape/middleware/versioner/path_spec.rb +3 -1
- data/spec/grape/middleware/versioner_spec.rb +2 -0
- data/spec/grape/named_api_spec.rb +2 -0
- data/spec/grape/parser_spec.rb +7 -5
- data/spec/grape/path_spec.rb +6 -4
- data/spec/grape/presenters/presenter_spec.rb +2 -0
- data/spec/grape/request_spec.rb +2 -0
- data/spec/grape/util/inheritable_setting_spec.rb +2 -0
- data/spec/grape/util/inheritable_values_spec.rb +2 -0
- data/spec/grape/util/reverse_stackable_values_spec.rb +2 -0
- data/spec/grape/util/stackable_values_spec.rb +3 -1
- data/spec/grape/util/strict_hash_configuration_spec.rb +2 -0
- data/spec/grape/validations/attributes_iterator_spec.rb +2 -0
- data/spec/grape/validations/instance_behaivour_spec.rb +5 -3
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +2 -0
- data/spec/grape/validations/params_scope_spec.rb +3 -1
- data/spec/grape/validations/single_attribute_iterator_spec.rb +18 -4
- data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
- data/spec/grape/validations/types/primitive_coercer_spec.rb +135 -0
- data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
- data/spec/grape/validations/types_spec.rb +9 -36
- data/spec/grape/validations/validators/all_or_none_spec.rb +2 -0
- data/spec/grape/validations/validators/allow_blank_spec.rb +2 -0
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +2 -0
- data/spec/grape/validations/validators/coerce_spec.rb +341 -136
- data/spec/grape/validations/validators/default_spec.rb +123 -0
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +14 -12
- data/spec/grape/validations/validators/except_values_spec.rb +3 -1
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +2 -0
- data/spec/grape/validations/validators/presence_spec.rb +30 -0
- data/spec/grape/validations/validators/regexp_spec.rb +2 -0
- data/spec/grape/validations/validators/same_as_spec.rb +2 -0
- data/spec/grape/validations/validators/values_spec.rb +30 -5
- data/spec/grape/validations_spec.rb +91 -33
- data/spec/integration/eager_load/eager_load_spec.rb +15 -0
- data/spec/integration/multi_json/json_spec.rb +2 -0
- data/spec/integration/multi_xml/xml_spec.rb +2 -0
- data/spec/shared/versioning_examples.rb +2 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/basic_auth_encode_helpers.rb +2 -0
- data/spec/support/content_type_helpers.rb +2 -0
- data/spec/support/eager_load.rb +19 -0
- data/spec/support/endpoint_faker.rb +2 -0
- data/spec/support/file_streamer.rb +2 -0
- data/spec/support/integer_helpers.rb +2 -0
- data/spec/support/versioned_helpers.rb +4 -2
- metadata +48 -28
- data/lib/grape/extensions/deep_hash_with_indifferent_access.rb +0 -18
- data/lib/grape/util/content_types.rb +0 -26
- 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::CoerceValidator do
|
@@ -10,11 +12,13 @@ describe Grape::Validations::CoerceValidator do
|
|
10
12
|
end
|
11
13
|
|
12
14
|
describe 'coerce' do
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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,26 +153,50 @@ describe Grape::Validations::CoerceValidator do
|
|
148
153
|
expect(last_response.body).to eq('array int works')
|
149
154
|
end
|
150
155
|
|
151
|
-
context '
|
152
|
-
|
153
|
-
|
154
|
-
|
156
|
+
context 'coerces' do
|
157
|
+
context 'json' do
|
158
|
+
let(:headers) { { 'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json' } }
|
159
|
+
|
160
|
+
it 'BigDecimal' do
|
161
|
+
subject.params do
|
162
|
+
requires :bigdecimal, type: BigDecimal
|
163
|
+
end
|
164
|
+
subject.post '/bigdecimal' do
|
165
|
+
"#{params[:bigdecimal].class} #{params[:bigdecimal].to_f}"
|
166
|
+
end
|
167
|
+
|
168
|
+
post '/bigdecimal', { bigdecimal: 45.1 }.to_json, headers
|
169
|
+
expect(last_response.status).to eq(201)
|
170
|
+
expect(last_response.body).to eq('BigDecimal 45.1')
|
155
171
|
end
|
156
|
-
|
157
|
-
|
172
|
+
|
173
|
+
it 'Boolean' do
|
174
|
+
subject.params do
|
175
|
+
requires :boolean, type: Boolean
|
176
|
+
end
|
177
|
+
subject.post '/boolean' do
|
178
|
+
params[:boolean]
|
179
|
+
end
|
180
|
+
|
181
|
+
post '/boolean', { boolean: 'true' }.to_json, headers
|
182
|
+
expect(last_response.status).to eq(201)
|
183
|
+
expect(last_response.body).to eq('true')
|
158
184
|
end
|
185
|
+
end
|
159
186
|
|
160
|
-
|
161
|
-
|
162
|
-
|
187
|
+
it 'BigDecimal' do
|
188
|
+
subject.params do
|
189
|
+
requires :bigdecimal, coerce: BigDecimal
|
190
|
+
end
|
191
|
+
subject.get '/bigdecimal' do
|
192
|
+
params[:bigdecimal].class
|
193
|
+
end
|
163
194
|
|
164
|
-
get '/
|
195
|
+
get '/bigdecimal', bigdecimal: '45'
|
165
196
|
expect(last_response.status).to eq(200)
|
166
|
-
expect(last_response.body).to eq('
|
197
|
+
expect(last_response.body).to eq('BigDecimal')
|
167
198
|
end
|
168
|
-
end
|
169
199
|
|
170
|
-
context 'coerces' do
|
171
200
|
it 'Integer' do
|
172
201
|
subject.params do
|
173
202
|
requires :int, coerce: Integer
|
@@ -181,6 +210,42 @@ describe Grape::Validations::CoerceValidator do
|
|
181
210
|
expect(last_response.body).to eq(integer_class_name)
|
182
211
|
end
|
183
212
|
|
213
|
+
it 'String' do
|
214
|
+
subject.params do
|
215
|
+
requires :string, coerce: String
|
216
|
+
end
|
217
|
+
subject.get '/string' do
|
218
|
+
params[:string].class
|
219
|
+
end
|
220
|
+
|
221
|
+
get '/string', string: 45
|
222
|
+
expect(last_response.status).to eq(200)
|
223
|
+
expect(last_response.body).to eq('String')
|
224
|
+
|
225
|
+
get '/string', string: nil
|
226
|
+
expect(last_response.status).to eq(200)
|
227
|
+
expect(last_response.body).to eq('NilClass')
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'is a custom type' do
|
231
|
+
subject.params do
|
232
|
+
requires :uri, coerce: SecureURIOnly
|
233
|
+
end
|
234
|
+
subject.get '/secure_uri' do
|
235
|
+
params[:uri].class
|
236
|
+
end
|
237
|
+
|
238
|
+
get 'secure_uri', uri: 'https://www.example.com'
|
239
|
+
|
240
|
+
expect(last_response.status).to eq(200)
|
241
|
+
expect(last_response.body).to eq('URI::HTTPS')
|
242
|
+
|
243
|
+
get 'secure_uri', uri: 'http://www.example.com'
|
244
|
+
|
245
|
+
expect(last_response.status).to eq(400)
|
246
|
+
expect(last_response.body).to eq('uri is invalid')
|
247
|
+
end
|
248
|
+
|
184
249
|
context 'Array' do
|
185
250
|
it 'Array of Integers' do
|
186
251
|
subject.params do
|
@@ -197,7 +262,7 @@ describe Grape::Validations::CoerceValidator do
|
|
197
262
|
|
198
263
|
it 'Array of Bools' do
|
199
264
|
subject.params do
|
200
|
-
requires :arry, coerce: Array[
|
265
|
+
requires :arry, coerce: Array[Grape::API::Boolean]
|
201
266
|
end
|
202
267
|
subject.get '/array' do
|
203
268
|
params[:arry][0].class
|
@@ -208,27 +273,6 @@ describe Grape::Validations::CoerceValidator do
|
|
208
273
|
expect(last_response.body).to eq('TrueClass')
|
209
274
|
end
|
210
275
|
|
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
276
|
it 'Array of type implementing parse' do
|
233
277
|
subject.params do
|
234
278
|
requires :uri, type: Array[URI]
|
@@ -253,17 +297,7 @@ describe Grape::Validations::CoerceValidator do
|
|
253
297
|
expect(last_response.body).to eq('Set,URI::HTTP,1')
|
254
298
|
end
|
255
299
|
|
256
|
-
it 'Array of
|
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
|
-
|
300
|
+
it 'Array of a custom type' do
|
267
301
|
subject.params do
|
268
302
|
requires :uri, type: Array[SecureURIOnly]
|
269
303
|
end
|
@@ -295,7 +329,7 @@ describe Grape::Validations::CoerceValidator do
|
|
295
329
|
|
296
330
|
it 'Set of Bools' do
|
297
331
|
subject.params do
|
298
|
-
requires :set, coerce: Set[
|
332
|
+
requires :set, coerce: Set[Grape::API::Boolean]
|
299
333
|
end
|
300
334
|
subject.get '/set' do
|
301
335
|
params[:set].first.class
|
@@ -307,119 +341,247 @@ describe Grape::Validations::CoerceValidator do
|
|
307
341
|
end
|
308
342
|
end
|
309
343
|
|
310
|
-
it '
|
344
|
+
it 'Boolean' do
|
311
345
|
subject.params do
|
312
|
-
requires :
|
346
|
+
requires :boolean, type: Boolean
|
313
347
|
end
|
314
|
-
subject.get '/
|
315
|
-
params[:
|
348
|
+
subject.get '/boolean' do
|
349
|
+
params[:boolean].class
|
316
350
|
end
|
317
351
|
|
318
|
-
get '/
|
352
|
+
get '/boolean', boolean: 1
|
319
353
|
expect(last_response.status).to eq(200)
|
320
354
|
expect(last_response.body).to eq('TrueClass')
|
355
|
+
end
|
321
356
|
|
322
|
-
|
323
|
-
|
324
|
-
|
357
|
+
context 'File' do
|
358
|
+
let(:file) { Rack::Test::UploadedFile.new(__FILE__) }
|
359
|
+
let(:filename) { File.basename(__FILE__).to_s }
|
325
360
|
|
326
|
-
|
327
|
-
|
328
|
-
|
361
|
+
it 'Rack::Multipart::UploadedFile' do
|
362
|
+
subject.params do
|
363
|
+
requires :file, type: Rack::Multipart::UploadedFile
|
364
|
+
end
|
365
|
+
subject.post '/upload' do
|
366
|
+
params[:file][:filename]
|
367
|
+
end
|
329
368
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
end
|
369
|
+
post '/upload', file: file
|
370
|
+
expect(last_response.status).to eq(201)
|
371
|
+
expect(last_response.body).to eq(filename)
|
334
372
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
end
|
339
|
-
subject.get '/boolean' do
|
340
|
-
params[:boolean].class
|
373
|
+
post '/upload', file: 'not a file'
|
374
|
+
expect(last_response.status).to eq(400)
|
375
|
+
expect(last_response.body).to eq('file is invalid')
|
341
376
|
end
|
342
377
|
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
378
|
+
it 'File' do
|
379
|
+
subject.params do
|
380
|
+
requires :file, coerce: File
|
381
|
+
end
|
382
|
+
subject.post '/upload' do
|
383
|
+
params[:file][:filename]
|
384
|
+
end
|
350
385
|
|
351
|
-
|
352
|
-
|
353
|
-
|
386
|
+
post '/upload', file: file
|
387
|
+
expect(last_response.status).to eq(201)
|
388
|
+
expect(last_response.body).to eq(filename)
|
354
389
|
|
355
|
-
|
356
|
-
|
357
|
-
|
390
|
+
post '/upload', file: 'not a file'
|
391
|
+
expect(last_response.status).to eq(400)
|
392
|
+
expect(last_response.body).to eq('file is invalid')
|
358
393
|
|
359
|
-
|
360
|
-
|
361
|
-
|
394
|
+
post '/upload', file: { filename: 'fake file', tempfile: '/etc/passwd' }
|
395
|
+
expect(last_response.status).to eq(400)
|
396
|
+
expect(last_response.body).to eq('file is invalid')
|
397
|
+
end
|
362
398
|
|
363
|
-
|
364
|
-
|
365
|
-
|
399
|
+
it 'collection' do
|
400
|
+
subject.params do
|
401
|
+
requires :files, type: Array[File]
|
402
|
+
end
|
403
|
+
subject.post '/upload' do
|
404
|
+
params[:files].first[:filename]
|
405
|
+
end
|
366
406
|
|
367
|
-
|
368
|
-
|
369
|
-
|
407
|
+
post '/upload', files: [file]
|
408
|
+
expect(last_response.status).to eq(201)
|
409
|
+
expect(last_response.body).to eq(filename)
|
410
|
+
end
|
370
411
|
end
|
371
412
|
|
372
|
-
it '
|
413
|
+
it 'Nests integers' do
|
373
414
|
subject.params do
|
374
|
-
requires :
|
415
|
+
requires :integers, type: Hash do
|
416
|
+
requires :int, coerce: Integer
|
417
|
+
end
|
375
418
|
end
|
376
|
-
subject.
|
377
|
-
params[:
|
419
|
+
subject.get '/int' do
|
420
|
+
params[:integers][:int].class
|
378
421
|
end
|
379
422
|
|
380
|
-
|
381
|
-
expect(last_response.status).to eq(
|
382
|
-
expect(last_response.body).to eq(
|
383
|
-
|
384
|
-
post '/upload', file: 'not a file'
|
385
|
-
expect(last_response.status).to eq(400)
|
386
|
-
expect(last_response.body).to eq('file is invalid')
|
423
|
+
get '/int', integers: { int: '45' }
|
424
|
+
expect(last_response.status).to eq(200)
|
425
|
+
expect(last_response.body).to eq(integer_class_name)
|
387
426
|
end
|
388
427
|
|
389
|
-
|
390
|
-
|
391
|
-
|
428
|
+
context 'nil values' do
|
429
|
+
context 'primitive types' do
|
430
|
+
Grape::Validations::Types::PRIMITIVES.each do |type|
|
431
|
+
it 'respects the nil value' do
|
432
|
+
subject.params do
|
433
|
+
requires :param, type: type
|
434
|
+
end
|
435
|
+
subject.get '/nil_value' do
|
436
|
+
params[:param].class
|
437
|
+
end
|
438
|
+
|
439
|
+
get '/nil_value', param: nil
|
440
|
+
expect(last_response.status).to eq(200)
|
441
|
+
expect(last_response.body).to eq('NilClass')
|
442
|
+
end
|
443
|
+
end
|
392
444
|
end
|
393
|
-
|
394
|
-
|
445
|
+
|
446
|
+
context 'structures types' do
|
447
|
+
Grape::Validations::Types::STRUCTURES.each do |type|
|
448
|
+
it 'respects the nil value' do
|
449
|
+
subject.params do
|
450
|
+
requires :param, type: type
|
451
|
+
end
|
452
|
+
subject.get '/nil_value' do
|
453
|
+
params[:param].class
|
454
|
+
end
|
455
|
+
|
456
|
+
get '/nil_value', param: nil
|
457
|
+
expect(last_response.status).to eq(200)
|
458
|
+
expect(last_response.body).to eq('NilClass')
|
459
|
+
end
|
460
|
+
end
|
395
461
|
end
|
396
462
|
|
397
|
-
|
398
|
-
|
399
|
-
|
463
|
+
context 'special types' do
|
464
|
+
Grape::Validations::Types::SPECIAL.each_key do |type|
|
465
|
+
it 'respects the nil value' do
|
466
|
+
subject.params do
|
467
|
+
requires :param, type: type
|
468
|
+
end
|
469
|
+
subject.get '/nil_value' do
|
470
|
+
params[:param].class
|
471
|
+
end
|
400
472
|
|
401
|
-
|
402
|
-
|
403
|
-
|
473
|
+
get '/nil_value', param: nil
|
474
|
+
expect(last_response.status).to eq(200)
|
475
|
+
expect(last_response.body).to eq('NilClass')
|
476
|
+
end
|
477
|
+
end
|
404
478
|
|
405
|
-
|
406
|
-
|
407
|
-
|
479
|
+
context 'variant-member-type collections' do
|
480
|
+
[
|
481
|
+
Array[Integer, String],
|
482
|
+
[Integer, String, Array[Integer, String]]
|
483
|
+
].each do |type|
|
484
|
+
it 'respects the nil value' do
|
485
|
+
subject.params do
|
486
|
+
requires :param, type: type
|
487
|
+
end
|
488
|
+
subject.get '/nil_value' do
|
489
|
+
params[:param].class
|
490
|
+
end
|
491
|
+
|
492
|
+
get '/nil_value', param: nil
|
493
|
+
expect(last_response.status).to eq(200)
|
494
|
+
expect(last_response.body).to eq('NilClass')
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|
408
499
|
end
|
409
500
|
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
501
|
+
context 'empty string' do
|
502
|
+
context 'primitive types' do
|
503
|
+
(Grape::Validations::Types::PRIMITIVES - [String]).each do |type|
|
504
|
+
it "is coerced to nil for type #{type}" do
|
505
|
+
subject.params do
|
506
|
+
requires :param, type: type
|
507
|
+
end
|
508
|
+
subject.get '/empty_string' do
|
509
|
+
params[:param].class
|
510
|
+
end
|
511
|
+
|
512
|
+
get '/empty_string', param: ''
|
513
|
+
expect(last_response.status).to eq(200)
|
514
|
+
expect(last_response.body).to eq('NilClass')
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
it 'is not coerced to nil for type String' do
|
519
|
+
subject.params do
|
520
|
+
requires :param, type: String
|
521
|
+
end
|
522
|
+
subject.get '/empty_string' do
|
523
|
+
params[:param].class
|
524
|
+
end
|
525
|
+
|
526
|
+
get '/empty_string', param: ''
|
527
|
+
expect(last_response.status).to eq(200)
|
528
|
+
expect(last_response.body).to eq('String')
|
414
529
|
end
|
415
530
|
end
|
416
|
-
|
417
|
-
|
531
|
+
|
532
|
+
context 'structures types' do
|
533
|
+
(Grape::Validations::Types::STRUCTURES - [Hash]).each do |type|
|
534
|
+
it "is coerced to nil for type #{type}" do
|
535
|
+
subject.params do
|
536
|
+
requires :param, type: type
|
537
|
+
end
|
538
|
+
subject.get '/empty_string' do
|
539
|
+
params[:param].class
|
540
|
+
end
|
541
|
+
|
542
|
+
get '/empty_string', param: ''
|
543
|
+
expect(last_response.status).to eq(200)
|
544
|
+
expect(last_response.body).to eq('NilClass')
|
545
|
+
end
|
546
|
+
end
|
418
547
|
end
|
419
548
|
|
420
|
-
|
421
|
-
|
422
|
-
|
549
|
+
context 'special types' do
|
550
|
+
(Grape::Validations::Types::SPECIAL.keys - [File, Rack::Multipart::UploadedFile]).each do |type|
|
551
|
+
it "is coerced to nil for type #{type}" do
|
552
|
+
subject.params do
|
553
|
+
requires :param, type: type
|
554
|
+
end
|
555
|
+
subject.get '/empty_string' do
|
556
|
+
params[:param].class
|
557
|
+
end
|
558
|
+
|
559
|
+
get '/empty_string', param: ''
|
560
|
+
expect(last_response.status).to eq(200)
|
561
|
+
expect(last_response.body).to eq('NilClass')
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
context 'variant-member-type collections' do
|
566
|
+
[
|
567
|
+
Array[Integer, String],
|
568
|
+
[Integer, String, Array[Integer, String]]
|
569
|
+
].each do |type|
|
570
|
+
it "is coerced to nil for type #{type}" do
|
571
|
+
subject.params do
|
572
|
+
requires :param, type: type
|
573
|
+
end
|
574
|
+
subject.get '/empty_string' do
|
575
|
+
params[:param].class
|
576
|
+
end
|
577
|
+
|
578
|
+
get '/empty_string', param: ''
|
579
|
+
expect(last_response.status).to eq(200)
|
580
|
+
expect(last_response.body).to eq('NilClass')
|
581
|
+
end
|
582
|
+
end
|
583
|
+
end
|
584
|
+
end
|
423
585
|
end
|
424
586
|
end
|
425
587
|
|
@@ -443,19 +605,19 @@ describe Grape::Validations::CoerceValidator do
|
|
443
605
|
|
444
606
|
it 'parses parameters with Array[String] type' do
|
445
607
|
subject.params do
|
446
|
-
requires :values, type: Array[String], coerce_with: ->(val) { val.split(/\s+/)
|
608
|
+
requires :values, type: Array[String], coerce_with: ->(val) { val.split(/\s+/) }
|
447
609
|
end
|
448
|
-
subject.get '/
|
610
|
+
subject.get '/strings' do
|
449
611
|
params[:values]
|
450
612
|
end
|
451
613
|
|
452
|
-
get '/
|
614
|
+
get '/strings', values: '1 2 3 4'
|
453
615
|
expect(last_response.status).to eq(200)
|
454
616
|
expect(JSON.parse(last_response.body)).to eq(%w[1 2 3 4])
|
455
617
|
|
456
|
-
get '/
|
618
|
+
get '/strings', values: 'a b c d'
|
457
619
|
expect(last_response.status).to eq(200)
|
458
|
-
expect(JSON.parse(last_response.body)).to eq(%w[
|
620
|
+
expect(JSON.parse(last_response.body)).to eq(%w[a b c d])
|
459
621
|
end
|
460
622
|
|
461
623
|
it 'parses parameters with Array[Integer] type' do
|
@@ -540,6 +702,46 @@ describe Grape::Validations::CoerceValidator do
|
|
540
702
|
expect(last_response.body).to eq('3')
|
541
703
|
end
|
542
704
|
|
705
|
+
context 'Integer type and coerce_with potentially returning nil' do
|
706
|
+
before do
|
707
|
+
subject.params do
|
708
|
+
requires :int, type: Integer, coerce_with: (lambda do |val|
|
709
|
+
if val == '0'
|
710
|
+
nil
|
711
|
+
elsif val.match?(/^-?\d+$/)
|
712
|
+
val.to_i
|
713
|
+
else
|
714
|
+
val
|
715
|
+
end
|
716
|
+
end)
|
717
|
+
end
|
718
|
+
subject.get '/' do
|
719
|
+
params[:int].class.to_s
|
720
|
+
end
|
721
|
+
end
|
722
|
+
|
723
|
+
it 'accepts value that coerces to nil' do
|
724
|
+
get '/', int: '0'
|
725
|
+
|
726
|
+
expect(last_response.status).to eq(200)
|
727
|
+
expect(last_response.body).to eq('NilClass')
|
728
|
+
end
|
729
|
+
|
730
|
+
it 'coerces to Integer' do
|
731
|
+
get '/', int: '1'
|
732
|
+
|
733
|
+
expect(last_response.status).to eq(200)
|
734
|
+
expect(last_response.body).to eq('Integer')
|
735
|
+
end
|
736
|
+
|
737
|
+
it 'returns invalid value if coercion returns a wrong type' do
|
738
|
+
get '/', int: 'lol'
|
739
|
+
|
740
|
+
expect(last_response.status).to eq(400)
|
741
|
+
expect(last_response.body).to eq('int is invalid')
|
742
|
+
end
|
743
|
+
end
|
744
|
+
|
543
745
|
it 'must be supplied with :type or :coerce' do
|
544
746
|
expect do
|
545
747
|
subject.params do
|
@@ -914,14 +1116,17 @@ describe Grape::Validations::CoerceValidator do
|
|
914
1116
|
end
|
915
1117
|
|
916
1118
|
context 'converter' do
|
917
|
-
it 'does not build
|
1119
|
+
it 'does not build a coercer multiple times' do
|
918
1120
|
subject.params do
|
919
1121
|
requires :something, type: Array[String]
|
920
1122
|
end
|
921
1123
|
subject.get do
|
922
1124
|
end
|
923
1125
|
|
924
|
-
expect(
|
1126
|
+
expect(Grape::Validations::Types::ArrayCoercer).to(
|
1127
|
+
receive(:new).at_most(:once).and_call_original
|
1128
|
+
)
|
1129
|
+
|
925
1130
|
10.times { get '/' }
|
926
1131
|
end
|
927
1132
|
end
|