dry-validation 0.12.0 → 1.6.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 +696 -239
- data/LICENSE +1 -1
- data/README.md +15 -12
- data/config/errors.yml +3 -88
- data/dry-validation.gemspec +31 -17
- data/lib/dry-validation.rb +3 -1
- data/lib/dry/validation.rb +45 -28
- data/lib/dry/validation/config.rb +24 -0
- data/lib/dry/validation/constants.rb +43 -0
- data/lib/dry/validation/contract.rb +171 -0
- data/lib/dry/validation/contract/class_interface.rb +230 -0
- data/lib/dry/validation/evaluator.rb +224 -0
- data/lib/dry/validation/extensions/hints.rb +67 -0
- data/lib/dry/validation/extensions/monads.rb +24 -8
- data/lib/dry/validation/extensions/predicates_as_macros.rb +75 -0
- data/lib/dry/validation/failures.rb +70 -0
- data/lib/dry/validation/function.rb +44 -0
- data/lib/dry/validation/macro.rb +38 -0
- data/lib/dry/validation/macros.rb +104 -0
- data/lib/dry/validation/message.rb +80 -80
- data/lib/dry/validation/message_set.rb +80 -105
- data/lib/dry/validation/messages/resolver.rb +131 -0
- data/lib/dry/validation/result.rb +183 -41
- data/lib/dry/validation/rule.rb +135 -0
- data/lib/dry/validation/schema_ext.rb +19 -0
- data/lib/dry/validation/values.rb +104 -0
- data/lib/dry/validation/version.rb +3 -1
- metadata +47 -336
- data/.codeclimate.yml +0 -17
- data/.gitignore +0 -9
- data/.rspec +0 -3
- data/.travis.yml +0 -26
- data/CONTRIBUTING.md +0 -31
- data/Gemfile +0 -33
- data/Rakefile +0 -22
- data/benchmarks/benchmark_form_invalid.rb +0 -64
- data/benchmarks/benchmark_form_valid.rb +0 -64
- data/benchmarks/benchmark_schema_invalid_huge.rb +0 -52
- data/benchmarks/profile_schema_call_invalid.rb +0 -20
- data/benchmarks/profile_schema_call_valid.rb +0 -20
- data/benchmarks/profile_schema_definition.rb +0 -14
- data/benchmarks/profile_schema_huge_invalid.rb +0 -30
- data/benchmarks/profile_schema_messages_invalid.rb +0 -20
- data/benchmarks/suite.rb +0 -5
- data/examples/basic.rb +0 -15
- data/examples/each.rb +0 -14
- data/examples/json.rb +0 -12
- data/examples/multiple.rb +0 -27
- data/examples/nested.rb +0 -22
- data/examples/params.rb +0 -11
- data/lib/dry/validation/compat/form.rb +0 -67
- data/lib/dry/validation/deprecations.rb +0 -24
- data/lib/dry/validation/executor.rb +0 -91
- data/lib/dry/validation/extensions.rb +0 -7
- data/lib/dry/validation/extensions/struct.rb +0 -32
- data/lib/dry/validation/input_processor_compiler.rb +0 -135
- data/lib/dry/validation/input_processor_compiler/json.rb +0 -45
- data/lib/dry/validation/input_processor_compiler/params.rb +0 -49
- data/lib/dry/validation/input_processor_compiler/sanitizer.rb +0 -47
- data/lib/dry/validation/message_compiler.rb +0 -192
- data/lib/dry/validation/message_compiler/visitor_opts.rb +0 -37
- data/lib/dry/validation/messages.rb +0 -14
- data/lib/dry/validation/messages/abstract.rb +0 -112
- data/lib/dry/validation/messages/i18n.rb +0 -35
- data/lib/dry/validation/messages/namespaced.rb +0 -32
- data/lib/dry/validation/messages/yaml.rb +0 -54
- data/lib/dry/validation/predicate_registry.rb +0 -115
- data/lib/dry/validation/schema.rb +0 -126
- data/lib/dry/validation/schema/check.rb +0 -37
- data/lib/dry/validation/schema/class_interface.rb +0 -189
- data/lib/dry/validation/schema/deprecated.rb +0 -30
- data/lib/dry/validation/schema/dsl.rb +0 -118
- data/lib/dry/validation/schema/form.rb +0 -9
- data/lib/dry/validation/schema/json.rb +0 -21
- data/lib/dry/validation/schema/key.rb +0 -71
- data/lib/dry/validation/schema/params.rb +0 -22
- data/lib/dry/validation/schema/rule.rb +0 -202
- data/lib/dry/validation/schema/value.rb +0 -211
- data/lib/dry/validation/schema_compiler.rb +0 -81
- data/lib/dry/validation/type_specs.rb +0 -70
- data/spec/extensions/monads/result_spec.rb +0 -40
- data/spec/extensions/struct/schema_spec.rb +0 -32
- data/spec/fixtures/locales/en.yml +0 -6
- data/spec/fixtures/locales/pl.yml +0 -18
- data/spec/integration/custom_error_messages_spec.rb +0 -48
- data/spec/integration/custom_predicates_spec.rb +0 -228
- data/spec/integration/hints_spec.rb +0 -170
- data/spec/integration/injecting_rules_spec.rb +0 -30
- data/spec/integration/json/defining_base_schema_spec.rb +0 -41
- data/spec/integration/localized_error_messages_spec.rb +0 -72
- data/spec/integration/message_compiler_spec.rb +0 -405
- data/spec/integration/messages/i18n_spec.rb +0 -94
- data/spec/integration/optional_keys_spec.rb +0 -28
- data/spec/integration/params/predicates/array_spec.rb +0 -287
- data/spec/integration/params/predicates/empty_spec.rb +0 -263
- data/spec/integration/params/predicates/eql_spec.rb +0 -327
- data/spec/integration/params/predicates/even_spec.rb +0 -455
- data/spec/integration/params/predicates/excluded_from_spec.rb +0 -455
- data/spec/integration/params/predicates/excludes_spec.rb +0 -391
- data/spec/integration/params/predicates/false_spec.rb +0 -455
- data/spec/integration/params/predicates/filled_spec.rb +0 -467
- data/spec/integration/params/predicates/format_spec.rb +0 -454
- data/spec/integration/params/predicates/gt_spec.rb +0 -519
- data/spec/integration/params/predicates/gteq_spec.rb +0 -519
- data/spec/integration/params/predicates/included_in_spec.rb +0 -455
- data/spec/integration/params/predicates/includes_spec.rb +0 -391
- data/spec/integration/params/predicates/key_spec.rb +0 -67
- data/spec/integration/params/predicates/lt_spec.rb +0 -519
- data/spec/integration/params/predicates/lteq_spec.rb +0 -519
- data/spec/integration/params/predicates/max_size_spec.rb +0 -391
- data/spec/integration/params/predicates/min_size_spec.rb +0 -391
- data/spec/integration/params/predicates/none_spec.rb +0 -265
- data/spec/integration/params/predicates/not_eql_spec.rb +0 -327
- data/spec/integration/params/predicates/odd_spec.rb +0 -455
- data/spec/integration/params/predicates/size/fixed_spec.rb +0 -393
- data/spec/integration/params/predicates/size/range_spec.rb +0 -396
- data/spec/integration/params/predicates/true_spec.rb +0 -455
- data/spec/integration/params/predicates/type_spec.rb +0 -391
- data/spec/integration/result_spec.rb +0 -81
- data/spec/integration/schema/array_schema_spec.rb +0 -59
- data/spec/integration/schema/check_rules_spec.rb +0 -119
- data/spec/integration/schema/check_with_nested_el_spec.rb +0 -37
- data/spec/integration/schema/check_with_nth_el_spec.rb +0 -25
- data/spec/integration/schema/default_settings_spec.rb +0 -11
- data/spec/integration/schema/defining_base_schema_spec.rb +0 -41
- data/spec/integration/schema/dynamic_predicate_args_spec.rb +0 -43
- data/spec/integration/schema/each_with_set_spec.rb +0 -70
- data/spec/integration/schema/extending_dsl_spec.rb +0 -27
- data/spec/integration/schema/form_spec.rb +0 -236
- data/spec/integration/schema/hash_schema_spec.rb +0 -47
- data/spec/integration/schema/inheriting_schema_spec.rb +0 -31
- data/spec/integration/schema/input_processor_spec.rb +0 -46
- data/spec/integration/schema/json/explicit_types_spec.rb +0 -157
- data/spec/integration/schema/json_spec.rb +0 -163
- data/spec/integration/schema/macros/confirmation_spec.rb +0 -35
- data/spec/integration/schema/macros/each_spec.rb +0 -268
- data/spec/integration/schema/macros/filled_spec.rb +0 -87
- data/spec/integration/schema/macros/input_spec.rb +0 -139
- data/spec/integration/schema/macros/maybe_spec.rb +0 -99
- data/spec/integration/schema/macros/rule_spec.rb +0 -75
- data/spec/integration/schema/macros/value_spec.rb +0 -119
- data/spec/integration/schema/macros/when_spec.rb +0 -62
- data/spec/integration/schema/nested_schemas_spec.rb +0 -236
- data/spec/integration/schema/nested_values_spec.rb +0 -46
- data/spec/integration/schema/not_spec.rb +0 -34
- data/spec/integration/schema/numbers_spec.rb +0 -19
- data/spec/integration/schema/option_with_default_spec.rb +0 -64
- data/spec/integration/schema/or_spec.rb +0 -87
- data/spec/integration/schema/params/defining_base_schema_spec.rb +0 -41
- data/spec/integration/schema/params/explicit_types_spec.rb +0 -195
- data/spec/integration/schema/params_spec.rb +0 -234
- data/spec/integration/schema/predicate_verification_spec.rb +0 -9
- data/spec/integration/schema/predicates/array_spec.rb +0 -295
- data/spec/integration/schema/predicates/custom_spec.rb +0 -103
- data/spec/integration/schema/predicates/empty_spec.rb +0 -263
- data/spec/integration/schema/predicates/eql_spec.rb +0 -327
- data/spec/integration/schema/predicates/even_spec.rb +0 -455
- data/spec/integration/schema/predicates/excluded_from/array_spec.rb +0 -459
- data/spec/integration/schema/predicates/excluded_from/range_spec.rb +0 -459
- data/spec/integration/schema/predicates/excludes_spec.rb +0 -391
- data/spec/integration/schema/predicates/filled_spec.rb +0 -467
- data/spec/integration/schema/predicates/format_spec.rb +0 -455
- data/spec/integration/schema/predicates/gt_spec.rb +0 -519
- data/spec/integration/schema/predicates/gteq_spec.rb +0 -519
- data/spec/integration/schema/predicates/hash_spec.rb +0 -69
- data/spec/integration/schema/predicates/included_in/array_spec.rb +0 -459
- data/spec/integration/schema/predicates/included_in/range_spec.rb +0 -459
- data/spec/integration/schema/predicates/includes_spec.rb +0 -391
- data/spec/integration/schema/predicates/key_spec.rb +0 -88
- data/spec/integration/schema/predicates/lt_spec.rb +0 -520
- data/spec/integration/schema/predicates/lteq_spec.rb +0 -519
- data/spec/integration/schema/predicates/max_size_spec.rb +0 -391
- data/spec/integration/schema/predicates/min_size_spec.rb +0 -391
- data/spec/integration/schema/predicates/none_spec.rb +0 -265
- data/spec/integration/schema/predicates/not_eql_spec.rb +0 -391
- data/spec/integration/schema/predicates/odd_spec.rb +0 -455
- data/spec/integration/schema/predicates/size/fixed_spec.rb +0 -398
- data/spec/integration/schema/predicates/size/range_spec.rb +0 -395
- data/spec/integration/schema/predicates/type_spec.rb +0 -413
- data/spec/integration/schema/reusing_schema_spec.rb +0 -33
- data/spec/integration/schema/using_types_spec.rb +0 -135
- data/spec/integration/schema/validate_spec.rb +0 -120
- data/spec/integration/schema/xor_spec.rb +0 -35
- data/spec/integration/schema_builders_spec.rb +0 -17
- data/spec/integration/schema_spec.rb +0 -173
- data/spec/shared/message_compiler.rb +0 -11
- data/spec/shared/predicate_helper.rb +0 -15
- data/spec/shared/rule_compiler.rb +0 -8
- data/spec/spec_helper.rb +0 -58
- data/spec/support/define_struct.rb +0 -25
- data/spec/support/matchers.rb +0 -38
- data/spec/support/mutant.rb +0 -9
- data/spec/support/predicates_integration.rb +0 -7
- data/spec/unit/input_processor_compiler/json_spec.rb +0 -283
- data/spec/unit/input_processor_compiler/params_spec.rb +0 -328
- data/spec/unit/message_compiler/visit_failure_spec.rb +0 -38
- data/spec/unit/message_compiler/visit_spec.rb +0 -16
- data/spec/unit/message_compiler_spec.rb +0 -7
- data/spec/unit/predicate_registry_spec.rb +0 -34
- data/spec/unit/schema/key_spec.rb +0 -38
- data/spec/unit/schema/rule_spec.rb +0 -42
- data/spec/unit/schema/value_spec.rb +0 -131
- data/spec/unit/schema_spec.rb +0 -35
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,25 +1,28 @@
|
|
1
1
|
[gem]: https://rubygems.org/gems/dry-validation
|
2
|
-
[
|
3
|
-
[
|
4
|
-
[
|
2
|
+
[actions]: https://github.com/dry-rb/dry-validation/actions
|
3
|
+
[codacy]: https://www.codacy.com/gh/dry-rb/dry-validation
|
4
|
+
[chat]: https://dry-rb.zulipchat.com
|
5
5
|
[inchpages]: http://inch-ci.org/github/dry-rb/dry-validation
|
6
6
|
|
7
|
-
# dry-validation [][chat]
|
8
8
|
|
9
9
|
[][gem]
|
10
|
-
[][actions]
|
11
|
+
[][codacy]
|
12
|
+
[][codacy]
|
13
13
|
[][inchpages]
|
14
14
|
|
15
|
-
##
|
15
|
+
## Links
|
16
16
|
|
17
|
-
|
17
|
+
* [User documentation](http://dry-rb.org/gems/dry-validation)
|
18
|
+
* [API documentation](http://rubydoc.info/gems/dry-validation)
|
18
19
|
|
19
|
-
##
|
20
|
+
## Supported Ruby versions
|
21
|
+
|
22
|
+
This library officially supports the following Ruby versions:
|
20
23
|
|
21
|
-
*
|
22
|
-
*
|
24
|
+
* MRI >= `2.5`
|
25
|
+
* jruby >= `9.2`
|
23
26
|
|
24
27
|
## License
|
25
28
|
|
data/config/errors.yml
CHANGED
@@ -1,89 +1,4 @@
|
|
1
1
|
en:
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
empty?: "must be empty"
|
7
|
-
|
8
|
-
excludes?: "must not include %{value}"
|
9
|
-
|
10
|
-
excluded_from?:
|
11
|
-
arg:
|
12
|
-
default: "must not be one of: %{list}"
|
13
|
-
range: "must not be one of: %{list_left} - %{list_right}"
|
14
|
-
exclusion?: "must not be one of: %{list}"
|
15
|
-
|
16
|
-
eql?: "must be equal to %{left}"
|
17
|
-
|
18
|
-
not_eql?: "must not be equal to %{left}"
|
19
|
-
|
20
|
-
filled?: "must be filled"
|
21
|
-
|
22
|
-
format?: "is in invalid format"
|
23
|
-
|
24
|
-
number?: "must be a number"
|
25
|
-
|
26
|
-
odd?: "must be odd"
|
27
|
-
|
28
|
-
even?: "must be even"
|
29
|
-
|
30
|
-
gt?: "must be greater than %{num}"
|
31
|
-
|
32
|
-
gteq?: "must be greater than or equal to %{num}"
|
33
|
-
|
34
|
-
hash?: "must be a hash"
|
35
|
-
|
36
|
-
included_in?:
|
37
|
-
arg:
|
38
|
-
default: "must be one of: %{list}"
|
39
|
-
range: "must be one of: %{list_left} - %{list_right}"
|
40
|
-
inclusion?: "must be one of: %{list}"
|
41
|
-
|
42
|
-
includes?: "must include %{value}"
|
43
|
-
|
44
|
-
bool?: "must be boolean"
|
45
|
-
|
46
|
-
true?: "must be true"
|
47
|
-
|
48
|
-
false?: "must be false"
|
49
|
-
|
50
|
-
int?: "must be an integer"
|
51
|
-
|
52
|
-
float?: "must be a float"
|
53
|
-
|
54
|
-
decimal?: "must be a decimal"
|
55
|
-
|
56
|
-
date?: "must be a date"
|
57
|
-
|
58
|
-
date_time?: "must be a date time"
|
59
|
-
|
60
|
-
time?: "must be a time"
|
61
|
-
|
62
|
-
key?: "is missing"
|
63
|
-
|
64
|
-
attr?: "is missing"
|
65
|
-
|
66
|
-
lt?: "must be less than %{num}"
|
67
|
-
|
68
|
-
lteq?: "must be less than or equal to %{num}"
|
69
|
-
|
70
|
-
max_size?: "size cannot be greater than %{num}"
|
71
|
-
|
72
|
-
min_size?: "size cannot be less than %{num}"
|
73
|
-
|
74
|
-
none?: "cannot be defined"
|
75
|
-
|
76
|
-
str?: "must be a string"
|
77
|
-
|
78
|
-
type?: "must be %{type}"
|
79
|
-
|
80
|
-
size?:
|
81
|
-
arg:
|
82
|
-
default: "size must be %{size}"
|
83
|
-
range: "size must be within %{size_left} - %{size_right}"
|
84
|
-
|
85
|
-
value:
|
86
|
-
string:
|
87
|
-
arg:
|
88
|
-
default: "length must be %{size}"
|
89
|
-
range: "length must be within %{size_left} - %{size_right}"
|
2
|
+
dry_validation:
|
3
|
+
errors:
|
4
|
+
acceptance: "must accept %{key}"
|
data/dry-validation.gemspec
CHANGED
@@ -1,27 +1,41 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# this file is managed by dry-rb/devtools project
|
3
|
+
|
4
|
+
lib = File.expand_path('lib', __dir__)
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
+
require 'dry/validation/version'
|
2
7
|
|
3
8
|
Gem::Specification.new do |spec|
|
4
9
|
spec.name = 'dry-validation'
|
5
|
-
spec.
|
6
|
-
spec.
|
7
|
-
spec.email = ['andyholland1991@aol.com', 'piotr.solnica@gmail.com']
|
8
|
-
spec.summary = 'A simple validation library'
|
9
|
-
spec.homepage = 'https://github.com/dry-rb/dry-validation'
|
10
|
+
spec.authors = ["Piotr Solnica"]
|
11
|
+
spec.email = ["piotr.solnica@gmail.com"]
|
10
12
|
spec.license = 'MIT'
|
13
|
+
spec.version = Dry::Validation::VERSION.dup
|
11
14
|
|
12
|
-
spec.
|
15
|
+
spec.summary = "Validation library"
|
16
|
+
spec.description = spec.summary
|
17
|
+
spec.homepage = 'https://dry-rb.org/gems/dry-validation'
|
18
|
+
spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-validation.gemspec", "lib/**/*", "config/*.yml"]
|
19
|
+
spec.bindir = 'bin'
|
13
20
|
spec.executables = []
|
14
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
15
21
|
spec.require_paths = ['lib']
|
16
22
|
|
17
|
-
spec.
|
18
|
-
spec.
|
19
|
-
spec.
|
20
|
-
spec.
|
21
|
-
|
22
|
-
spec.
|
23
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
24
|
+
spec.metadata['changelog_uri'] = 'https://github.com/dry-rb/dry-validation/blob/master/CHANGELOG.md'
|
25
|
+
spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-validation'
|
26
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-validation/issues'
|
27
|
+
|
28
|
+
spec.required_ruby_version = ">= 2.5.0"
|
29
|
+
|
30
|
+
# to update dependencies edit project.yml
|
31
|
+
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
32
|
+
spec.add_runtime_dependency "dry-container", "~> 0.7", ">= 0.7.1"
|
33
|
+
spec.add_runtime_dependency "dry-core", "~> 0.4"
|
34
|
+
spec.add_runtime_dependency "dry-equalizer", "~> 0.2"
|
35
|
+
spec.add_runtime_dependency "dry-initializer", "~> 3.0"
|
36
|
+
spec.add_runtime_dependency "dry-schema", "~> 1.5", ">= 1.5.2"
|
23
37
|
|
24
|
-
spec.add_development_dependency
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
38
|
+
spec.add_development_dependency "bundler"
|
39
|
+
spec.add_development_dependency "rake"
|
40
|
+
spec.add_development_dependency "rspec"
|
27
41
|
end
|
data/lib/dry-validation.rb
CHANGED
data/lib/dry/validation.rb
CHANGED
@@ -1,43 +1,60 @@
|
|
1
|
-
|
2
|
-
require 'dry/core/constants'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
3
|
+
require "dry/validation/constants"
|
4
|
+
require "dry/validation/contract"
|
5
|
+
require "dry/validation/macros"
|
6
|
+
|
7
|
+
# Main namespace
|
8
|
+
#
|
9
|
+
# @api public
|
4
10
|
module Dry
|
11
|
+
# Main library namespace
|
12
|
+
#
|
13
|
+
# @api public
|
5
14
|
module Validation
|
6
15
|
extend Dry::Core::Extensions
|
7
|
-
|
8
|
-
|
9
|
-
MissingMessageError = Class.new(StandardError)
|
10
|
-
InvalidSchemaError = Class.new(StandardError)
|
16
|
+
extend Macros::Registrar
|
11
17
|
|
12
|
-
|
13
|
-
|
18
|
+
register_extension(:monads) do
|
19
|
+
require "dry/validation/extensions/monads"
|
14
20
|
end
|
15
21
|
|
16
|
-
|
17
|
-
|
18
|
-
|
22
|
+
register_extension(:hints) do
|
23
|
+
require "dry/validation/extensions/hints"
|
24
|
+
end
|
19
25
|
|
20
|
-
|
21
|
-
|
22
|
-
else
|
23
|
-
klass.new
|
24
|
-
end
|
26
|
+
register_extension(:predicates_as_macros) do
|
27
|
+
require "dry/validation/extensions/predicates_as_macros"
|
25
28
|
end
|
26
29
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
+
# Define a contract and build its instance
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# my_contract = Dry::Validation.Contract do
|
34
|
+
# params do
|
35
|
+
# required(:name).filled(:string)
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# my_contract.call(name: "Jane")
|
40
|
+
#
|
41
|
+
# @param [Hash] options Contract options
|
42
|
+
#
|
43
|
+
# @see Contract
|
44
|
+
#
|
45
|
+
# @return [Contract]
|
46
|
+
#
|
47
|
+
# @api public
|
48
|
+
#
|
49
|
+
def self.Contract(options = EMPTY_HASH, &block)
|
50
|
+
Contract.build(options, &block)
|
30
51
|
end
|
31
52
|
|
32
|
-
|
33
|
-
|
34
|
-
|
53
|
+
# This is needed by Macros::Registrar
|
54
|
+
#
|
55
|
+
# @api private
|
56
|
+
def self.macros
|
57
|
+
Macros
|
35
58
|
end
|
36
59
|
end
|
37
60
|
end
|
38
|
-
|
39
|
-
require 'dry/validation/schema'
|
40
|
-
require 'dry/validation/schema/params'
|
41
|
-
require 'dry/validation/schema/json'
|
42
|
-
require 'dry/validation/extensions'
|
43
|
-
require 'dry/validation/version'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/schema/config"
|
4
|
+
require "dry/validation/macros"
|
5
|
+
|
6
|
+
module Dry
|
7
|
+
module Validation
|
8
|
+
# Configuration for contracts
|
9
|
+
#
|
10
|
+
# @see Contract#config
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
class Config < Schema::Config
|
14
|
+
setting :macros, Macros::Container.new, &:dup
|
15
|
+
|
16
|
+
# @api private
|
17
|
+
def dup
|
18
|
+
config = super
|
19
|
+
config.macros = macros.dup
|
20
|
+
config
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pathname"
|
4
|
+
require "dry/core/constants"
|
5
|
+
|
6
|
+
module Dry
|
7
|
+
module Validation
|
8
|
+
include Dry::Core::Constants
|
9
|
+
|
10
|
+
DOT = "."
|
11
|
+
|
12
|
+
# Root path is used for base errors in hash representation of error messages
|
13
|
+
ROOT_PATH = [nil].freeze
|
14
|
+
|
15
|
+
# Path to the default errors locale file
|
16
|
+
DEFAULT_ERRORS_NAMESPACE = "dry_validation"
|
17
|
+
|
18
|
+
# Path to the default errors locale file
|
19
|
+
DEFAULT_ERRORS_PATH = Pathname(__FILE__).join("../../../../config/errors.yml").realpath.freeze
|
20
|
+
|
21
|
+
# Mapping for block kwarg options used by block_options
|
22
|
+
#
|
23
|
+
# @see Rule#block_options
|
24
|
+
BLOCK_OPTIONS_MAPPINGS = Hash.new { |_, key| key }.update(context: :_context).freeze
|
25
|
+
|
26
|
+
# Error raised when `rule` specifies one or more keys that the schema doesn't specify
|
27
|
+
InvalidKeysError = Class.new(StandardError)
|
28
|
+
|
29
|
+
# Error raised when a localized message was not found
|
30
|
+
MissingMessageError = Class.new(StandardError)
|
31
|
+
|
32
|
+
# Error raised when trying to define a schema in a contract class that already has a schema
|
33
|
+
DuplicateSchemaError = Class.new(StandardError)
|
34
|
+
|
35
|
+
# Error raised during initialization of a contract that has no schema defined
|
36
|
+
SchemaMissingError = Class.new(StandardError) do
|
37
|
+
# @api private
|
38
|
+
def initialize(klass)
|
39
|
+
super("#{klass} cannot be instantiated without a schema defined")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "concurrent/map"
|
4
|
+
|
5
|
+
require "dry/equalizer"
|
6
|
+
require "dry/initializer"
|
7
|
+
require "dry/schema/path"
|
8
|
+
|
9
|
+
require "dry/validation/config"
|
10
|
+
require "dry/validation/constants"
|
11
|
+
require "dry/validation/rule"
|
12
|
+
require "dry/validation/evaluator"
|
13
|
+
require "dry/validation/messages/resolver"
|
14
|
+
require "dry/validation/result"
|
15
|
+
require "dry/validation/contract/class_interface"
|
16
|
+
|
17
|
+
module Dry
|
18
|
+
module Validation
|
19
|
+
# Contract objects apply rules to input
|
20
|
+
#
|
21
|
+
# A contract consists of a schema and rules. The schema is applied to the
|
22
|
+
# input before rules are applied, this way you can be sure that your rules
|
23
|
+
# won't be applied to values that didn't pass schema checks.
|
24
|
+
#
|
25
|
+
# It's up to you how exactly you're going to separate schema checks from
|
26
|
+
# your rules.
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# class NewUserContract < Dry::Validation::Contract
|
30
|
+
# params do
|
31
|
+
# required(:email).filled(:string)
|
32
|
+
# required(:age).filled(:integer)
|
33
|
+
# optional(:login).maybe(:string, :filled?)
|
34
|
+
# optional(:password).maybe(:string, min_size?: 10)
|
35
|
+
# optional(:password_confirmation).maybe(:string)
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# rule(:password) do
|
39
|
+
# key.failure('is required') if values[:login] && !values[:password]
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# rule(:age) do
|
43
|
+
# key.failure('must be greater or equal 18') if values[:age] < 18
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# new_user_contract = NewUserContract.new
|
48
|
+
# new_user_contract.call(email: 'jane@doe.org', age: 21)
|
49
|
+
#
|
50
|
+
# @api public
|
51
|
+
class Contract
|
52
|
+
include Dry::Equalizer(:schema, :rules, :messages, inspect: false)
|
53
|
+
|
54
|
+
extend Dry::Initializer
|
55
|
+
extend ClassInterface
|
56
|
+
|
57
|
+
config.messages.top_namespace = DEFAULT_ERRORS_NAMESPACE
|
58
|
+
config.messages.load_paths << DEFAULT_ERRORS_PATH
|
59
|
+
|
60
|
+
# @!attribute [r] config
|
61
|
+
# @return [Config] Contract's configuration object
|
62
|
+
# @api public
|
63
|
+
option :config, default: -> { self.class.config }
|
64
|
+
|
65
|
+
# @!attribute [r] macros
|
66
|
+
# @return [Macros::Container] Configured macros
|
67
|
+
# @see Macros::Container#register
|
68
|
+
# @api public
|
69
|
+
option :macros, default: -> { config.macros }
|
70
|
+
|
71
|
+
# @!attribute [r] default_context
|
72
|
+
# @return [Hash] Default context for rules
|
73
|
+
# @api public
|
74
|
+
option :default_context, default: -> { EMPTY_HASH }
|
75
|
+
|
76
|
+
# @!attribute [r] schema
|
77
|
+
# @return [Dry::Schema::Params, Dry::Schema::JSON, Dry::Schema::Processor]
|
78
|
+
# @api private
|
79
|
+
option :schema, default: -> { self.class.__schema__ || raise(SchemaMissingError, self.class) }
|
80
|
+
|
81
|
+
# @!attribute [r] rules
|
82
|
+
# @return [Hash]
|
83
|
+
# @api private
|
84
|
+
option :rules, default: -> { self.class.rules }
|
85
|
+
|
86
|
+
# @!attribute [r] message_resolver
|
87
|
+
# @return [Messages::Resolver]
|
88
|
+
# @api private
|
89
|
+
option :message_resolver, default: -> { Messages::Resolver.new(messages) }
|
90
|
+
|
91
|
+
# Apply the contract to an input
|
92
|
+
#
|
93
|
+
# @param [Hash] input The input to validate
|
94
|
+
# @param [Hash] context Initial context for rules
|
95
|
+
#
|
96
|
+
# @return [Result]
|
97
|
+
#
|
98
|
+
# @api public
|
99
|
+
def call(input, context = EMPTY_HASH)
|
100
|
+
context_map = Concurrent::Map.new.tap do |map|
|
101
|
+
default_context.each { |key, value| map[key] = value }
|
102
|
+
context.each { |key, value| map[key] = value }
|
103
|
+
end
|
104
|
+
|
105
|
+
Result.new(schema.(input), context_map) do |result|
|
106
|
+
rules.each do |rule|
|
107
|
+
next if rule.keys.any? { |key| error?(result, key) }
|
108
|
+
|
109
|
+
rule_result = rule.(self, result)
|
110
|
+
|
111
|
+
rule_result.failures.each do |failure|
|
112
|
+
result.add_error(message_resolver.(**failure))
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Return a nice string representation
|
119
|
+
#
|
120
|
+
# @return [String]
|
121
|
+
#
|
122
|
+
# @api public
|
123
|
+
def inspect
|
124
|
+
%(#<#{self.class} schema=#{schema.inspect} rules=#{rules.inspect}>)
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
# @api private
|
130
|
+
def error?(result, spec)
|
131
|
+
path = Schema::Path[spec]
|
132
|
+
|
133
|
+
if path.multi_value?
|
134
|
+
return path.expand.any? { |nested_path| error?(result, nested_path) }
|
135
|
+
end
|
136
|
+
|
137
|
+
return true if result.schema_error?(path)
|
138
|
+
|
139
|
+
path
|
140
|
+
.to_a[0..-2]
|
141
|
+
.any? { |key|
|
142
|
+
curr_path = Schema::Path[path.keys[0..path.keys.index(key)]]
|
143
|
+
|
144
|
+
return false unless result.schema_error?(curr_path)
|
145
|
+
|
146
|
+
result.errors.any? { |err|
|
147
|
+
(other = Schema::Path[err.path]).same_root?(curr_path) && other == curr_path
|
148
|
+
}
|
149
|
+
}
|
150
|
+
end
|
151
|
+
|
152
|
+
# Get a registered macro
|
153
|
+
#
|
154
|
+
# @return [Proc,#to_proc]
|
155
|
+
#
|
156
|
+
# @api private
|
157
|
+
def macro(name, *args)
|
158
|
+
(macros.key?(name) ? macros[name] : Macros[name]).with(args)
|
159
|
+
end
|
160
|
+
|
161
|
+
# Return configured messages backend
|
162
|
+
#
|
163
|
+
# @return [Dry::Schema::Messages::YAML, Dry::Schema::Messages::I18n]
|
164
|
+
#
|
165
|
+
# @api private
|
166
|
+
def messages
|
167
|
+
self.class.messages
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|