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