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
@@ -1,59 +0,0 @@
|
|
1
|
-
RSpec.describe Dry::Validation::Schema, 'for an array' do
|
2
|
-
context 'without type specs' do
|
3
|
-
subject(:schema) do
|
4
|
-
Dry::Validation.Schema do
|
5
|
-
each do
|
6
|
-
schema do
|
7
|
-
required(:prefix).filled
|
8
|
-
required(:value).filled
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'applies its rules to array input' do
|
15
|
-
result = schema.([{ prefix: 1, value: 123 }, { prefix: 2, value: 456 }])
|
16
|
-
|
17
|
-
expect(result).to be_success
|
18
|
-
|
19
|
-
result = schema.([{ prefix: 1, value: nil }, { prefix: nil, value: 456 }])
|
20
|
-
|
21
|
-
expect(result.messages).to eql(
|
22
|
-
0 => { value: ["must be filled"] },
|
23
|
-
1 => { prefix: ["must be filled"] }
|
24
|
-
)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
context 'with type specs' do
|
29
|
-
subject(:schema) do
|
30
|
-
Dry::Validation.Params do
|
31
|
-
configure { config.type_specs = true }
|
32
|
-
|
33
|
-
each do
|
34
|
-
schema do
|
35
|
-
required(:prefix, :integer).filled
|
36
|
-
required(:value, :integer).filled
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'applies its rules to coerced array input' do
|
43
|
-
result = schema.([{ prefix: 1, value: '123' }, { prefix: 2, value: 456 }])
|
44
|
-
|
45
|
-
expect(result).to be_success
|
46
|
-
|
47
|
-
expect(result.output).to eql(
|
48
|
-
[{ prefix: 1, value: 123 }, { prefix: 2, value: 456 }]
|
49
|
-
)
|
50
|
-
|
51
|
-
result = schema.([{ prefix: 1, value: nil }, { prefix: nil, value: 456 }])
|
52
|
-
|
53
|
-
expect(result.messages).to eql(
|
54
|
-
0 => { value: ["must be filled"] },
|
55
|
-
1 => { prefix: ["must be filled"] }
|
56
|
-
)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,119 +0,0 @@
|
|
1
|
-
RSpec.describe Schema, 'using high-level rules' do
|
2
|
-
context 'composing rules' do
|
3
|
-
subject(:schema) do
|
4
|
-
Dry::Validation.Schema do
|
5
|
-
configure do
|
6
|
-
def self.messages
|
7
|
-
Messages.default.merge(
|
8
|
-
en: { errors: { destiny: 'you must select either red or blue' } }
|
9
|
-
)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
optional(:red).maybe
|
14
|
-
optional(:blue).maybe
|
15
|
-
|
16
|
-
rule(destiny: [:red, :blue]) do |red, blue|
|
17
|
-
red.filled? | blue.filled?
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'passes when only red is filled' do
|
23
|
-
expect(schema.(red: '1')).to be_success
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'fails when keys are missing' do
|
27
|
-
expect(schema.({})).to be_failure
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'fails when red and blue are not filled ' do
|
31
|
-
expect(schema.(red: nil, blue: nil).messages).to eql(
|
32
|
-
destiny: ['you must select either red or blue']
|
33
|
-
)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
context 'composing specific predicates' do
|
38
|
-
let(:schema) do
|
39
|
-
Dry::Validation.Schema do
|
40
|
-
configure do
|
41
|
-
def self.messages
|
42
|
-
Messages.default.merge(
|
43
|
-
en: {
|
44
|
-
errors: {
|
45
|
-
email_presence: 'must be present when login is set to true',
|
46
|
-
email_absence: 'must not be present when login is set to false'
|
47
|
-
}
|
48
|
-
}
|
49
|
-
)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
required(:login).filled(:bool?)
|
54
|
-
required(:email).maybe
|
55
|
-
|
56
|
-
rule(:email_presence) { value(:login).true?.then(value(:email).filled?) }
|
57
|
-
|
58
|
-
rule(:email_absence) { value(:login).false?.then(value(:email).none?) }
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'passes when login is false and email is nil' do
|
63
|
-
expect(schema.(login: false, email: nil)).to be_success
|
64
|
-
end
|
65
|
-
|
66
|
-
it 'fails when login is false and email is present' do
|
67
|
-
expect(schema.(login: false, email: 'jane@doe').messages).to eql(
|
68
|
-
email_absence: ['must not be present when login is set to false']
|
69
|
-
)
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'passes when login is true and email is present' do
|
73
|
-
expect(schema.(login: true, email: 'jane@doe')).to be_success
|
74
|
-
end
|
75
|
-
|
76
|
-
it 'fails when login is true and email is not present' do
|
77
|
-
expect(schema.(login: true, email: nil).messages).to eql(
|
78
|
-
email_presence: ['must be present when login is set to true']
|
79
|
-
)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
describe 'with nested schemas' do
|
84
|
-
subject(:schema) do
|
85
|
-
Dry::Validation.Schema do
|
86
|
-
required(:command).filled(:str?, included_in?: %w(First Second))
|
87
|
-
|
88
|
-
required(:args).filled(:hash?)
|
89
|
-
|
90
|
-
rule(first_args: [:command, :args]) do |command, args|
|
91
|
-
command.eql?('First')
|
92
|
-
.then(args.schema { required(:first).filled(:bool?) })
|
93
|
-
end
|
94
|
-
|
95
|
-
rule(second_args: [:command, :args]) do |command, args|
|
96
|
-
command.eql?('Second')
|
97
|
-
.then(args.schema { required(:second).filled(:bool?) })
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'generates check rule matching on value' do
|
103
|
-
expect(schema.(command: 'First', args: { first: true })).to be_success
|
104
|
-
expect(schema.(command: 'Second', args: { second: true })).to be_success
|
105
|
-
|
106
|
-
expect(schema.(command: 'oops', args: { such: 'validation' }).messages).to eql(
|
107
|
-
command: ['must be one of: First, Second']
|
108
|
-
)
|
109
|
-
|
110
|
-
expect(schema.(command: 'First', args: { second: true }).messages).to eql(
|
111
|
-
args: { first: ['is missing'] }
|
112
|
-
)
|
113
|
-
|
114
|
-
expect(schema.(command: 'Second', args: { first: true }).messages).to eql(
|
115
|
-
args: { second: ['is missing'] }
|
116
|
-
)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
RSpec.describe 'Check depending on a nested value from a hash' do
|
2
|
-
subject(:schema) do
|
3
|
-
Dry::Validation.Schema do
|
4
|
-
required(:tag).schema do
|
5
|
-
required(:color).schema do
|
6
|
-
required(:value).filled(:str?)
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
rule(tag: [[:tag, :color, :value]]) do |value|
|
11
|
-
value.eql?('red')
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'passes when check passes' do
|
17
|
-
expect(schema.(tag: { color: { value: 'red' }})).to be_success
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'skips check when parent of the dependency failed' do
|
21
|
-
expect(schema.(tag: { color: :oops }).messages).to eql(
|
22
|
-
tag: { color: ['must be a hash'] }
|
23
|
-
)
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'skips check when dependency failed' do
|
27
|
-
expect(schema.(tag: { color: { value: :oops }}).messages).to eql(
|
28
|
-
tag: { color: { value: ['must be a string'] } }
|
29
|
-
)
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'fails when check fails' do
|
33
|
-
expect(schema.(tag: { color: { value: 'blue' }}).messages).to eql(
|
34
|
-
tag: { color: { value: ['must be equal to red'] } }
|
35
|
-
)
|
36
|
-
end
|
37
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
RSpec.describe 'Check depending on nth element in an array' do
|
2
|
-
subject(:schema) do
|
3
|
-
Dry::Validation.Schema do
|
4
|
-
required(:tags).each(:str?)
|
5
|
-
|
6
|
-
rule(tags: [[:tags, 0]]) do |value|
|
7
|
-
value.eql?('red')
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'skips check when dependency failed' do
|
13
|
-
expect(schema.(tags: 'oops')).to be_failure
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'passes when check passes' do
|
17
|
-
expect(schema.(tags: %w(red green blue))).to be_success
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'fails when check fails' do
|
21
|
-
expect(schema.(tags: %w(blue green red)).messages).to eql(
|
22
|
-
tags: { 0 => ["must be equal to red"] }
|
23
|
-
)
|
24
|
-
end
|
25
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
RSpec.describe Dry::Validation::Schema, 'default settings' do
|
2
|
-
subject(:schema) do
|
3
|
-
Dry::Validation.Schema(build: false) do
|
4
|
-
required(:name).filled
|
5
|
-
end
|
6
|
-
end
|
7
|
-
|
8
|
-
it 'uses :yaml messages by default' do
|
9
|
-
expect(schema.config.messages).to be(:yaml)
|
10
|
-
end
|
11
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
require 'dry/validation/messages/i18n'
|
2
|
-
require 'i18n'
|
3
|
-
|
4
|
-
RSpec.describe 'Defining base schema class' do
|
5
|
-
subject(:schema) do
|
6
|
-
Dry::Validation.Schema(BaseSchema) do
|
7
|
-
required(:email).filled(:email?)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
before do
|
12
|
-
class BaseSchema < Dry::Validation::Schema
|
13
|
-
configure do |config|
|
14
|
-
config.messages_file = SPEC_ROOT.join('fixtures/locales/en.yml')
|
15
|
-
config.messages = :i18n
|
16
|
-
end
|
17
|
-
|
18
|
-
def email?(value)
|
19
|
-
true
|
20
|
-
end
|
21
|
-
|
22
|
-
define! do
|
23
|
-
required(:name).filled
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
after do
|
29
|
-
Object.send(:remove_const, :BaseSchema)
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'inherits predicates' do
|
33
|
-
expect(schema).to respond_to(:email?)
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'inherits rules' do
|
37
|
-
expect(schema.(name: nil).messages).to eql(
|
38
|
-
name: ['must be filled'], email: ['is missing', 'must be an email']
|
39
|
-
)
|
40
|
-
end
|
41
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
RSpec.describe Dry::Validation::Schema, 'dynamic predicate args' do
|
2
|
-
context 'with base rules' do
|
3
|
-
subject(:schema) do
|
4
|
-
Dry::Validation.Schema do
|
5
|
-
configure do
|
6
|
-
def data
|
7
|
-
%w(a b c)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
required(:letter).filled(included_in?: data)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'evaluates predicate arguments' do
|
16
|
-
expect(schema.(letter: 'a')).to be_success
|
17
|
-
expect(schema.(letter: 'f')).to be_failure
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
context 'with high-level rules' do
|
22
|
-
subject(:schema) do
|
23
|
-
Dry::Validation.Schema do
|
24
|
-
configure do
|
25
|
-
def data
|
26
|
-
%w(a b c)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
required(:letter).filled(:str?)
|
31
|
-
|
32
|
-
rule(valid_letter: [:letter]) do |letter|
|
33
|
-
letter.included_in?(data)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'evaluates predicate arguments' do
|
39
|
-
expect(schema.(letter: 'a')).to be_success
|
40
|
-
expect(schema.(letter: 'f')).to be_failure
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
RSpec.describe 'Schema with each and set rules' do
|
2
|
-
subject(:schema) do
|
3
|
-
Dry::Validation.Schema do
|
4
|
-
required(:payments).each do
|
5
|
-
required(:method).filled(:str?)
|
6
|
-
required(:amount).filled(:float?)
|
7
|
-
end
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
describe '#messages' do
|
12
|
-
it 'validates using all rules' do
|
13
|
-
expect(schema.(payments: [{}]).messages).to eql(
|
14
|
-
{ payments: {
|
15
|
-
0 => { method: ['is missing'], amount: ['is missing'] }
|
16
|
-
}}
|
17
|
-
)
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'validates each payment against its set of rules' do
|
21
|
-
input = {
|
22
|
-
payments: [
|
23
|
-
{ method: 'cc', amount: 1.23 },
|
24
|
-
{ method: 'wire', amount: 4.56 }
|
25
|
-
]
|
26
|
-
}
|
27
|
-
|
28
|
-
expect(schema.(input).messages).to eql({})
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'validates presence of the method key for each payment' do
|
32
|
-
input = {
|
33
|
-
payments: [
|
34
|
-
{ method: 'cc', amount: 1.23 },
|
35
|
-
{ amount: 4.56 }
|
36
|
-
]
|
37
|
-
}
|
38
|
-
|
39
|
-
expect(schema.(input).messages).to eql(
|
40
|
-
payments: { 1 => { method: ['is missing'] } }
|
41
|
-
)
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'validates type of the method value for each payment' do
|
45
|
-
input = {
|
46
|
-
payments: [
|
47
|
-
{ method: 'cc', amount: 1.23 },
|
48
|
-
{ method: 12, amount: 4.56 }
|
49
|
-
]
|
50
|
-
}
|
51
|
-
|
52
|
-
expect(schema.(input).messages).to eql(
|
53
|
-
payments: { 1 => { method: ['must be a string'] } }
|
54
|
-
)
|
55
|
-
end
|
56
|
-
|
57
|
-
it 'validates type of the amount value for each payment' do
|
58
|
-
input = {
|
59
|
-
payments: [
|
60
|
-
{ method: 'cc', amount: 1.23 },
|
61
|
-
{ method: 'wire', amount: '4.56' }
|
62
|
-
]
|
63
|
-
}
|
64
|
-
|
65
|
-
expect(schema.(input).messages).to eql(
|
66
|
-
payments: { 1 => { amount: ['must be a float'] } }
|
67
|
-
)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
RSpec.describe 'Extending DSL' do
|
2
|
-
it 'allows configuring custom DSL methods' do
|
3
|
-
dsl_ext = Module.new do
|
4
|
-
def maybe_int(name, *predicates, &block)
|
5
|
-
required(name, [:nil, :integer]).maybe(:int?, *predicates, &block)
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
Dry::Validation::Schema.configure do |config|
|
10
|
-
config.dsl_extensions = dsl_ext
|
11
|
-
end
|
12
|
-
|
13
|
-
schema = Dry::Validation.Schema do
|
14
|
-
configure do
|
15
|
-
config.input_processor = :params
|
16
|
-
config.type_specs = true
|
17
|
-
end
|
18
|
-
|
19
|
-
maybe_int(:age)
|
20
|
-
end
|
21
|
-
|
22
|
-
expect(schema.(age: nil)).to be_success
|
23
|
-
expect(schema.(age: 1)).to be_success
|
24
|
-
expect(schema.(age: '1')).to be_success
|
25
|
-
expect(schema.(age: 'foo').messages).to eql(age: ['must be an integer'])
|
26
|
-
end
|
27
|
-
end
|
@@ -1,236 +0,0 @@
|
|
1
|
-
RSpec.describe 'Dry::Validation::Schema::Form', 'defining a schema' do
|
2
|
-
before(:all) { require 'dry/validation/compat/form' }
|
3
|
-
|
4
|
-
subject(:schema) do
|
5
|
-
Dry::Validation.Form do
|
6
|
-
configure do
|
7
|
-
def email?(value)
|
8
|
-
true
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
required(:email).filled
|
13
|
-
|
14
|
-
required(:age).maybe(:int?, gt?: 18)
|
15
|
-
|
16
|
-
required(:address).schema do
|
17
|
-
required(:city).filled
|
18
|
-
required(:street).filled
|
19
|
-
|
20
|
-
required(:loc).schema do
|
21
|
-
required(:lat).filled(:float?)
|
22
|
-
required(:lng).filled(:float?)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
optional(:password).maybe.confirmation
|
27
|
-
|
28
|
-
optional(:phone_number).maybe(:int?, gt?: 0)
|
29
|
-
|
30
|
-
rule(:email_valid) { value(:email).email? }
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
describe '#messages' do
|
35
|
-
it 'returns compiled error messages' do
|
36
|
-
result = schema.('email' => '', 'age' => '19')
|
37
|
-
|
38
|
-
expect(result.messages).to eql(
|
39
|
-
email: ['must be filled'],
|
40
|
-
address: ['is missing']
|
41
|
-
)
|
42
|
-
|
43
|
-
expect(result.output).to eql(email: '', age: 19)
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'returns hints for nested data' do
|
47
|
-
result = schema.(
|
48
|
-
'email' => 'jane@doe.org',
|
49
|
-
'age' => '19',
|
50
|
-
'address' => {
|
51
|
-
'city' => '',
|
52
|
-
'street' => 'Street 1/2',
|
53
|
-
'loc' => { 'lat' => '123.456', 'lng' => '' }
|
54
|
-
}
|
55
|
-
)
|
56
|
-
|
57
|
-
expect(result.messages).to eql(
|
58
|
-
address: {
|
59
|
-
loc: { lng: ['must be filled'] },
|
60
|
-
city: ['must be filled']
|
61
|
-
}
|
62
|
-
)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
describe '#call' do
|
67
|
-
it 'passes when attributes are valid' do
|
68
|
-
result = schema.(
|
69
|
-
'email' => 'jane@doe.org',
|
70
|
-
'age' => '19',
|
71
|
-
'address' => {
|
72
|
-
'city' => 'NYC',
|
73
|
-
'street' => 'Street 1/2',
|
74
|
-
'loc' => { 'lat' => '123.456', 'lng' => '456.123' }
|
75
|
-
}
|
76
|
-
)
|
77
|
-
|
78
|
-
expect(result).to be_success
|
79
|
-
|
80
|
-
expect(result.output).to eql(
|
81
|
-
email: 'jane@doe.org', age: 19,
|
82
|
-
address: {
|
83
|
-
city: 'NYC', street: 'Street 1/2',
|
84
|
-
loc: { lat: 123.456, lng: 456.123 }
|
85
|
-
}
|
86
|
-
)
|
87
|
-
end
|
88
|
-
|
89
|
-
it 'validates presence of an email and min age value' do
|
90
|
-
result = schema.('email' => '', 'age' => '18')
|
91
|
-
|
92
|
-
expect(result.messages).to eql(
|
93
|
-
address: ['is missing'],
|
94
|
-
age: ['must be greater than 18'],
|
95
|
-
email: ['must be filled']
|
96
|
-
)
|
97
|
-
end
|
98
|
-
|
99
|
-
it 'handles optionals' do
|
100
|
-
result = schema.(
|
101
|
-
'email' => 'jane@doe.org',
|
102
|
-
'age' => '19',
|
103
|
-
'phone_number' => '12',
|
104
|
-
'address' => {
|
105
|
-
'city' => 'NYC',
|
106
|
-
'street' => 'Street 1/2',
|
107
|
-
'loc' => { 'lat' => '123.456', 'lng' => '456.123' }
|
108
|
-
}
|
109
|
-
)
|
110
|
-
|
111
|
-
expect(result).to be_success
|
112
|
-
|
113
|
-
expect(result.output).to eql(
|
114
|
-
email: 'jane@doe.org', age: 19, phone_number: 12,
|
115
|
-
address: {
|
116
|
-
city: 'NYC', street: 'Street 1/2',
|
117
|
-
loc: { lat: 123.456, lng: 456.123 }
|
118
|
-
}
|
119
|
-
)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
describe 'with an each and nested schema' do
|
124
|
-
subject(:schema) do
|
125
|
-
Dry::Validation.Form do
|
126
|
-
required(:items).each do
|
127
|
-
schema do
|
128
|
-
required(:title).filled(:str?)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
it 'passes when each element passes schema check' do
|
135
|
-
expect(schema.(items: [{ title: 'Foo' }])).to be_success
|
136
|
-
end
|
137
|
-
|
138
|
-
it 'fails when one or more elements did not pass schema check' do
|
139
|
-
expect(schema.(items: [{ title: 'Foo' }, { title: :Foo }]).messages).to eql(
|
140
|
-
items: { 1 => { title: ['must be a string'] } }
|
141
|
-
)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
describe 'symbolizing keys when coercion fails' do
|
146
|
-
subject(:schema) do
|
147
|
-
Dry::Validation.Form do
|
148
|
-
required(:email).value(size?: 8..60)
|
149
|
-
required(:birthdate).value(:date?)
|
150
|
-
required(:age).value(:int?, gt?: 23)
|
151
|
-
required(:tags).maybe(max_size?: 3)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
let(:tags) { %(al b c) }
|
156
|
-
|
157
|
-
it 'symbolizes keys and coerces values' do
|
158
|
-
result = schema.(
|
159
|
-
'email' => 'jane@doe.org',
|
160
|
-
'birthdate' => '2001-02-03',
|
161
|
-
'age' => '24',
|
162
|
-
'tags' => tags
|
163
|
-
).to_h
|
164
|
-
|
165
|
-
expect(result.to_h).to eql(
|
166
|
-
email: 'jane@doe.org',
|
167
|
-
birthdate: Date.new(2001, 2, 3),
|
168
|
-
age: 24,
|
169
|
-
tags: tags
|
170
|
-
)
|
171
|
-
end
|
172
|
-
|
173
|
-
it 'symbolizes keys even when coercion fails' do
|
174
|
-
result = schema.(
|
175
|
-
'email' => 'jane@doe.org',
|
176
|
-
'birthdate' => '2001-sutin-03',
|
177
|
-
'age' => ['oops'],
|
178
|
-
'tags' => nil
|
179
|
-
)
|
180
|
-
|
181
|
-
expect(result.to_h).to eql(
|
182
|
-
email: 'jane@doe.org',
|
183
|
-
birthdate: '2001-sutin-03',
|
184
|
-
age: ['oops'],
|
185
|
-
tags: nil
|
186
|
-
)
|
187
|
-
|
188
|
-
expect(result.messages).to eql(
|
189
|
-
birthdate: ['must be a date'],
|
190
|
-
age: ['must be an integer', 'must be greater than 23']
|
191
|
-
)
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
describe 'with nested schema in a high-level rule' do
|
196
|
-
subject(:schema) do
|
197
|
-
Dry::Validation.Form do
|
198
|
-
required(:address).maybe(:hash?)
|
199
|
-
|
200
|
-
required(:delivery).filled(:bool?)
|
201
|
-
|
202
|
-
rule(address: [:delivery, :address]) do |delivery, address|
|
203
|
-
delivery.true?.then(address.schema(AddressSchema))
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
before do
|
209
|
-
AddressSchema = Dry::Validation.Form do
|
210
|
-
required(:city).filled
|
211
|
-
required(:zipcode).filled(:int?)
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
after do
|
216
|
-
Object.send(:remove_const, :AddressSchema)
|
217
|
-
end
|
218
|
-
|
219
|
-
it 'succeeds when nested form schema succeeds' do
|
220
|
-
result = schema.(delivery: '1', address: { city: 'NYC', zipcode: '123' })
|
221
|
-
expect(result).to be_success
|
222
|
-
end
|
223
|
-
|
224
|
-
it 'does not apply schema when there is no match' do
|
225
|
-
result = schema.(delivery: '0', address: nil)
|
226
|
-
expect(result).to be_success
|
227
|
-
end
|
228
|
-
|
229
|
-
it 'fails when nested schema fails' do
|
230
|
-
result = schema.(delivery: '1', address: { city: 'NYC', zipcode: 'foo' })
|
231
|
-
expect(result.messages).to eql(
|
232
|
-
address: { zipcode: ['must be an integer'] }
|
233
|
-
)
|
234
|
-
end
|
235
|
-
end
|
236
|
-
end
|