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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +278 -44
- data/LICENSE +1 -1
- data/README.md +514 -69
- data/UPGRADING.md +424 -17
- data/grape.gemspec +13 -2
- data/lib/grape.rb +104 -71
- data/lib/grape/api.rb +138 -175
- data/lib/grape/api/helpers.rb +2 -0
- data/lib/grape/api/instance.rb +283 -0
- data/lib/grape/config.rb +34 -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 +22 -0
- data/lib/grape/dsl/configuration.rb +2 -0
- data/lib/grape/dsl/desc.rb +41 -7
- data/lib/grape/dsl/headers.rb +2 -0
- data/lib/grape/dsl/helpers.rb +5 -2
- data/lib/grape/dsl/inside_route.rb +92 -49
- data/lib/grape/dsl/logger.rb +2 -0
- data/lib/grape/dsl/middleware.rb +9 -0
- data/lib/grape/dsl/parameters.rb +25 -14
- data/lib/grape/dsl/request_response.rb +4 -2
- data/lib/grape/dsl/routing.rb +17 -10
- data/lib/grape/dsl/settings.rb +7 -1
- data/lib/grape/dsl/validations.rb +24 -4
- data/lib/grape/eager_load.rb +20 -0
- data/lib/grape/endpoint.rb +59 -35
- data/lib/grape/error_formatter.rb +4 -2
- 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 +20 -14
- data/lib/grape/exceptions/empty_message_body.rb +11 -0
- 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 +11 -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 +4 -2
- data/lib/grape/exceptions/validation_array_errors.rb +2 -0
- data/lib/grape/exceptions/validation_errors.rb +16 -13
- 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/locale/en.yml +3 -1
- data/lib/grape/middleware/auth/base.rb +7 -7
- 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 +10 -7
- data/lib/grape/middleware/error.rb +21 -16
- 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 +12 -0
- data/lib/grape/middleware/stack.rb +13 -3
- 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 +10 -8
- 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 +4 -2
- data/lib/grape/parser/json.rb +3 -1
- data/lib/grape/parser/xml.rb +3 -1
- data/lib/grape/path.rb +15 -3
- data/lib/grape/presenters/presenter.rb +2 -0
- data/lib/grape/request.rb +19 -10
- data/lib/grape/router.rb +30 -29
- data/lib/grape/router/attribute_translator.rb +41 -8
- data/lib/grape/router/pattern.rb +20 -16
- data/lib/grape/router/route.rb +14 -28
- 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 +43 -0
- data/lib/grape/util/cache.rb +20 -0
- data/lib/grape/util/endpoint_configuration.rb +8 -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 +7 -25
- data/lib/grape/util/json.rb +2 -0
- data/lib/grape/util/lazy_block.rb +27 -0
- data/lib/grape/util/lazy_object.rb +43 -0
- data/lib/grape/util/lazy_value.rb +98 -0
- data/lib/grape/util/registrable.rb +2 -0
- data/lib/grape/util/reverse_stackable_values.rb +10 -35
- data/lib/grape/util/stackable_values.rb +21 -34
- 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 +16 -6
- data/lib/grape/validations/multiple_attributes_iterator.rb +13 -0
- data/lib/grape/validations/params_scope.rb +51 -30
- data/lib/grape/validations/single_attribute_iterator.rb +24 -0
- data/lib/grape/validations/types.rb +13 -38
- 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 +29 -51
- 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/invalid_value.rb +24 -0
- 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 +8 -11
- data/lib/grape/validations/validators/all_or_none.rb +8 -13
- data/lib/grape/validations/validators/allow_blank.rb +3 -1
- data/lib/grape/validations/validators/as.rb +5 -4
- data/lib/grape/validations/validators/at_least_one_of.rb +7 -13
- data/lib/grape/validations/validators/base.rb +20 -16
- data/lib/grape/validations/validators/coerce.rb +46 -29
- data/lib/grape/validations/validators/default.rb +6 -6
- data/lib/grape/validations/validators/exactly_one_of.rb +10 -23
- data/lib/grape/validations/validators/except_values.rb +4 -2
- data/lib/grape/validations/validators/multiple_params_base.rb +17 -10
- data/lib/grape/validations/validators/mutual_exclusion.rb +8 -18
- 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 +26 -0
- data/lib/grape/validations/validators/values.rb +18 -6
- 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 +39 -0
- 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 +61 -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 +473 -0
- data/spec/grape/api_spec.rb +565 -12
- data/spec/grape/config_spec.rb +19 -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 +42 -16
- 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 +184 -33
- data/spec/grape/dsl/logger_spec.rb +2 -0
- data/spec/grape/dsl/middleware_spec.rb +10 -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 +12 -0
- data/spec/grape/dsl/settings_spec.rb +2 -0
- data/spec/grape/dsl/validations_spec.rb +2 -0
- data/spec/grape/endpoint/declared_spec.rb +601 -0
- data/spec/grape/endpoint_spec.rb +53 -523
- data/spec/grape/entity_spec.rb +9 -1
- data/spec/grape/exceptions/base_spec.rb +67 -0
- 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 +13 -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 +8 -4
- 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 +25 -7
- 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 +5 -3
- data/spec/grape/middleware/auth/strategies_spec.rb +3 -1
- data/spec/grape/middleware/base_spec.rb +10 -0
- data/spec/grape/middleware/error_spec.rb +3 -1
- data/spec/grape/middleware/exception_spec.rb +4 -2
- data/spec/grape/middleware/formatter_spec.rb +33 -16
- data/spec/grape/middleware/globals_spec.rb +2 -0
- data/spec/grape/middleware/stack_spec.rb +12 -0
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -1
- data/spec/grape/middleware/versioner/header_spec.rb +9 -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 +21 -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 +26 -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 +41 -0
- data/spec/grape/validations/params_scope_spec.rb +213 -9
- data/spec/grape/validations/single_attribute_iterator_spec.rb +58 -0
- 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 +140 -30
- data/spec/grape/validations/validators/allow_blank_spec.rb +2 -0
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +175 -29
- data/spec/grape/validations/validators/coerce_spec.rb +476 -135
- data/spec/grape/validations/validators/default_spec.rb +172 -0
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +204 -38
- data/spec/grape/validations/validators/except_values_spec.rb +4 -1
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +186 -27
- 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 +65 -0
- data/spec/grape/validations/validators/values_spec.rb +30 -5
- data/spec/grape/validations_spec.rb +388 -50
- 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 +22 -20
- data/spec/spec_helper.rb +12 -1
- data/spec/support/basic_auth_encode_helpers.rb +2 -0
- data/spec/support/chunks.rb +14 -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 +8 -8
- metadata +86 -48
- data/Appraisals +0 -32
- data/Dangerfile +0 -2
- data/Gemfile +0 -33
- data/Gemfile.lock +0 -231
- data/Guardfile +0 -10
- data/RELEASING.md +0 -111
- data/Rakefile +0 -25
- data/benchmark/simple.rb +0 -27
- data/benchmark/simple_with_type_coercer.rb +0 -22
- data/gemfiles/multi_json.gemfile +0 -35
- data/gemfiles/multi_xml.gemfile +0 -35
- data/gemfiles/rack_1.5.2.gemfile +0 -35
- data/gemfiles/rack_edge.gemfile +0 -35
- data/gemfiles/rails_3.gemfile +0 -36
- data/gemfiles/rails_4.gemfile +0 -35
- data/gemfiles/rails_5.gemfile +0 -35
- data/gemfiles/rails_edge.gemfile +0 -35
- 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
- data/pkg/grape-0.17.0.gem +0 -0
- data/pkg/grape-0.19.0.gem +0 -0
@@ -1,25 +1,29 @@
|
|
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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
+
class << self
|
11
|
+
def parse(input)
|
12
|
+
return if input.nil?
|
13
|
+
return InvalidValue.new unless parsed?(input)
|
14
|
+
|
15
|
+
# Processing of multipart file objects
|
16
|
+
# is already taken care of by Rack::Request.
|
17
|
+
# Nothing to do here.
|
18
|
+
input
|
19
|
+
end
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
def parsed?(value)
|
22
|
+
# Rack::Request creates a Hash with filename,
|
23
|
+
# content type and an IO object. Do a bit of basic
|
24
|
+
# duck-typing.
|
25
|
+
value.is_a?(::Hash) && value.key?(:tempfile) && value[:tempfile].is_a?(Tempfile)
|
26
|
+
end
|
23
27
|
end
|
24
28
|
end
|
25
29
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Validations
|
5
|
+
module Types
|
6
|
+
# Instances of this class may be used as tokens to denote that a parameter value could not be
|
7
|
+
# coerced. The given message will be used as a validation error.
|
8
|
+
class InvalidValue
|
9
|
+
attr_reader :message
|
10
|
+
|
11
|
+
def initialize(message = nil)
|
12
|
+
@message = message
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# only exists to make it shorter for external use
|
20
|
+
module Grape
|
21
|
+
module Types
|
22
|
+
InvalidValue = Class.new(Grape::Validations::Types::InvalidValue)
|
23
|
+
end
|
24
|
+
end
|
@@ -1,43 +1,48 @@
|
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
JSON.parse(input, symbolize_names: true)
|
22
|
-
end
|
14
|
+
class Json
|
15
|
+
class << self
|
16
|
+
# Coerce the input into a JSON-like data structure.
|
17
|
+
#
|
18
|
+
# @param input [String] a JSON-encoded parameter value
|
19
|
+
# @return [Hash,Array<Hash>,nil]
|
20
|
+
def parse(input)
|
21
|
+
return input if parsed?(input)
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
# @return [true,false]
|
29
|
-
def value_coerced?(value)
|
30
|
-
value.is_a?(::Hash) || coerced_collection?(value)
|
31
|
-
end
|
23
|
+
# Allow nulls and blank strings
|
24
|
+
return if input.nil? || input.match?(/^\s*$/)
|
25
|
+
JSON.parse(input, symbolize_names: true)
|
26
|
+
end
|
32
27
|
|
33
|
-
|
28
|
+
# Checks that the input was parsed successfully
|
29
|
+
# and isn't something odd such as an array of primitives.
|
30
|
+
#
|
31
|
+
# @param value [Object] result of {#parse}
|
32
|
+
# @return [true,false]
|
33
|
+
def parsed?(value)
|
34
|
+
value.is_a?(::Hash) || coerced_collection?(value)
|
35
|
+
end
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
protected
|
38
|
+
|
39
|
+
# Is the value an array of JSON-like objects?
|
40
|
+
#
|
41
|
+
# @param value [Object] result of {#parse}
|
42
|
+
# @return [true,false]
|
43
|
+
def coerced_collection?(value)
|
44
|
+
value.is_a?(::Array) && value.all? { |i| i.is_a? ::Hash }
|
45
|
+
end
|
41
46
|
end
|
42
47
|
end
|
43
48
|
|
@@ -46,18 +51,20 @@ module Grape
|
|
46
51
|
# objects and arrays of objects, but wraps single objects
|
47
52
|
# in an Array.
|
48
53
|
class JsonArray < Json
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
class << self
|
55
|
+
# See {Json#parse}. Wraps single objects in an array.
|
56
|
+
#
|
57
|
+
# @param input [String] JSON-encoded parameter value
|
58
|
+
# @return [Array<Hash>]
|
59
|
+
def parse(input)
|
60
|
+
json = super
|
61
|
+
Array.wrap(json) unless json.nil?
|
62
|
+
end
|
57
63
|
|
58
|
-
|
59
|
-
|
60
|
-
|
64
|
+
# See {Json#coerced_collection?}
|
65
|
+
def parsed?(value)
|
66
|
+
coerced_collection? value
|
67
|
+
end
|
61
68
|
end
|
62
69
|
end
|
63
70
|
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,67 @@
|
|
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. When +strict+ is true, it doesn't coerce a value but check
|
10
|
+
# that it has the proper type.
|
11
|
+
class PrimitiveCoercer < DryTypeCoercer
|
12
|
+
MAPPING = {
|
13
|
+
Grape::API::Boolean => DryTypes::Params::Bool,
|
14
|
+
BigDecimal => DryTypes::Params::Decimal,
|
15
|
+
|
16
|
+
# unfortunately, a +Params+ scope doesn't contain String
|
17
|
+
String => DryTypes::Coercible::String
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
STRICT_MAPPING = {
|
21
|
+
Grape::API::Boolean => DryTypes::Strict::Bool,
|
22
|
+
BigDecimal => DryTypes::Strict::Decimal
|
23
|
+
}.freeze
|
24
|
+
|
25
|
+
def initialize(type, strict = false)
|
26
|
+
super
|
27
|
+
|
28
|
+
@type = type
|
29
|
+
|
30
|
+
@coercer = if strict
|
31
|
+
STRICT_MAPPING.fetch(type) { scope.const_get(type.name) }
|
32
|
+
else
|
33
|
+
MAPPING.fetch(type) { scope.const_get(type.name) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def call(val)
|
38
|
+
return InvalidValue.new if reject?(val)
|
39
|
+
return nil if val.nil? || treat_as_nil?(val)
|
40
|
+
|
41
|
+
super
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
attr_reader :type
|
47
|
+
|
48
|
+
# This method maintains logic which was defined by Virtus. For example,
|
49
|
+
# dry-types is ok to convert an array or a hash to a string, it is supported,
|
50
|
+
# but Virtus wouldn't accept it. So, this method only exists to not introduce
|
51
|
+
# breaking changes.
|
52
|
+
def reject?(val)
|
53
|
+
(val.is_a?(Array) && type == String) ||
|
54
|
+
(val.is_a?(String) && type == Hash) ||
|
55
|
+
(val.is_a?(Hash) && type == String)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Dry-Types treats an empty string as invalid. However, Grape considers an empty string as
|
59
|
+
# absence of a value and coerces it into nil. See a discussion there
|
60
|
+
# https://github.com/ruby-grape/grape/pull/2045
|
61
|
+
def treat_as_nil?(val)
|
62
|
+
val == '' && type != String
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
require_relative 'array_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 < ArrayCoercer
|
12
|
+
register_collection Set
|
13
|
+
|
14
|
+
def initialize(type, strict = false)
|
15
|
+
super
|
16
|
+
|
17
|
+
@coercer = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(value)
|
21
|
+
return InvalidValue.new unless value.is_a?(Array)
|
22
|
+
|
23
|
+
coerce_elements(value)
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def coerce_elements(collection)
|
29
|
+
collection.each_with_object(Set.new) do |elem, memo|
|
30
|
+
coerced_elem = elem_coercer.call(elem)
|
31
|
+
|
32
|
+
return coerced_elem if coerced_elem.is_a?(InvalidValue)
|
33
|
+
|
34
|
+
memo.add(coerced_elem)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
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,8 +32,8 @@ 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
|
34
|
-
return
|
35
|
+
def call(value)
|
36
|
+
return unless value.is_a? Array
|
35
37
|
|
36
38
|
value =
|
37
39
|
if @method
|
@@ -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,17 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Grape
|
2
4
|
module Validations
|
3
5
|
class ValidatorFactory
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
@validator_class.new(@options[:attributes],
|
11
|
-
@options[:options],
|
12
|
-
@options[:required],
|
13
|
-
@options[:params_scope],
|
14
|
-
@options[:opts])
|
6
|
+
def self.create_validator(**options)
|
7
|
+
options[:validator_class].new(options[:attributes],
|
8
|
+
options[:options],
|
9
|
+
options[:required],
|
10
|
+
options[:params_scope],
|
11
|
+
**options[:opts])
|
15
12
|
end
|
16
13
|
end
|
17
14
|
end
|
@@ -1,19 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'grape/validations/validators/multiple_params_base'
|
4
|
+
|
1
5
|
module Grape
|
2
6
|
module Validations
|
3
|
-
require 'grape/validations/validators/multiple_params_base'
|
4
7
|
class AllOrNoneOfValidator < MultipleParamsBase
|
5
|
-
def
|
6
|
-
|
7
|
-
if
|
8
|
-
|
9
|
-
end
|
10
|
-
params
|
11
|
-
end
|
12
|
-
|
13
|
-
private
|
14
|
-
|
15
|
-
def only_subset_present
|
16
|
-
scoped_params.any? { |resource_params| !keys_in_common(resource_params).empty? && keys_in_common(resource_params).length < attrs.length }
|
8
|
+
def validate_params!(params)
|
9
|
+
keys = keys_in_common(params)
|
10
|
+
return if keys.empty? || keys.length == all_keys.length
|
11
|
+
raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:all_or_none))
|
17
12
|
end
|
18
13
|
end
|
19
14
|
end
|