dry-validation 0.9.5 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/lib/dry/validation/error.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
module Dry
|
2
|
-
module Validation
|
3
|
-
class Error
|
4
|
-
include Dry::Equalizer(:name, :result)
|
5
|
-
|
6
|
-
attr_reader :name, :result
|
7
|
-
|
8
|
-
def initialize(name, result)
|
9
|
-
@name = name
|
10
|
-
@result = result
|
11
|
-
end
|
12
|
-
|
13
|
-
def schema?
|
14
|
-
result.response.is_a?(Validation::Result)
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_ast
|
18
|
-
if schema?
|
19
|
-
[:schema, [name, result.response.to_ast]]
|
20
|
-
else
|
21
|
-
[:error, [name, result.to_ast]]
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
require 'dry/validation/message_compiler'
|
2
|
-
|
3
|
-
module Dry
|
4
|
-
module Validation
|
5
|
-
class ErrorCompiler < MessageCompiler
|
6
|
-
def message_type
|
7
|
-
:failure
|
8
|
-
end
|
9
|
-
|
10
|
-
def message_class
|
11
|
-
Message
|
12
|
-
end
|
13
|
-
|
14
|
-
def visit_error(node, opts = EMPTY_HASH)
|
15
|
-
rule, error = node
|
16
|
-
node_path = Array(opts.fetch(:path, rule))
|
17
|
-
|
18
|
-
path = if rule.is_a?(Array) && rule.size > node_path.size
|
19
|
-
rule
|
20
|
-
else
|
21
|
-
node_path
|
22
|
-
end
|
23
|
-
|
24
|
-
path.compact!
|
25
|
-
|
26
|
-
template = messages[rule.is_a?(Array) ? rule.last : rule, default_lookup_options]
|
27
|
-
|
28
|
-
if template
|
29
|
-
predicate, args, tokens = visit(error, opts.merge(path: path, message: false))
|
30
|
-
message_class[predicate, path, template % tokens, rule: rule, args: args]
|
31
|
-
else
|
32
|
-
visit(error, opts.merge(rule: rule, path: path))
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def visit_input(node, opts = EMPTY_HASH)
|
37
|
-
rule, result = node
|
38
|
-
opt_rule = opts[:rule]
|
39
|
-
|
40
|
-
if opts[:each] && opt_rule.is_a?(Array)
|
41
|
-
visit(result, opts.merge(rule: rule, path: opts[:path] + [opt_rule.last]))
|
42
|
-
else
|
43
|
-
visit(result, opts.merge(rule: rule))
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def visit_result(node, opts = EMPTY_HASH)
|
48
|
-
input, other = node
|
49
|
-
visit(other, opts.merge(input: input))
|
50
|
-
end
|
51
|
-
|
52
|
-
def visit_each(node, opts = EMPTY_HASH)
|
53
|
-
node.map { |el| visit(el, opts.merge(each: true)) }
|
54
|
-
end
|
55
|
-
|
56
|
-
def visit_schema(node, opts = EMPTY_HASH)
|
57
|
-
path, other = node
|
58
|
-
|
59
|
-
if opts[:path]
|
60
|
-
visit(other, opts.merge(path: opts[:path] + [path.last]))
|
61
|
-
else
|
62
|
-
visit(other, opts.merge(path: [path], schema: true))
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def visit_check(node, opts = EMPTY_HASH)
|
67
|
-
name, other = node
|
68
|
-
|
69
|
-
if opts[:schema]
|
70
|
-
visit(other, opts)
|
71
|
-
else
|
72
|
-
visit(other, opts.merge(path: Array(name)))
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def lookup_options(opts, arg_vals = [])
|
77
|
-
super.update(val_type: opts[:input].class)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
@@ -1,104 +0,0 @@
|
|
1
|
-
require 'dry/validation/message_compiler'
|
2
|
-
|
3
|
-
module Dry
|
4
|
-
module Validation
|
5
|
-
class HintCompiler < MessageCompiler
|
6
|
-
include Dry::Equalizer(:messages, :rules, :options)
|
7
|
-
|
8
|
-
attr_reader :rules, :excluded, :cache
|
9
|
-
|
10
|
-
TYPES = {
|
11
|
-
none?: NilClass,
|
12
|
-
bool?: TrueClass,
|
13
|
-
str?: String,
|
14
|
-
int?: Fixnum,
|
15
|
-
float?: Float,
|
16
|
-
decimal?: BigDecimal,
|
17
|
-
date?: Date,
|
18
|
-
date_time?: DateTime,
|
19
|
-
time?: Time,
|
20
|
-
hash?: Hash,
|
21
|
-
array?: Array
|
22
|
-
}.freeze
|
23
|
-
|
24
|
-
EXCLUDED = (%i(key? none? filled?) + TYPES.keys).freeze
|
25
|
-
|
26
|
-
def self.cache
|
27
|
-
@cache ||= Concurrent::Map.new
|
28
|
-
end
|
29
|
-
|
30
|
-
def initialize(messages, options = {})
|
31
|
-
super(messages, options)
|
32
|
-
@rules = options.fetch(:rules, EMPTY_ARRAY)
|
33
|
-
@excluded = options.fetch(:excluded, EXCLUDED)
|
34
|
-
@cache = self.class.cache
|
35
|
-
end
|
36
|
-
|
37
|
-
def message_type
|
38
|
-
:hint
|
39
|
-
end
|
40
|
-
|
41
|
-
def message_class
|
42
|
-
Hint
|
43
|
-
end
|
44
|
-
|
45
|
-
def hash
|
46
|
-
@hash ||= [messages, rules, options].hash
|
47
|
-
end
|
48
|
-
|
49
|
-
def call
|
50
|
-
cache.fetch_or_store(hash) { super(rules) }
|
51
|
-
end
|
52
|
-
|
53
|
-
def visit_predicate(node, opts = EMPTY_HASH)
|
54
|
-
predicate, args = node
|
55
|
-
return EMPTY_ARRAY if excluded.include?(predicate) || dyn_args?(args)
|
56
|
-
super(node, opts.merge(val_type: TYPES[predicate]))
|
57
|
-
end
|
58
|
-
|
59
|
-
def visit_each(node, opts = EMPTY_HASH)
|
60
|
-
visit(node, opts.merge(each: true))
|
61
|
-
end
|
62
|
-
|
63
|
-
def visit_or(node, *args)
|
64
|
-
left, right = node
|
65
|
-
[Array[visit(left, *args)], Array[visit(right, *args)]].flatten
|
66
|
-
end
|
67
|
-
|
68
|
-
def visit_and(node, *args)
|
69
|
-
_, right = node
|
70
|
-
visit(right, *args)
|
71
|
-
end
|
72
|
-
|
73
|
-
def visit_schema(node, opts = EMPTY_HASH)
|
74
|
-
path = node.config.path
|
75
|
-
rules = node.rule_ast
|
76
|
-
schema_opts = opts.merge(path: [path])
|
77
|
-
|
78
|
-
rules.map { |rule| visit(rule, schema_opts) }
|
79
|
-
end
|
80
|
-
|
81
|
-
def visit_check(node)
|
82
|
-
EMPTY_ARRAY
|
83
|
-
end
|
84
|
-
|
85
|
-
def visit_xor(node)
|
86
|
-
EMPTY_ARRAY
|
87
|
-
end
|
88
|
-
|
89
|
-
def visit_not(node)
|
90
|
-
EMPTY_ARRAY
|
91
|
-
end
|
92
|
-
|
93
|
-
def visit_type(node, *args)
|
94
|
-
visit(node.rule.to_ast, *args)
|
95
|
-
end
|
96
|
-
|
97
|
-
private
|
98
|
-
|
99
|
-
def dyn_args?(args)
|
100
|
-
args.map(&:last).any? { |a| a.is_a?(UnboundMethod) }
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
require 'dry/validation/hint_compiler'
|
2
|
-
|
3
|
-
RSpec.describe HintCompiler, '#call' do
|
4
|
-
subject(:compiler) { HintCompiler.new(Messages.default, rules: rules) }
|
5
|
-
|
6
|
-
include_context 'predicate helper'
|
7
|
-
|
8
|
-
let(:rules) do
|
9
|
-
[
|
10
|
-
[
|
11
|
-
:and, [
|
12
|
-
[:val, p(:key?, :age)],
|
13
|
-
[
|
14
|
-
:or, [
|
15
|
-
[:key, [:age, p(:none?)]],
|
16
|
-
[
|
17
|
-
:and, [
|
18
|
-
[:key, [:age, p(:int?)]],
|
19
|
-
[:key, [:age, p(:gt?, 18)]]
|
20
|
-
]
|
21
|
-
]
|
22
|
-
]
|
23
|
-
]
|
24
|
-
],
|
25
|
-
],
|
26
|
-
[
|
27
|
-
:and, [
|
28
|
-
[:val, p(:key?, :height)],
|
29
|
-
[
|
30
|
-
:or, [
|
31
|
-
[:key, [:height, p(:none?)]],
|
32
|
-
[
|
33
|
-
:and, [
|
34
|
-
[:key, [:height, p(:int?)]],
|
35
|
-
[:key, [:height, p(:gt?, 180)]]
|
36
|
-
]
|
37
|
-
]
|
38
|
-
]
|
39
|
-
]
|
40
|
-
]
|
41
|
-
]
|
42
|
-
]
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'returns hint messages for given rules' do
|
46
|
-
expect(compiler.call.to_h).to eql(
|
47
|
-
age: ['must be greater than 18'],
|
48
|
-
height: ['must be greater than 180'],
|
49
|
-
)
|
50
|
-
end
|
51
|
-
end
|