dry-validation 0.9.5 → 0.10.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/.travis.yml +1 -8
- data/CHANGELOG.md +34 -1
- data/Gemfile +2 -0
- data/Rakefile +12 -3
- data/config/errors.yml +1 -0
- data/dry-validation.gemspec +3 -2
- data/lib/dry/validation/executor.rb +3 -27
- data/lib/dry/validation/extensions/monads.rb +17 -0
- data/lib/dry/validation/extensions/struct.rb +32 -0
- data/lib/dry/validation/extensions.rb +7 -0
- data/lib/dry/validation/input_processor_compiler.rb +19 -3
- data/lib/dry/validation/message.rb +43 -30
- data/lib/dry/validation/message_compiler/visitor_opts.rb +39 -0
- data/lib/dry/validation/message_compiler.rb +98 -52
- data/lib/dry/validation/message_set.rb +59 -30
- data/lib/dry/validation/predicate_registry.rb +17 -6
- data/lib/dry/validation/result.rb +39 -17
- data/lib/dry/validation/schema/check.rb +5 -4
- data/lib/dry/validation/schema/class_interface.rb +6 -13
- data/lib/dry/validation/schema/dsl.rb +9 -3
- data/lib/dry/validation/schema/form.rb +12 -3
- data/lib/dry/validation/schema/json.rb +12 -3
- data/lib/dry/validation/schema/key.rb +6 -6
- data/lib/dry/validation/schema/rule.rb +14 -8
- data/lib/dry/validation/schema/value.rb +23 -21
- data/lib/dry/validation/schema.rb +9 -12
- data/lib/dry/validation/schema_compiler.rb +16 -2
- data/lib/dry/validation/version.rb +1 -1
- data/lib/dry/validation.rb +11 -23
- data/spec/extensions/monads/result_spec.rb +38 -0
- data/spec/extensions/struct/schema_spec.rb +32 -0
- data/spec/integration/custom_predicates_spec.rb +7 -6
- data/spec/integration/form/predicates/size/fixed_spec.rb +0 -2
- data/spec/integration/form/predicates/size/range_spec.rb +0 -2
- data/spec/integration/hints_spec.rb +2 -6
- data/spec/integration/json/defining_base_schema_spec.rb +41 -0
- data/spec/integration/{error_compiler_spec.rb → message_compiler_spec.rb} +79 -131
- data/spec/integration/result_spec.rb +26 -4
- data/spec/integration/schema/check_with_nested_el_spec.rb +1 -1
- data/spec/integration/schema/check_with_nth_el_spec.rb +1 -1
- data/spec/integration/schema/defining_base_schema_spec.rb +3 -0
- data/spec/integration/schema/dynamic_predicate_args_spec.rb +34 -9
- data/spec/integration/schema/form/defining_base_schema_spec.rb +41 -0
- data/spec/integration/schema/json_spec.rb +1 -0
- data/spec/integration/schema/macros/input_spec.rb +26 -0
- data/spec/integration/schema/macros/rule_spec.rb +2 -1
- data/spec/integration/schema/macros/value_spec.rb +1 -1
- data/spec/integration/schema/macros/when_spec.rb +1 -24
- data/spec/integration/schema/or_spec.rb +87 -0
- data/spec/integration/schema/predicates/custom_spec.rb +4 -4
- data/spec/integration/schema/predicates/even_spec.rb +10 -10
- data/spec/integration/schema/predicates/odd_spec.rb +10 -10
- data/spec/integration/schema/predicates/size/fixed_spec.rb +0 -3
- data/spec/integration/schema/predicates/size/range_spec.rb +0 -2
- data/spec/integration/schema/predicates/type_spec.rb +22 -0
- data/spec/integration/schema/using_types_spec.rb +14 -41
- data/spec/integration/schema/validate_spec.rb +83 -0
- data/spec/integration/schema/xor_spec.rb +5 -5
- data/spec/integration/schema_builders_spec.rb +4 -2
- data/spec/integration/schema_spec.rb +8 -0
- data/spec/shared/message_compiler.rb +11 -0
- data/spec/shared/predicate_helper.rb +5 -3
- data/spec/spec_helper.rb +15 -0
- data/spec/unit/input_processor_compiler/form_spec.rb +3 -3
- data/spec/unit/message_compiler/visit_failure_spec.rb +38 -0
- data/spec/unit/message_compiler/visit_spec.rb +16 -0
- data/spec/unit/message_compiler_spec.rb +7 -0
- data/spec/unit/predicate_registry_spec.rb +2 -2
- data/spec/unit/schema/key_spec.rb +19 -12
- data/spec/unit/schema/rule_spec.rb +14 -6
- data/spec/unit/schema/value_spec.rb +49 -52
- metadata +50 -20
- data/lib/dry/validation/constants.rb +0 -6
- data/lib/dry/validation/error.rb +0 -26
- data/lib/dry/validation/error_compiler.rb +0 -81
- data/lib/dry/validation/hint_compiler.rb +0 -104
- data/spec/unit/error_compiler_spec.rb +0 -7
- data/spec/unit/hint_compiler_spec.rb +0 -51
@@ -1,7 +1,7 @@
|
|
1
1
|
RSpec.describe Dry::Validation::Result do
|
2
2
|
subject(:result) { schema.(input) }
|
3
3
|
|
4
|
-
let(:schema) { Dry::Validation.Schema { required(:name).filled(:str
|
4
|
+
let(:schema) { Dry::Validation.Schema { required(:name).filled(:str?, size?: 2..4) } }
|
5
5
|
|
6
6
|
context 'with valid input' do
|
7
7
|
let(:input) { { name: 'Jane' } }
|
@@ -42,17 +42,39 @@ RSpec.describe Dry::Validation::Result do
|
|
42
42
|
|
43
43
|
describe '#messages' do
|
44
44
|
it 'returns a hash with error messages' do
|
45
|
-
expect(result.messages).to eql(
|
45
|
+
expect(result.messages).to eql(
|
46
|
+
name: ['must be filled', 'length must be within 2 - 4']
|
47
|
+
)
|
46
48
|
end
|
47
49
|
|
48
50
|
it 'with full: true returns full messages' do
|
49
|
-
expect(result.messages(full: true)).to eql(
|
51
|
+
expect(result.messages(full: true)).to eql(
|
52
|
+
name: ['name must be filled', 'name length must be within 2 - 4']
|
53
|
+
)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#errors' do
|
58
|
+
let(:input) { { name: '' } }
|
59
|
+
|
60
|
+
it 'returns failure messages' do
|
61
|
+
expect(result.errors).to eql(name: ['must be filled'])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#hints' do
|
66
|
+
let(:input) { { name: '' } }
|
67
|
+
|
68
|
+
it 'returns hint messages' do
|
69
|
+
expect(result.hints).to eql(name: ['length must be within 2 - 4'])
|
50
70
|
end
|
51
71
|
end
|
52
72
|
|
53
73
|
describe '#message_set' do
|
54
74
|
it 'returns message set' do
|
55
|
-
expect(result.message_set.to_h).to eql(
|
75
|
+
expect(result.message_set.to_h).to eql(
|
76
|
+
name: ['must be filled', 'length must be within 2 - 4']
|
77
|
+
)
|
56
78
|
end
|
57
79
|
end
|
58
80
|
end
|
@@ -1,18 +1,43 @@
|
|
1
1
|
RSpec.describe Dry::Validation::Schema, 'dynamic predicate args' do
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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
|
7
9
|
end
|
10
|
+
|
11
|
+
required(:letter).filled(included_in?: data)
|
8
12
|
end
|
13
|
+
end
|
9
14
|
|
10
|
-
|
15
|
+
it 'evaluates predicate arguments' do
|
16
|
+
expect(schema.(letter: 'a')).to be_success
|
17
|
+
expect(schema.(letter: 'f')).to be_failure
|
11
18
|
end
|
12
19
|
end
|
13
20
|
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
17
42
|
end
|
18
43
|
end
|
@@ -0,0 +1,41 @@
|
|
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.Form(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' => '').messages).to eql(
|
38
|
+
name: ['must be filled'], email: ['is missing', 'must be an email']
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
@@ -154,6 +154,7 @@ RSpec.describe Dry::Validation::Schema::JSON, 'defining a schema' do
|
|
154
154
|
|
155
155
|
it 'fails when nested schema fails' do
|
156
156
|
result = schema.(delivery: true, address: { city: 'NYC', zipcode: 'foo' })
|
157
|
+
|
157
158
|
expect(result.messages).to eql(
|
158
159
|
address: { zipcode: ['must be an integer'] }
|
159
160
|
)
|
@@ -110,4 +110,30 @@ RSpec.describe 'Macros #input' do
|
|
110
110
|
)
|
111
111
|
end
|
112
112
|
end
|
113
|
+
|
114
|
+
context 'using a custom predicate' do
|
115
|
+
subject(:schema) do
|
116
|
+
Dry::Validation.Schema do
|
117
|
+
configure do
|
118
|
+
def valid_keys?(input)
|
119
|
+
input.size == 2 || input.size == 1
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
input :hash?, :valid_keys?
|
124
|
+
|
125
|
+
required(:foo).filled
|
126
|
+
optional(:bar).filled
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'passes when input is valid' do
|
131
|
+
expect(schema.(foo: 'bar')).to be_successful
|
132
|
+
expect(schema.(foo: 'bar', bar: 'baz')).to be_successful
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'fails when one of the root-rules fails' do
|
136
|
+
expect(schema.(foo: 'bar', bar: 'baz', oops: 'heh')).to be_failure
|
137
|
+
end
|
138
|
+
end
|
113
139
|
end
|
@@ -67,7 +67,8 @@ RSpec.describe 'Macros / rule' do
|
|
67
67
|
|
68
68
|
it 'fails when rules failed' do
|
69
69
|
expect(schema.(x: 2).messages).to eql(
|
70
|
-
|
70
|
+
a: ['must be greater than 3'],
|
71
|
+
b: ['must be greater than 5']
|
71
72
|
)
|
72
73
|
end
|
73
74
|
end
|
@@ -111,7 +111,7 @@ RSpec.describe 'Macros #value' do
|
|
111
111
|
|
112
112
|
it 'uses the schema' do
|
113
113
|
expect(schema.(data: { foo: '' }).messages).to eql(
|
114
|
-
data: { foo: ['must be filled', '
|
114
|
+
data: { foo: ['must be filled', 'length must be within 2 - 10'] }
|
115
115
|
)
|
116
116
|
end
|
117
117
|
end
|
@@ -40,30 +40,7 @@ RSpec.describe 'Macros #when' do
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
|
44
|
-
subject(:schema) do
|
45
|
-
Dry::Validation.Schema do
|
46
|
-
required(:email).maybe
|
47
|
-
required(:password).maybe
|
48
|
-
|
49
|
-
required(:login).maybe(:bool?).when(:true?) do
|
50
|
-
value(:email).filled?
|
51
|
-
value(:password).filled?
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'generates check rule' do
|
57
|
-
expect(schema.(login: false, email: nil, password: nil)).to be_success
|
58
|
-
|
59
|
-
expect(schema.(login: true, email: nil, password: nil).messages).to eql(
|
60
|
-
email: ['must be filled'],
|
61
|
-
password: ['must be filled']
|
62
|
-
)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
context "predicate with options" do
|
43
|
+
context 'predicate with options' do
|
67
44
|
subject(:schema) do
|
68
45
|
Dry::Validation.Schema do
|
69
46
|
required(:bar).maybe
|
@@ -0,0 +1,87 @@
|
|
1
|
+
RSpec.describe Dry::Validation::Schema, 'OR messages' do
|
2
|
+
context 'with two predicates' do
|
3
|
+
subject(:schema) do
|
4
|
+
Dry::Validation.Schema do
|
5
|
+
required(:foo) { str? | int? }
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'returns success for valid input' do
|
10
|
+
expect(schema.(foo: 'bar')).to be_success
|
11
|
+
expect(schema.(foo: 321)).to be_success
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'provides OR error message for invalid input where all both sides failed' do
|
15
|
+
expect(schema.(foo: []).errors).to eql(foo: ['must be a string or must be an integer'])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'with a predicate and a conjunction of predicates' do
|
20
|
+
subject(:schema) do
|
21
|
+
Dry::Validation.Schema do
|
22
|
+
required(:foo) { str? | (int? & gt?(18)) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'returns success for valid input' do
|
27
|
+
expect(schema.(foo: 'bar')).to be_success
|
28
|
+
expect(schema.(foo: 321)).to be_success
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'provides OR message for invalid input where both sides failed' do
|
32
|
+
expect(schema.(foo: []).errors).to eql(foo: ['must be a string or must be an integer'])
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'provides error messages for invalid input where right side failed' do
|
36
|
+
expect(schema.(foo: 17).errors).to eql(foo: ['must be a string or must be greater than 18'])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'with a predicate and an each operation' do
|
41
|
+
subject(:schema) do
|
42
|
+
Dry::Validation.Schema do
|
43
|
+
required(:foo) { str? | each(:int?) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'returns success for valid input' do
|
48
|
+
expect(schema.(foo: 'bar')).to be_success
|
49
|
+
expect(schema.(foo: [1, 2, 3])).to be_success
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'provides OR message for invalid input where both sides failed' do
|
53
|
+
expect(schema.(foo: {}).errors).to eql(foo: ['must be a string or must be an array'])
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'provides error messages for invalid input where right side failed' do
|
57
|
+
expect(schema.(foo: %w(1 2 3)).errors).to eql(
|
58
|
+
foo: {
|
59
|
+
0 => ['must be an integer'],
|
60
|
+
1 => ['must be an integer'],
|
61
|
+
2 => ['must be an integer']
|
62
|
+
}
|
63
|
+
)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'with a predicate and a schema' do
|
68
|
+
subject(:schema) do
|
69
|
+
Dry::Validation.Schema do
|
70
|
+
required(:foo) { str? | schema { required(:bar).filled } }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'returns success for valid input' do
|
75
|
+
expect(schema.(foo: 'bar')).to be_success
|
76
|
+
expect(schema.(foo: { bar: 'baz' })).to be_success
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'provides OR message for invalid input where both sides failed' do
|
80
|
+
expect(schema.(foo: []).errors).to eql(foo: ['must be a string or must be a hash'])
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'provides error messages for invalid input where right side rules failed' do
|
84
|
+
expect(schema.(foo: { bar: '' }).errors).to eql(foo: { bar: ['must be filled'] })
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -6,7 +6,7 @@ RSpec.describe 'Predicates: custom' do
|
|
6
6
|
config.messages_file = 'spec/fixtures/locales/en.yml'
|
7
7
|
|
8
8
|
def email?(current)
|
9
|
-
current.match(/\@/)
|
9
|
+
!current.match(/\@/).nil?
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -39,8 +39,8 @@ RSpec.describe 'Predicates: custom' do
|
|
39
39
|
predicates (Module.new do
|
40
40
|
include Dry::Logic::Predicates
|
41
41
|
|
42
|
-
|
43
|
-
current.match(
|
42
|
+
def self.email?(current)
|
43
|
+
!current.match(/\@/).nil?
|
44
44
|
end
|
45
45
|
end)
|
46
46
|
end
|
@@ -97,7 +97,7 @@ RSpec.describe 'Predicates: custom' do
|
|
97
97
|
|
98
98
|
it 'allows groups to define their own custom predicates' do
|
99
99
|
expect(result).to_not be_success
|
100
|
-
expect(result.messages
|
100
|
+
expect(result.messages[:details]).to eq(foo: ['must be odd'])
|
101
101
|
end
|
102
102
|
end
|
103
103
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
RSpec.describe 'Predicates: Even' do
|
2
2
|
context 'with required' do
|
3
3
|
subject(:schema) do
|
4
|
-
Dry::Validation.
|
4
|
+
Dry::Validation.Schema do
|
5
5
|
required(:foo) { even? }
|
6
6
|
end
|
7
7
|
end
|
@@ -57,7 +57,7 @@ RSpec.describe 'Predicates: Even' do
|
|
57
57
|
|
58
58
|
context 'with optional' do
|
59
59
|
subject(:schema) do
|
60
|
-
Dry::Validation.
|
60
|
+
Dry::Validation.Schema do
|
61
61
|
optional(:foo) { even? }
|
62
62
|
end
|
63
63
|
end
|
@@ -115,7 +115,7 @@ RSpec.describe 'Predicates: Even' do
|
|
115
115
|
context 'with required' do
|
116
116
|
context 'with value' do
|
117
117
|
subject(:schema) do
|
118
|
-
Dry::Validation.
|
118
|
+
Dry::Validation.Schema do
|
119
119
|
required(:foo).value(:even?)
|
120
120
|
end
|
121
121
|
end
|
@@ -171,7 +171,7 @@ RSpec.describe 'Predicates: Even' do
|
|
171
171
|
|
172
172
|
context 'with filled' do
|
173
173
|
subject(:schema) do
|
174
|
-
Dry::Validation.
|
174
|
+
Dry::Validation.Schema do
|
175
175
|
required(:foo).filled(:even?)
|
176
176
|
end
|
177
177
|
end
|
@@ -227,7 +227,7 @@ RSpec.describe 'Predicates: Even' do
|
|
227
227
|
|
228
228
|
context 'with maybe' do
|
229
229
|
subject(:schema) do
|
230
|
-
Dry::Validation.
|
230
|
+
Dry::Validation.Schema do
|
231
231
|
required(:foo).maybe(:even?)
|
232
232
|
end
|
233
233
|
end
|
@@ -260,7 +260,7 @@ RSpec.describe 'Predicates: Even' do
|
|
260
260
|
let(:input) { { foo: '' } }
|
261
261
|
|
262
262
|
it 'is successful' do
|
263
|
-
expect
|
263
|
+
expect { result }.to raise_error(NoMethodError)
|
264
264
|
end
|
265
265
|
end
|
266
266
|
|
@@ -285,7 +285,7 @@ RSpec.describe 'Predicates: Even' do
|
|
285
285
|
context 'with optional' do
|
286
286
|
context 'with value' do
|
287
287
|
subject(:schema) do
|
288
|
-
Dry::Validation.
|
288
|
+
Dry::Validation.Schema do
|
289
289
|
optional(:foo).value(:even?)
|
290
290
|
end
|
291
291
|
end
|
@@ -341,7 +341,7 @@ RSpec.describe 'Predicates: Even' do
|
|
341
341
|
|
342
342
|
context 'with filled' do
|
343
343
|
subject(:schema) do
|
344
|
-
Dry::Validation.
|
344
|
+
Dry::Validation.Schema do
|
345
345
|
optional(:foo).filled(:even?)
|
346
346
|
end
|
347
347
|
end
|
@@ -397,7 +397,7 @@ RSpec.describe 'Predicates: Even' do
|
|
397
397
|
|
398
398
|
context 'with maybe' do
|
399
399
|
subject(:schema) do
|
400
|
-
Dry::Validation.
|
400
|
+
Dry::Validation.Schema do
|
401
401
|
optional(:foo).maybe(:even?)
|
402
402
|
end
|
403
403
|
end
|
@@ -430,7 +430,7 @@ RSpec.describe 'Predicates: Even' do
|
|
430
430
|
let(:input) { { foo: '' } }
|
431
431
|
|
432
432
|
it 'is successful' do
|
433
|
-
expect
|
433
|
+
expect { result }.to raise_error(NoMethodError)
|
434
434
|
end
|
435
435
|
end
|
436
436
|
|