dry-validation 0.7.4 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +9 -6
- data/CHANGELOG.md +58 -0
- data/Gemfile +3 -3
- data/benchmarks/benchmark_form_invalid.rb +64 -0
- data/benchmarks/benchmark_form_valid.rb +64 -0
- data/benchmarks/profile_schema_call_invalid.rb +20 -0
- data/benchmarks/profile_schema_call_valid.rb +20 -0
- data/benchmarks/profile_schema_definition.rb +14 -0
- data/benchmarks/profile_schema_messages_invalid.rb +20 -0
- data/benchmarks/suite.rb +5 -0
- data/config/errors.yml +12 -5
- data/dry-validation.gemspec +2 -2
- data/examples/basic.rb +2 -2
- data/examples/form.rb +2 -2
- data/examples/json.rb +2 -2
- data/examples/nested.rb +6 -6
- data/lib/dry/validation.rb +22 -3
- data/lib/dry/validation/deprecations.rb +23 -0
- data/lib/dry/validation/error_compiler.rb +31 -11
- data/lib/dry/validation/error_compiler/input.rb +44 -57
- data/lib/dry/validation/hint_compiler.rb +15 -7
- data/lib/dry/validation/input_processor_compiler.rb +13 -6
- data/lib/dry/validation/input_processor_compiler/form.rb +2 -0
- data/lib/dry/validation/input_processor_compiler/sanitizer.rb +1 -1
- data/lib/dry/validation/messages/abstract.rb +9 -1
- data/lib/dry/validation/predicate_registry.rb +101 -0
- data/lib/dry/validation/result.rb +8 -1
- data/lib/dry/validation/schema.rb +110 -44
- data/lib/dry/validation/schema/check.rb +4 -2
- data/lib/dry/validation/schema/deprecated.rb +31 -0
- data/lib/dry/validation/schema/dsl.rb +18 -11
- data/lib/dry/validation/schema/form.rb +1 -0
- data/lib/dry/validation/schema/json.rb +1 -0
- data/lib/dry/validation/schema/key.rb +23 -10
- data/lib/dry/validation/schema/rule.rb +81 -20
- data/lib/dry/validation/schema/value.rb +110 -25
- data/lib/dry/validation/version.rb +1 -1
- data/spec/fixtures/locales/en.yml +1 -0
- data/spec/fixtures/locales/pl.yml +1 -1
- data/spec/integration/custom_error_messages_spec.rb +2 -2
- data/spec/integration/custom_predicates_spec.rb +98 -15
- data/spec/integration/error_compiler_spec.rb +111 -96
- data/spec/integration/form/predicates/array_spec.rb +243 -0
- data/spec/integration/form/predicates/empty_spec.rb +263 -0
- data/spec/integration/form/predicates/eql_spec.rb +327 -0
- data/spec/integration/form/predicates/even_spec.rb +455 -0
- data/spec/integration/form/predicates/excluded_from_spec.rb +455 -0
- data/spec/integration/form/predicates/excludes_spec.rb +391 -0
- data/spec/integration/form/predicates/false_spec.rb +455 -0
- data/spec/integration/form/predicates/filled_spec.rb +467 -0
- data/spec/integration/form/predicates/format_spec.rb +454 -0
- data/spec/integration/form/predicates/gt_spec.rb +519 -0
- data/spec/integration/form/predicates/gteq_spec.rb +519 -0
- data/spec/integration/form/predicates/included_in_spec.rb +455 -0
- data/spec/integration/form/predicates/includes_spec.rb +391 -0
- data/spec/integration/form/predicates/key_spec.rb +75 -0
- data/spec/integration/form/predicates/lt_spec.rb +519 -0
- data/spec/integration/form/predicates/lteq_spec.rb +519 -0
- data/spec/integration/form/predicates/max_size_spec.rb +391 -0
- data/spec/integration/form/predicates/min_size_spec.rb +391 -0
- data/spec/integration/form/predicates/none_spec.rb +265 -0
- data/spec/integration/form/predicates/not_eql_spec.rb +327 -0
- data/spec/integration/form/predicates/odd_spec.rb +455 -0
- data/spec/integration/form/predicates/size/fixed_spec.rb +399 -0
- data/spec/integration/form/predicates/size/range_spec.rb +398 -0
- data/spec/integration/form/predicates/true_spec.rb +455 -0
- data/spec/integration/form/predicates/type_spec.rb +391 -0
- data/spec/integration/hints_spec.rb +90 -4
- data/spec/integration/injecting_rules_spec.rb +2 -2
- data/spec/integration/localized_error_messages_spec.rb +2 -2
- data/spec/integration/messages/i18n_spec.rb +3 -3
- data/spec/integration/optional_keys_spec.rb +3 -3
- data/spec/integration/schema/array_schema_spec.rb +49 -13
- data/spec/integration/schema/check_rules_spec.rb +6 -6
- data/spec/integration/schema/check_with_nested_el_spec.rb +3 -3
- data/spec/integration/schema/check_with_nth_el_spec.rb +1 -1
- data/spec/integration/schema/each_with_set_spec.rb +3 -3
- data/spec/integration/schema/extending_dsl_spec.rb +27 -0
- data/spec/integration/schema/form/explicit_types_spec.rb +182 -0
- data/spec/integration/schema/form_spec.rb +90 -18
- data/spec/integration/schema/hash_schema_spec.rb +47 -0
- data/spec/integration/schema/inheriting_schema_spec.rb +4 -4
- data/spec/integration/schema/input_processor_spec.rb +8 -8
- data/spec/integration/schema/json/explicit_types_spec.rb +157 -0
- data/spec/integration/schema/json_spec.rb +18 -18
- data/spec/integration/schema/macros/confirmation_spec.rb +1 -1
- data/spec/integration/schema/macros/each_spec.rb +177 -43
- data/spec/integration/schema/macros/{required_spec.rb → filled_spec.rb} +34 -6
- data/spec/integration/schema/macros/input_spec.rb +21 -0
- data/spec/integration/schema/macros/maybe_spec.rb +39 -2
- data/spec/integration/schema/macros/value_spec.rb +105 -0
- data/spec/integration/schema/macros/when_spec.rb +28 -8
- data/spec/integration/schema/nested_values_spec.rb +11 -8
- data/spec/integration/schema/not_spec.rb +2 -2
- data/spec/integration/schema/numbers_spec.rb +1 -1
- data/spec/integration/schema/option_with_default_spec.rb +1 -1
- data/spec/integration/schema/predicate_verification_spec.rb +9 -0
- data/spec/integration/schema/predicates/array_spec.rb +295 -0
- data/spec/integration/schema/predicates/custom_spec.rb +103 -0
- data/spec/integration/schema/predicates/empty_spec.rb +263 -0
- data/spec/integration/schema/predicates/eql_spec.rb +327 -0
- data/spec/integration/schema/predicates/even_spec.rb +455 -0
- data/spec/integration/schema/predicates/excluded_from_spec.rb +455 -0
- data/spec/integration/schema/predicates/excludes_spec.rb +391 -0
- data/spec/integration/schema/predicates/filled_spec.rb +467 -0
- data/spec/integration/schema/predicates/format_spec.rb +455 -0
- data/spec/integration/schema/predicates/gt_spec.rb +519 -0
- data/spec/integration/schema/predicates/gteq_spec.rb +519 -0
- data/spec/integration/schema/predicates/hash_spec.rb +69 -0
- data/spec/integration/schema/predicates/included_in_spec.rb +455 -0
- data/spec/integration/schema/predicates/includes_spec.rb +391 -0
- data/spec/integration/schema/predicates/key_spec.rb +88 -0
- data/spec/integration/schema/predicates/lt_spec.rb +520 -0
- data/spec/integration/schema/predicates/lteq_spec.rb +519 -0
- data/spec/integration/schema/predicates/max_size_spec.rb +391 -0
- data/spec/integration/schema/predicates/min_size_spec.rb +391 -0
- data/spec/integration/schema/predicates/none_spec.rb +265 -0
- data/spec/integration/schema/predicates/not_eql_spec.rb +391 -0
- data/spec/integration/schema/predicates/odd_spec.rb +455 -0
- data/spec/integration/schema/predicates/size/fixed_spec.rb +401 -0
- data/spec/integration/schema/predicates/size/range_spec.rb +399 -0
- data/spec/integration/schema/predicates/type_spec.rb +391 -0
- data/spec/integration/schema/reusing_schema_spec.rb +4 -4
- data/spec/integration/schema/using_types_spec.rb +24 -6
- data/spec/integration/schema/xor_spec.rb +2 -2
- data/spec/integration/schema_builders_spec.rb +15 -0
- data/spec/integration/schema_spec.rb +37 -12
- data/spec/shared/predicate_helper.rb +13 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/support/matchers.rb +38 -0
- data/spec/support/predicates_integration.rb +7 -0
- data/spec/unit/hint_compiler_spec.rb +10 -8
- data/spec/unit/input_processor_compiler/form_spec.rb +45 -43
- data/spec/unit/input_processor_compiler/json_spec.rb +37 -35
- data/spec/unit/predicate_registry_spec.rb +34 -0
- data/spec/unit/schema/key_spec.rb +12 -14
- data/spec/unit/schema/rule_spec.rb +4 -2
- data/spec/unit/schema/value_spec.rb +38 -121
- metadata +150 -16
- data/lib/dry/validation/schema/attr.rb +0 -15
- data/spec/integration/attr_spec.rb +0 -122
@@ -17,6 +17,9 @@ module Dry
|
|
17
17
|
setting :lookup_paths, %w(
|
18
18
|
%{root}.rules.%{rule}.%{predicate}.arg.%{arg_type}
|
19
19
|
%{root}.rules.%{rule}.%{predicate}
|
20
|
+
%{root}.%{predicate}.%{message_type}
|
21
|
+
%{root}.%{predicate}.value.%{rule}.arg.%{arg_type}
|
22
|
+
%{root}.%{predicate}.value.%{rule}
|
20
23
|
%{root}.%{predicate}.value.%{val_type}.arg.%{arg_type}
|
21
24
|
%{root}.%{predicate}.value.%{val_type}
|
22
25
|
%{root}.%{predicate}.arg.%{arg_type}
|
@@ -45,6 +48,10 @@ module Dry
|
|
45
48
|
@config = self.class.config
|
46
49
|
end
|
47
50
|
|
51
|
+
def hash
|
52
|
+
@hash ||= config.hash
|
53
|
+
end
|
54
|
+
|
48
55
|
def rule(name, options = {})
|
49
56
|
path = "%{locale}.rules.#{name}"
|
50
57
|
get(path, options) if key?(path, options)
|
@@ -63,7 +70,8 @@ module Dry
|
|
63
70
|
root: root,
|
64
71
|
predicate: predicate,
|
65
72
|
arg_type: config.arg_types[options[:arg_type]],
|
66
|
-
val_type: config.val_types[options[:val_type]]
|
73
|
+
val_type: config.val_types[options[:val_type]],
|
74
|
+
message_type: options[:message_type] || :failure
|
67
75
|
)
|
68
76
|
|
69
77
|
tokens[:rule] = predicate unless tokens.key?(:rule)
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Dry
|
2
|
+
module Validation
|
3
|
+
class PredicateRegistry
|
4
|
+
attr_reader :predicates
|
5
|
+
attr_reader :external
|
6
|
+
|
7
|
+
class Bound < PredicateRegistry
|
8
|
+
def initialize(*args)
|
9
|
+
super
|
10
|
+
freeze
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Unbound < PredicateRegistry
|
15
|
+
def bind(schema)
|
16
|
+
bound_predicates = predicates.each_with_object({}) do |(n, p), res|
|
17
|
+
res[n] = p.bind(schema)
|
18
|
+
end
|
19
|
+
Bound.new(external, bound_predicates)
|
20
|
+
end
|
21
|
+
|
22
|
+
def update(other)
|
23
|
+
unbound_predicates = other.each_with_object({}) { |(n, p), res|
|
24
|
+
res[n] = Logic::Predicate.new(n, fn: p)
|
25
|
+
}
|
26
|
+
predicates.update(unbound_predicates)
|
27
|
+
self
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.[](klass, predicates)
|
32
|
+
Unbound.new(predicates).tap do |registry|
|
33
|
+
klass.class_eval do
|
34
|
+
def self.method_added(name)
|
35
|
+
super
|
36
|
+
if name.to_s.end_with?('?')
|
37
|
+
registry.update(name => instance_method(name))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize(external, predicates = {})
|
45
|
+
@external = external
|
46
|
+
@predicates = predicates
|
47
|
+
end
|
48
|
+
|
49
|
+
def new(klass)
|
50
|
+
new_predicates = predicates
|
51
|
+
.keys
|
52
|
+
.each_with_object({}) { |key, res| res[key] = klass.instance_method(key) }
|
53
|
+
|
54
|
+
self.class.new(external).update(new_predicates)
|
55
|
+
end
|
56
|
+
|
57
|
+
def [](name)
|
58
|
+
predicates.fetch(name) do
|
59
|
+
if external.key?(name)
|
60
|
+
external[name]
|
61
|
+
else
|
62
|
+
raise_unknown_predicate_error(name)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def key?(name)
|
68
|
+
predicates.key?(name) || external.key?(name)
|
69
|
+
end
|
70
|
+
|
71
|
+
def ensure_valid_predicate(name, args_or_arity)
|
72
|
+
if name == :key?
|
73
|
+
raise InvalidSchemaError, "#{name} is a reserved predicate name"
|
74
|
+
end
|
75
|
+
|
76
|
+
if key?(name)
|
77
|
+
arity = self[name].arity
|
78
|
+
|
79
|
+
case args_or_arity
|
80
|
+
when Array
|
81
|
+
raise_invalid_arity_error(name) if ![0, args_or_arity.size + 1].include?(arity)
|
82
|
+
when Fixnum
|
83
|
+
raise_invalid_arity_error(name) if args_or_arity != arity
|
84
|
+
end
|
85
|
+
else
|
86
|
+
raise_unknown_predicate_error(name)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def raise_unknown_predicate_error(name)
|
93
|
+
raise ArgumentError, "+#{name}+ is not a valid predicate name"
|
94
|
+
end
|
95
|
+
|
96
|
+
def raise_invalid_arity_error(name)
|
97
|
+
raise ArgumentError, "#{name} predicate arity is invalid"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -45,7 +45,14 @@ module Dry
|
|
45
45
|
hints = hint_compiler.with(options).call
|
46
46
|
comp = error_compiler.with(options.merge(hints: hints))
|
47
47
|
|
48
|
-
comp.(error_ast)
|
48
|
+
messages = comp.(error_ast)
|
49
|
+
msg_hash = comp.dump_messages(messages)
|
50
|
+
|
51
|
+
if msg_hash.key?(nil)
|
52
|
+
msg_hash.values.flatten
|
53
|
+
else
|
54
|
+
msg_hash
|
55
|
+
end
|
49
56
|
end
|
50
57
|
end
|
51
58
|
|
@@ -1,8 +1,9 @@
|
|
1
|
+
require 'dry/logic/predicates'
|
1
2
|
require 'dry/types/constraints'
|
2
3
|
|
4
|
+
require 'dry/validation/predicate_registry'
|
3
5
|
require 'dry/validation/schema_compiler'
|
4
6
|
require 'dry/validation/schema/key'
|
5
|
-
require 'dry/validation/schema/attr'
|
6
7
|
require 'dry/validation/schema/value'
|
7
8
|
require 'dry/validation/schema/check'
|
8
9
|
|
@@ -12,7 +13,7 @@ require 'dry/validation/messages'
|
|
12
13
|
require 'dry/validation/error_compiler'
|
13
14
|
require 'dry/validation/hint_compiler'
|
14
15
|
|
15
|
-
require 'dry/validation/
|
16
|
+
require 'dry/validation/schema/deprecated'
|
16
17
|
|
17
18
|
module Dry
|
18
19
|
module Validation
|
@@ -22,24 +23,109 @@ module Dry
|
|
22
23
|
NOOP_INPUT_PROCESSOR = -> input { input }
|
23
24
|
|
24
25
|
setting :path
|
25
|
-
setting :predicates,
|
26
|
+
setting :predicates, Logic::Predicates
|
27
|
+
setting :registry
|
26
28
|
setting :messages, :yaml
|
27
29
|
setting :messages_file
|
28
30
|
setting :namespace
|
29
31
|
setting :rules, []
|
30
32
|
setting :checks, []
|
33
|
+
setting :options, {}
|
34
|
+
setting :type_map, {}
|
35
|
+
setting :hash_type, :weak
|
36
|
+
setting :input, nil
|
37
|
+
setting :dsl_extensions, nil
|
31
38
|
|
32
39
|
setting :input_processor, :noop
|
33
|
-
|
34
40
|
setting :input_processor_map, {
|
35
41
|
sanitizer: InputProcessorCompiler::Sanitizer.new,
|
36
42
|
json: InputProcessorCompiler::JSON.new,
|
37
43
|
form: InputProcessorCompiler::Form.new,
|
38
44
|
}.freeze
|
39
45
|
|
46
|
+
setting :type_specs, false
|
47
|
+
|
40
48
|
def self.inherited(klass)
|
41
49
|
super
|
42
|
-
klass.
|
50
|
+
klass.config.options = klass.config.options.dup
|
51
|
+
|
52
|
+
if registry && self != Schema
|
53
|
+
klass.config.registry = registry.new(self)
|
54
|
+
else
|
55
|
+
klass.set_registry!
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.clone
|
60
|
+
klass = Class.new(self)
|
61
|
+
klass.config.rules = []
|
62
|
+
klass.config.registry = registry
|
63
|
+
klass
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.set_registry!
|
67
|
+
config.registry = PredicateRegistry[self, config.predicates]
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.registry
|
71
|
+
config.registry
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.build_array_type(spec, category)
|
75
|
+
member_schema = build_type_map(spec, category)
|
76
|
+
member_type = lookup_type("hash", category)
|
77
|
+
.public_send(config.hash_type, member_schema)
|
78
|
+
|
79
|
+
lookup_type("array", category).member(member_type)
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.build_type_map(type_specs, category = config.input_processor)
|
83
|
+
if type_specs.is_a?(Array)
|
84
|
+
build_array_type(type_specs[0], category)
|
85
|
+
else
|
86
|
+
type_specs.each_with_object({}) do |(name, spec), result|
|
87
|
+
result[name] =
|
88
|
+
case spec
|
89
|
+
when Hash
|
90
|
+
lookup_type("hash", category).public_send(config.hash_type, spec)
|
91
|
+
when Array
|
92
|
+
if spec.size == 1
|
93
|
+
if spec[0].is_a?(Hash)
|
94
|
+
build_array_type(spec[0], category)
|
95
|
+
else
|
96
|
+
lookup_type("array", category).member(lookup_type(spec[0], category))
|
97
|
+
end
|
98
|
+
else
|
99
|
+
spec
|
100
|
+
.map { |id| id.is_a?(Symbol) ? lookup_type(id, category) : id }
|
101
|
+
.reduce(:|)
|
102
|
+
end
|
103
|
+
when Symbol
|
104
|
+
lookup_type(spec, category)
|
105
|
+
else
|
106
|
+
spec
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.lookup_type(name, category)
|
113
|
+
id = "#{category}.#{name}"
|
114
|
+
Types.type_keys.include?(id) ? Types[id] : Types[name.to_s]
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
def self.type_map
|
119
|
+
config.type_map
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.predicates(predicate_set = nil)
|
123
|
+
if predicate_set
|
124
|
+
config.predicates = predicate_set
|
125
|
+
set_registry!
|
126
|
+
else
|
127
|
+
config.predicates
|
128
|
+
end
|
43
129
|
end
|
44
130
|
|
45
131
|
def self.new(rules = config.rules, **options)
|
@@ -52,8 +138,10 @@ module Dry
|
|
52
138
|
Class.new(other.class)
|
53
139
|
elsif other.is_a?(Class) && other < Types::Struct
|
54
140
|
Validation.Schema(parent: target, build: false) do
|
55
|
-
other.schema.each { |attr, type|
|
141
|
+
other.schema.each { |attr, type| required(attr).filled(type) }
|
56
142
|
end
|
143
|
+
elsif other.respond_to?(:schema) && other.schema.is_a?(self)
|
144
|
+
Class.new(other.schema.class)
|
57
145
|
else
|
58
146
|
Validation.Schema(target.schema_class, parent: target, build: false, &block)
|
59
147
|
end
|
@@ -77,10 +165,6 @@ module Dry
|
|
77
165
|
config.rules
|
78
166
|
end
|
79
167
|
|
80
|
-
def self.predicates
|
81
|
-
config.predicates
|
82
|
-
end
|
83
|
-
|
84
168
|
def self.options
|
85
169
|
config.options
|
86
170
|
end
|
@@ -116,31 +200,12 @@ module Dry
|
|
116
200
|
@hint_compiler ||= HintCompiler.new(messages, rules: rule_ast)
|
117
201
|
end
|
118
202
|
|
119
|
-
def self.input_processor
|
120
|
-
@input_processor ||=
|
121
|
-
begin
|
122
|
-
if input_processor_compiler
|
123
|
-
input_processor_compiler.(rule_ast)
|
124
|
-
else
|
125
|
-
NOOP_INPUT_PROCESSOR
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
def self.input_processor_ast(type)
|
131
|
-
config.input_processor_map.fetch(type).schema_ast(rule_ast)
|
132
|
-
end
|
133
|
-
|
134
|
-
def self.input_processor_compiler
|
135
|
-
@input_processor_comp ||= config.input_processor_map[config.input_processor]
|
136
|
-
end
|
137
|
-
|
138
203
|
def self.rule_ast
|
139
|
-
@rule_ast ||= config.rules.
|
204
|
+
@rule_ast ||= config.rules.map(&:to_ast)
|
140
205
|
end
|
141
206
|
|
142
207
|
def self.default_options
|
143
|
-
{
|
208
|
+
{ predicate_registry: registry,
|
144
209
|
error_compiler: error_compiler,
|
145
210
|
hint_compiler: hint_compiler,
|
146
211
|
input_processor: input_processor,
|
@@ -163,11 +228,14 @@ module Dry
|
|
163
228
|
|
164
229
|
attr_reader :options
|
165
230
|
|
231
|
+
attr_reader :type_map
|
232
|
+
|
166
233
|
def initialize(rules, options)
|
167
|
-
@
|
234
|
+
@type_map = self.class.type_map
|
235
|
+
@predicates = options.fetch(:predicate_registry).bind(self)
|
236
|
+
@rule_compiler = SchemaCompiler.new(predicates)
|
168
237
|
@error_compiler = options.fetch(:error_compiler)
|
169
238
|
@hint_compiler = options.fetch(:hint_compiler)
|
170
|
-
@predicates = options.fetch(:predicates)
|
171
239
|
@input_processor = options.fetch(:input_processor, NOOP_INPUT_PROCESSOR)
|
172
240
|
|
173
241
|
initialize_options(options)
|
@@ -186,22 +254,20 @@ module Dry
|
|
186
254
|
Result.new(processed_input, apply(processed_input), error_compiler, hint_compiler)
|
187
255
|
end
|
188
256
|
|
189
|
-
def [](name)
|
190
|
-
if predicates.key?(name)
|
191
|
-
predicates[name]
|
192
|
-
elsif respond_to?(name)
|
193
|
-
Logic::Predicate.new(name, &method(name))
|
194
|
-
else
|
195
|
-
raise ArgumentError, "+#{name}+ is not a valid predicate name"
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
257
|
def curry(*args)
|
200
258
|
to_proc.curry.(*args)
|
201
259
|
end
|
202
260
|
|
203
261
|
def to_proc
|
204
|
-
-> input {
|
262
|
+
-> input { call(input) }
|
263
|
+
end
|
264
|
+
|
265
|
+
def arity
|
266
|
+
1
|
267
|
+
end
|
268
|
+
|
269
|
+
def to_ast
|
270
|
+
self.class.to_ast
|
205
271
|
end
|
206
272
|
|
207
273
|
private
|
@@ -22,9 +22,11 @@ module Dry
|
|
22
22
|
vals, args = meth_args.partition { |arg| arg.class < DSL }
|
23
23
|
|
24
24
|
keys = [name, *vals.map(&:name)]
|
25
|
-
predicate = [:predicate, [meth, args]]
|
26
25
|
|
27
|
-
|
26
|
+
registry.ensure_valid_predicate(meth, args.size + keys.size)
|
27
|
+
predicate = registry[meth].curry(*args)
|
28
|
+
|
29
|
+
rule = create_rule([:check, [name, predicate.to_ast, keys]])
|
28
30
|
add_rule(rule)
|
29
31
|
rule
|
30
32
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'dry/validation/input_processor_compiler'
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
module Validation
|
5
|
+
class Schema
|
6
|
+
def self.input_processor
|
7
|
+
@input_processor ||=
|
8
|
+
begin
|
9
|
+
if type_map.is_a?(Dry::Types::Safe) && config.input_processor != :noop
|
10
|
+
type_map
|
11
|
+
elsif type_map.size > 0 && config.input_processor != :noop
|
12
|
+
lookup_type("hash", config.input_processor)
|
13
|
+
.public_send(config.hash_type, type_map)
|
14
|
+
elsif input_processor_compiler
|
15
|
+
input_processor_compiler.(rule_ast)
|
16
|
+
else
|
17
|
+
NOOP_INPUT_PROCESSOR
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.input_processor_ast(type)
|
23
|
+
config.input_processor_map.fetch(type).schema_ast(rule_ast)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.input_processor_compiler
|
27
|
+
@input_processor_comp ||= config.input_processor_map[config.input_processor]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,10 +1,13 @@
|
|
1
1
|
require 'dry/validation/schema/rule'
|
2
|
+
require 'dry/validation/deprecations'
|
2
3
|
|
3
4
|
module Dry
|
4
5
|
module Validation
|
5
6
|
class Schema
|
6
7
|
class DSL < BasicObject
|
7
|
-
|
8
|
+
include ::Dry::Validation::Deprecations
|
9
|
+
|
10
|
+
attr_reader :name, :registry, :rules, :checks, :parent, :options
|
8
11
|
|
9
12
|
def self.[](name, options = {})
|
10
13
|
new(options.merge(name: name))
|
@@ -13,6 +16,7 @@ module Dry
|
|
13
16
|
def initialize(options = {})
|
14
17
|
@name = options[:name]
|
15
18
|
@parent = options[:parent]
|
19
|
+
@registry = options.fetch(:registry)
|
16
20
|
@rules = options.fetch(:rules, [])
|
17
21
|
@checks = options.fetch(:checks, [])
|
18
22
|
@options = options
|
@@ -23,16 +27,14 @@ module Dry
|
|
23
27
|
end
|
24
28
|
alias_method :to_s, :inspect
|
25
29
|
|
26
|
-
def
|
27
|
-
define(name, Key, &block)
|
28
|
-
end
|
30
|
+
def optional(name, type_spec = nil, &block)
|
31
|
+
rule = define(name, Key, :then, &block)
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
+
if type_spec
|
34
|
+
type_map[name] = type_spec
|
35
|
+
end
|
33
36
|
|
34
|
-
|
35
|
-
define(name, Attr, &block)
|
37
|
+
rule
|
36
38
|
end
|
37
39
|
|
38
40
|
def not
|
@@ -73,17 +75,22 @@ module Dry
|
|
73
75
|
self.class.new(options.merge(new_options))
|
74
76
|
end
|
75
77
|
|
78
|
+
def predicate?(meth)
|
79
|
+
registry.key?(meth)
|
80
|
+
end
|
81
|
+
|
76
82
|
private
|
77
83
|
|
78
84
|
def define(name, key_class, op = :and, &block)
|
79
85
|
type = key_class.type
|
80
86
|
|
81
87
|
val = Value[
|
82
|
-
name, type: type, parent: self, rules: rules,
|
88
|
+
name, registry: registry, type: type, parent: self, rules: rules,
|
89
|
+
checks: checks, schema_class: schema_class.clone
|
83
90
|
].__send__(:"#{type}?", name)
|
84
91
|
|
85
92
|
if block
|
86
|
-
key = key_class[name]
|
93
|
+
key = key_class[name, registry: registry]
|
87
94
|
res = key.instance_eval(&block)
|
88
95
|
|
89
96
|
if res.class == Value
|