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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/README.md +5 -3
- data/UPGRADING.md +43 -0
- data/grape.gemspec +10 -1
- data/lib/grape.rb +2 -2
- data/lib/grape/api.rb +2 -0
- data/lib/grape/api/helpers.rb +2 -0
- data/lib/grape/api/instance.rb +4 -2
- data/lib/grape/config.rb +2 -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 +3 -1
- data/lib/grape/dsl/inside_route.rb +7 -4
- data/lib/grape/dsl/logger.rb +2 -0
- data/lib/grape/dsl/middleware.rb +2 -0
- data/lib/grape/dsl/parameters.rb +4 -2
- data/lib/grape/dsl/request_response.rb +4 -2
- data/lib/grape/dsl/routing.rb +3 -1
- data/lib/grape/dsl/settings.rb +7 -1
- data/lib/grape/dsl/validations.rb +2 -0
- data/lib/grape/eager_load.rb +2 -0
- data/lib/grape/endpoint.rb +13 -7
- 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 -9
- 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 +2 -0
- 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 +23 -17
- 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 +4 -2
- data/lib/grape/middleware/error.rb +3 -1
- data/lib/grape/middleware/filter.rb +2 -0
- data/lib/grape/middleware/formatter.rb +5 -3
- data/lib/grape/middleware/globals.rb +2 -0
- data/lib/grape/middleware/helpers.rb +2 -0
- data/lib/grape/middleware/stack.rb +2 -0
- 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 +2 -0
- data/lib/grape/middleware/versioner/param.rb +3 -1
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -0
- data/lib/grape/middleware/versioner/path.rb +2 -0
- data/lib/grape/namespace.rb +2 -0
- 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 +2 -0
- data/lib/grape/presenters/presenter.rb +2 -0
- data/lib/grape/request.rb +3 -1
- data/lib/grape/router.rb +11 -6
- data/lib/grape/router/attribute_translator.rb +18 -8
- data/lib/grape/router/pattern.rb +6 -3
- data/lib/grape/router/route.rb +7 -2
- data/lib/grape/serve_file/file_body.rb +2 -0
- data/lib/grape/serve_file/file_response.rb +2 -0
- data/lib/grape/serve_file/sendfile_response.rb +2 -0
- data/lib/grape/util/base_inheritable.rb +2 -0
- data/lib/grape/util/content_types.rb +2 -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_value.rb +2 -0
- data/lib/grape/util/registrable.rb +2 -0
- data/lib/grape/util/reverse_stackable_values.rb +2 -0
- data/lib/grape/util/stackable_values.rb +3 -0
- 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 +23 -10
- data/lib/grape/validations/single_attribute_iterator.rb +13 -2
- data/lib/grape/validations/types.rb +7 -30
- data/lib/grape/validations/types/array_coercer.rb +56 -0
- data/lib/grape/validations/types/build_coercer.rb +49 -48
- 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 +41 -0
- data/lib/grape/validations/types/file.rb +10 -9
- data/lib/grape/validations/types/json.rb +11 -8
- data/lib/grape/validations/types/multiple_type_coercer.rb +14 -33
- data/lib/grape/validations/types/primitive_coercer.rb +58 -0
- data/lib/grape/validations/types/set_coercer.rb +38 -0
- data/lib/grape/validations/types/variant_collection_coercer.rb +4 -12
- 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 +43 -26
- data/lib/grape/validations/validators/default.rb +2 -0
- data/lib/grape/validations/validators/exactly_one_of.rb +3 -1
- 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 +3 -1
- 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 +54 -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 +27 -5
- 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 +2 -0
- 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 +3 -1
- 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 +2 -0
- 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 +2 -0
- 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 +2 -0
- 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 +17 -10
- data/spec/grape/middleware/globals_spec.rb +2 -0
- data/spec/grape/middleware/stack_spec.rb +2 -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 +2 -0
- 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 +4 -2
- 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_spec.rb +8 -35
- 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 +43 -66
- data/spec/grape/validations/validators/default_spec.rb +2 -0
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +2 -0
- 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 +29 -4
- data/spec/grape/validations_spec.rb +61 -3
- 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 +15 -0
- data/spec/support/basic_auth_encode_helpers.rb +2 -0
- data/spec/support/content_type_helpers.rb +2 -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 +119 -111
- data/lib/grape/extensions/deep_hash_with_indifferent_access.rb +0 -18
- data/lib/grape/validations/types/virtus_collection_patch.rb +0 -16
@@ -1,12 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Grape
|
2
4
|
module Validations
|
3
5
|
module Types
|
4
|
-
# Instances of this class may be passed to
|
5
|
-
# +Virtus::Attribute.build+ as the +:coercer+
|
6
|
-
# option, to handle collections of types that
|
7
|
-
# provide their own parsing (and optionally,
|
8
|
-
# type-checking) functionality.
|
9
|
-
#
|
10
6
|
# See {CustomTypeCoercer} for details on types
|
11
7
|
# that will be supported by this by this coercer.
|
12
8
|
# This coercer works in the same way as +CustomTypeCoercer+
|
@@ -38,32 +34,21 @@ module Grape
|
|
38
34
|
@set = set
|
39
35
|
end
|
40
36
|
|
41
|
-
#
|
42
|
-
# +Virtus::Attribute::coerce+ in order to coerce
|
43
|
-
# the given value.
|
37
|
+
# Coerces the given value.
|
44
38
|
#
|
45
39
|
# @param value [Array<String>] an array of values to be coerced
|
46
40
|
# @return [Array,Set] the coerced result. May be an +Array+ or a
|
47
41
|
# +Set+ depending on the setting given to the constructor
|
48
42
|
def call(value)
|
49
|
-
coerced = value.map
|
43
|
+
coerced = value.map do |item|
|
44
|
+
coerced_item = super(item)
|
50
45
|
|
51
|
-
|
52
|
-
end
|
46
|
+
return coerced_item if coerced_item.is_a?(InvalidValue)
|
53
47
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
#
|
59
|
-
# @param primitive [Axiom::Types::Type] primitive type for
|
60
|
-
# the coercion as deteced by axiom-types' inference system.
|
61
|
-
# @param value [Enumerable] a coerced result returned from {#call}
|
62
|
-
# @return [true,false] whether or not all of the coerced values in
|
63
|
-
# the collection satisfy type requirements.
|
64
|
-
def success?(primitive, value)
|
65
|
-
value.is_a?(@set ? Set : Array) &&
|
66
|
-
value.all? { |item| super(primitive, item) }
|
48
|
+
coerced_item
|
49
|
+
end
|
50
|
+
|
51
|
+
@set ? Set.new(coerced) : coerced
|
67
52
|
end
|
68
53
|
end
|
69
54
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry-types'
|
4
|
+
|
5
|
+
module DryTypes
|
6
|
+
# Call +Dry.Types()+ to add all registered types to +DryTypes+ which is
|
7
|
+
# a container in this case. Check documentation for more information
|
8
|
+
# https://dry-rb.org/gems/dry-types/1.2/getting-started/
|
9
|
+
include Dry.Types()
|
10
|
+
end
|
11
|
+
|
12
|
+
module Grape
|
13
|
+
module Validations
|
14
|
+
module Types
|
15
|
+
# A base class for classes which must identify a coercer to be used.
|
16
|
+
# If the +strict+ argument is true, it won't coerce the given value
|
17
|
+
# but check its type. More information there
|
18
|
+
# https://dry-rb.org/gems/dry-types/1.2/built-in-types/
|
19
|
+
class DryTypeCoercer
|
20
|
+
def initialize(type, strict = false)
|
21
|
+
@type = type
|
22
|
+
@scope = strict ? DryTypes::Strict : DryTypes::Params
|
23
|
+
end
|
24
|
+
|
25
|
+
# Coerces the given value to a type which was specified during
|
26
|
+
# initialization as a type argument.
|
27
|
+
#
|
28
|
+
# @param val [Object]
|
29
|
+
def call(val)
|
30
|
+
@coercer[val]
|
31
|
+
rescue Dry::Types::CoercionError => _e
|
32
|
+
InvalidValue.new
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
attr_reader :scope, :type
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,21 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Grape
|
2
4
|
module Validations
|
3
5
|
module Types
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def coerce(input)
|
6
|
+
# Implementation for parameters that are multipart file objects.
|
7
|
+
# Actual handling of these objects is provided by +Rack::Request+;
|
8
|
+
# this class is here only to assert that rack's handling has succeeded.
|
9
|
+
class File
|
10
|
+
def call(input)
|
11
|
+
return InvalidValue.new unless coerced?(input)
|
12
|
+
|
12
13
|
# Processing of multipart file objects
|
13
14
|
# is already taken care of by Rack::Request.
|
14
15
|
# Nothing to do here.
|
15
16
|
input
|
16
17
|
end
|
17
18
|
|
18
|
-
def
|
19
|
+
def coerced?(value)
|
19
20
|
# Rack::Request creates a Hash with filename,
|
20
21
|
# content type and an IO object. Do a bit of basic
|
21
22
|
# duck-typing.
|
@@ -1,21 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
|
3
5
|
module Grape
|
4
6
|
module Validations
|
5
7
|
module Types
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# given as JSON-encoded strings. It accepts both JSON objects
|
8
|
+
# Handles coercion and type checking for parameters that are complex
|
9
|
+
# types given as JSON-encoded strings. It accepts both JSON objects
|
9
10
|
# and arrays of objects, and will coerce the input to a +Hash+
|
10
11
|
# or +Array+ object respectively. In either case the Grape
|
11
12
|
# validation system will apply nested validation rules to
|
12
13
|
# all returned objects.
|
13
|
-
class Json
|
14
|
+
class Json
|
14
15
|
# Coerce the input into a JSON-like data structure.
|
15
16
|
#
|
16
17
|
# @param input [String] a JSON-encoded parameter value
|
17
18
|
# @return [Hash,Array<Hash>,nil]
|
18
|
-
def
|
19
|
+
def call(input)
|
20
|
+
return input if coerced?(input)
|
21
|
+
|
19
22
|
# Allow nulls and blank strings
|
20
23
|
return if input.nil? || input =~ /^\s*$/
|
21
24
|
JSON.parse(input, symbolize_names: true)
|
@@ -26,7 +29,7 @@ module Grape
|
|
26
29
|
#
|
27
30
|
# @param value [Object] result of {#coerce}
|
28
31
|
# @return [true,false]
|
29
|
-
def
|
32
|
+
def coerced?(value)
|
30
33
|
value.is_a?(::Hash) || coerced_collection?(value)
|
31
34
|
end
|
32
35
|
|
@@ -50,13 +53,13 @@ module Grape
|
|
50
53
|
#
|
51
54
|
# @param input [String] JSON-encoded parameter value
|
52
55
|
# @return [Array<Hash>]
|
53
|
-
def
|
56
|
+
def call(input)
|
54
57
|
json = super
|
55
58
|
Array.wrap(json) unless json.nil?
|
56
59
|
end
|
57
60
|
|
58
61
|
# See {Json#coerced_collection?}
|
59
|
-
def
|
62
|
+
def coerced?(value)
|
60
63
|
coerced_collection? value
|
61
64
|
end
|
62
65
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Grape
|
2
4
|
module Validations
|
3
5
|
module Types
|
@@ -22,53 +24,32 @@ module Grape
|
|
22
24
|
|
23
25
|
@type_coercers = types.map do |type|
|
24
26
|
if Types.multiple? type
|
25
|
-
VariantCollectionCoercer.new type
|
27
|
+
VariantCollectionCoercer.new type, @method
|
26
28
|
else
|
27
|
-
Types.build_coercer type
|
29
|
+
Types.build_coercer type, strict: !@method.nil?
|
28
30
|
end
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
32
|
-
#
|
33
|
-
# +Virtus::Attribute::coerce+ in order to coerce
|
34
|
-
# the given value.
|
34
|
+
# Coerces the given value.
|
35
35
|
#
|
36
|
-
# @param
|
36
|
+
# @param val [String] value to be coerced, in grape
|
37
37
|
# this should always be a string.
|
38
38
|
# @return [Object,InvalidValue] the coerced result, or an instance
|
39
39
|
# of {InvalidValue} if the value could not be coerced.
|
40
|
-
def call(
|
41
|
-
|
40
|
+
def call(val)
|
41
|
+
# once the value is coerced by the custom method, its type should be checked
|
42
|
+
val = @method.call(val) if @method
|
43
|
+
|
44
|
+
coerced_val = InvalidValue.new
|
42
45
|
|
43
46
|
@type_coercers.each do |coercer|
|
44
|
-
|
47
|
+
coerced_val = coercer.call(val)
|
45
48
|
|
46
|
-
return
|
49
|
+
return coerced_val unless coerced_val.is_a?(InvalidValue)
|
47
50
|
end
|
48
51
|
|
49
|
-
|
50
|
-
# that Grape won't ask us again if the value is valid
|
51
|
-
InvalidValue.new
|
52
|
-
end
|
53
|
-
|
54
|
-
# This method is called from somewhere within
|
55
|
-
# +Virtus::Attribute::value_coerced?+ in order to
|
56
|
-
# assert that the value has been coerced successfully.
|
57
|
-
# Due to Grape's design this will in fact only be called
|
58
|
-
# if a custom coercion method is being used, since {#call}
|
59
|
-
# returns an {InvalidValue} object if the value could not
|
60
|
-
# be coerced.
|
61
|
-
#
|
62
|
-
# @param _primitive [Axiom::Types::Type] primitive type
|
63
|
-
# for the coercion as detected by axiom-types' inference
|
64
|
-
# system. For custom types this is typically not much use
|
65
|
-
# (i.e. it is +Axiom::Types::Object+) unless special
|
66
|
-
# inference rules have been declared for the type.
|
67
|
-
# @param value [Object] a coerced result returned from {#call}
|
68
|
-
# @return [true,false] whether or not the coerced value
|
69
|
-
# satisfies type requirements.
|
70
|
-
def success?(_primitive, value)
|
71
|
-
@type_coercers.any? { |coercer| coercer.value_coerced? value }
|
52
|
+
coerced_val
|
72
53
|
end
|
73
54
|
end
|
74
55
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'dry_type_coercer'
|
4
|
+
|
5
|
+
module Grape
|
6
|
+
module Validations
|
7
|
+
module Types
|
8
|
+
# Coerces the given value to a type defined via a +type+ argument during
|
9
|
+
# initialization.
|
10
|
+
class PrimitiveCoercer < DryTypeCoercer
|
11
|
+
MAPPING = {
|
12
|
+
Grape::API::Boolean => DryTypes::Params::Bool,
|
13
|
+
|
14
|
+
# unfortunatelly, a +Params+ scope doesn't contain String
|
15
|
+
String => DryTypes::Coercible::String
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
STRICT_MAPPING = {
|
19
|
+
Grape::API::Boolean => DryTypes::Strict::Bool
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
def initialize(type, strict = false)
|
23
|
+
super
|
24
|
+
|
25
|
+
@type = type
|
26
|
+
|
27
|
+
@coercer = if strict
|
28
|
+
STRICT_MAPPING.fetch(type) { scope.const_get(type.name) }
|
29
|
+
else
|
30
|
+
MAPPING.fetch(type) { scope.const_get(type.name) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def call(val)
|
35
|
+
return InvalidValue.new if reject?(val)
|
36
|
+
return nil if val.nil?
|
37
|
+
return '' if val == ''
|
38
|
+
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
attr_reader :type
|
45
|
+
|
46
|
+
# This method maintaine logic which was defined by Virtus. For example,
|
47
|
+
# dry-types is ok to convert an array or a hash to a string, it is supported,
|
48
|
+
# but Virtus wouldn't accept it. So, this method only exists to not introduce
|
49
|
+
# breaking changes.
|
50
|
+
def reject?(val)
|
51
|
+
(val.is_a?(Array) && type == String) ||
|
52
|
+
(val.is_a?(String) && type == Hash) ||
|
53
|
+
(val.is_a?(Hash) && type == String)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
require_relative 'dry_type_coercer'
|
5
|
+
|
6
|
+
module Grape
|
7
|
+
module Validations
|
8
|
+
module Types
|
9
|
+
# Takes the given array and converts it to a set. Every element of the set
|
10
|
+
# is also coerced.
|
11
|
+
class SetCoercer < DryTypeCoercer
|
12
|
+
def initialize(type, strict = false)
|
13
|
+
super
|
14
|
+
|
15
|
+
@elem_coercer = PrimitiveCoercer.new(type.first, strict)
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(value)
|
19
|
+
return InvalidValue.new unless value.is_a?(Array)
|
20
|
+
|
21
|
+
coerce_elements(value)
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def coerce_elements(collection)
|
27
|
+
collection.each_with_object(Set.new) do |elem, memo|
|
28
|
+
coerced_elem = @elem_coercer.call(elem)
|
29
|
+
|
30
|
+
return coerced_elem if coerced_elem.is_a?(InvalidValue)
|
31
|
+
|
32
|
+
memo.add(coerced_elem)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Grape
|
2
4
|
module Validations
|
3
5
|
module Types
|
4
6
|
# This class wraps {MultipleTypeCoercer}, for use with collections
|
5
7
|
# that allow members of more than one type.
|
6
|
-
class VariantCollectionCoercer
|
8
|
+
class VariantCollectionCoercer
|
7
9
|
# Construct a new coercer that will attempt to coerce
|
8
10
|
# a list of values such that all members are of one of
|
9
11
|
# the given types. The container may also optionally be
|
@@ -30,7 +32,7 @@ module Grape
|
|
30
32
|
# @return [Array<Object>,Set<Object>,InvalidValue]
|
31
33
|
# the coerced result, or an instance
|
32
34
|
# of {InvalidValue} if the value could not be coerced.
|
33
|
-
def
|
35
|
+
def call(value)
|
34
36
|
return InvalidValue.new unless value.is_a? Array
|
35
37
|
|
36
38
|
value =
|
@@ -43,16 +45,6 @@ module Grape
|
|
43
45
|
|
44
46
|
value
|
45
47
|
end
|
46
|
-
|
47
|
-
# Assert that the value has been coerced successfully.
|
48
|
-
#
|
49
|
-
# @param value [Object] a coerced result returned from {#coerce}
|
50
|
-
# @return [true,false] whether or not the coerced value
|
51
|
-
# satisfies type requirements.
|
52
|
-
def value_coerced?(value)
|
53
|
-
value.is_a?(@types.class) &&
|
54
|
-
value.all? { |v| @member_coercer.success?(@types, v) }
|
55
|
-
end
|
56
48
|
end
|
57
49
|
end
|
58
50
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'grape/validations/validators/multiple_params_base'
|
2
4
|
|
3
5
|
module Grape
|
@@ -6,7 +8,7 @@ module Grape
|
|
6
8
|
def validate_params!(params)
|
7
9
|
keys = keys_in_common(params)
|
8
10
|
return if keys.empty? || keys.length == all_keys.length
|
9
|
-
raise Grape::Exceptions::Validation
|
11
|
+
raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:all_or_none))
|
10
12
|
end
|
11
13
|
end
|
12
14
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Grape
|
2
4
|
module Validations
|
3
5
|
class AllowBlankValidator < Base
|
@@ -9,7 +11,7 @@ module Grape
|
|
9
11
|
|
10
12
|
return if value == false || value.present?
|
11
13
|
|
12
|
-
raise Grape::Exceptions::Validation
|
14
|
+
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:blank))
|
13
15
|
end
|
14
16
|
end
|
15
17
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'grape/validations/validators/multiple_params_base'
|
2
4
|
|
3
5
|
module Grape
|
@@ -5,7 +7,7 @@ module Grape
|
|
5
7
|
class AtLeastOneOfValidator < MultipleParamsBase
|
6
8
|
def validate_params!(params)
|
7
9
|
return unless keys_in_common(params).empty?
|
8
|
-
raise Grape::Exceptions::Validation
|
10
|
+
raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:at_least_one))
|
9
11
|
end
|
10
12
|
end
|
11
13
|
end
|