dry-schema 1.4.1 → 1.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +210 -73
- data/LICENSE +1 -1
- data/README.md +4 -6
- data/config/errors.yml +4 -0
- data/dry-schema.gemspec +46 -0
- data/lib/dry-schema.rb +1 -1
- data/lib/dry/schema.rb +20 -7
- data/lib/dry/schema/compiler.rb +5 -5
- data/lib/dry/schema/config.rb +15 -6
- data/lib/dry/schema/constants.rb +16 -7
- data/lib/dry/schema/dsl.rb +89 -31
- data/lib/dry/schema/extensions.rb +10 -2
- data/lib/dry/schema/extensions/hints.rb +15 -8
- data/lib/dry/schema/extensions/hints/message_compiler_methods.rb +2 -2
- data/lib/dry/schema/extensions/hints/message_set_methods.rb +0 -47
- data/lib/dry/schema/extensions/info.rb +27 -0
- data/lib/dry/schema/extensions/info/schema_compiler.rb +105 -0
- data/lib/dry/schema/extensions/monads.rb +1 -1
- data/lib/dry/schema/extensions/struct.rb +32 -0
- data/lib/dry/schema/json.rb +1 -1
- data/lib/dry/schema/key.rb +20 -5
- data/lib/dry/schema/key_coercer.rb +4 -4
- data/lib/dry/schema/key_map.rb +9 -4
- data/lib/dry/schema/key_validator.rb +67 -0
- data/lib/dry/schema/macros.rb +8 -8
- data/lib/dry/schema/macros/array.rb +17 -4
- data/lib/dry/schema/macros/core.rb +11 -6
- data/lib/dry/schema/macros/dsl.rb +44 -23
- data/lib/dry/schema/macros/each.rb +4 -4
- data/lib/dry/schema/macros/filled.rb +5 -5
- data/lib/dry/schema/macros/hash.rb +21 -3
- data/lib/dry/schema/macros/key.rb +10 -9
- data/lib/dry/schema/macros/maybe.rb +4 -5
- data/lib/dry/schema/macros/optional.rb +1 -1
- data/lib/dry/schema/macros/required.rb +1 -1
- data/lib/dry/schema/macros/schema.rb +23 -2
- data/lib/dry/schema/macros/value.rb +34 -7
- data/lib/dry/schema/message.rb +35 -9
- data/lib/dry/schema/message/or.rb +18 -39
- data/lib/dry/schema/message/or/abstract.rb +28 -0
- data/lib/dry/schema/message/or/multi_path.rb +37 -0
- data/lib/dry/schema/message/or/single_path.rb +64 -0
- data/lib/dry/schema/message_compiler.rb +58 -22
- data/lib/dry/schema/message_compiler/visitor_opts.rb +2 -2
- data/lib/dry/schema/message_set.rb +26 -37
- data/lib/dry/schema/messages.rb +6 -6
- data/lib/dry/schema/messages/abstract.rb +54 -62
- data/lib/dry/schema/messages/i18n.rb +36 -10
- data/lib/dry/schema/messages/namespaced.rb +12 -2
- data/lib/dry/schema/messages/template.rb +19 -44
- data/lib/dry/schema/messages/yaml.rb +61 -14
- data/lib/dry/schema/params.rb +1 -1
- data/lib/dry/schema/path.rb +44 -5
- data/lib/dry/schema/predicate.rb +4 -2
- data/lib/dry/schema/predicate_inferrer.rb +4 -184
- data/lib/dry/schema/predicate_registry.rb +2 -2
- data/lib/dry/schema/primitive_inferrer.rb +16 -0
- data/lib/dry/schema/processor.rb +50 -29
- data/lib/dry/schema/processor_steps.rb +50 -27
- data/lib/dry/schema/result.rb +53 -6
- data/lib/dry/schema/rule_applier.rb +7 -7
- data/lib/dry/schema/step.rb +79 -0
- data/lib/dry/schema/trace.rb +5 -4
- data/lib/dry/schema/type_container.rb +3 -3
- data/lib/dry/schema/type_registry.rb +2 -2
- data/lib/dry/schema/types.rb +1 -1
- data/lib/dry/schema/value_coercer.rb +2 -2
- data/lib/dry/schema/version.rb +1 -1
- metadata +21 -7
data/lib/dry/schema/macros.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
3
|
+
require "dry/schema/macros/array"
|
4
|
+
require "dry/schema/macros/each"
|
5
|
+
require "dry/schema/macros/filled"
|
6
|
+
require "dry/schema/macros/schema"
|
7
|
+
require "dry/schema/macros/hash"
|
8
|
+
require "dry/schema/macros/maybe"
|
9
|
+
require "dry/schema/macros/optional"
|
10
|
+
require "dry/schema/macros/required"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/schema/macros/dsl"
|
4
4
|
|
5
5
|
module Dry
|
6
6
|
module Schema
|
@@ -13,16 +13,29 @@ module Dry
|
|
13
13
|
def value(*args, **opts, &block)
|
14
14
|
type(:array)
|
15
15
|
|
16
|
-
extract_type_spec(*args, set_type: false) do |*predicates, type_spec:|
|
16
|
+
extract_type_spec(*args, set_type: false) do |*predicates, type_spec:, type_rule:|
|
17
17
|
type(schema_dsl.array[type_spec]) if type_spec
|
18
18
|
|
19
19
|
is_hash_block = type_spec.equal?(:hash)
|
20
20
|
|
21
21
|
if predicates.any? || opts.any? || !is_hash_block
|
22
|
-
super(
|
22
|
+
super(
|
23
|
+
*predicates, type_spec: type_spec, type_rule: type_rule, **opts,
|
24
|
+
&(is_hash_block ? nil : block)
|
25
|
+
)
|
23
26
|
end
|
24
27
|
|
25
|
-
|
28
|
+
is_op = args.size.equal?(2) && args[1].is_a?(Logic::Operations::Abstract)
|
29
|
+
|
30
|
+
if is_hash_block && !is_op
|
31
|
+
hash(&block)
|
32
|
+
elsif is_op
|
33
|
+
hash = Value.new(schema_dsl: schema_dsl.new, name: name).hash(args[1])
|
34
|
+
|
35
|
+
trace.captures.concat(hash.trace.captures)
|
36
|
+
|
37
|
+
type(schema_dsl.types[name].of(hash.schema_dsl.types[name]))
|
38
|
+
end
|
26
39
|
end
|
27
40
|
|
28
41
|
self
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/initializer"
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
5
|
+
require "dry/schema/constants"
|
6
|
+
require "dry/schema/compiler"
|
7
|
+
require "dry/schema/trace"
|
8
8
|
|
9
9
|
module Dry
|
10
10
|
module Schema
|
@@ -28,8 +28,13 @@ module Dry
|
|
28
28
|
option :schema_dsl, optional: true
|
29
29
|
|
30
30
|
# @api private
|
31
|
-
def new(options
|
32
|
-
self.class.new(
|
31
|
+
def new(**options)
|
32
|
+
self.class.new(name: name, compiler: compiler, schema_dsl: schema_dsl, **options)
|
33
|
+
end
|
34
|
+
|
35
|
+
# @api private
|
36
|
+
def path
|
37
|
+
schema_dsl.path
|
33
38
|
end
|
34
39
|
|
35
40
|
# @api private
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require 'dry/types/predicate_inferrer'
|
5
|
-
require 'dry/types/primitive_inferrer'
|
3
|
+
require "dry/logic/operators"
|
6
4
|
|
7
|
-
require
|
5
|
+
require "dry/schema/macros/core"
|
6
|
+
require "dry/schema/predicate_inferrer"
|
7
|
+
require "dry/schema/primitive_inferrer"
|
8
8
|
|
9
9
|
module Dry
|
10
10
|
module Schema
|
@@ -28,13 +28,13 @@ module Dry
|
|
28
28
|
# PredicateInferrer is used to infer predicate type-check from a type spec
|
29
29
|
# @return [PredicateInferrer]
|
30
30
|
# @api private
|
31
|
-
option :predicate_inferrer, default: proc {
|
31
|
+
option :predicate_inferrer, default: proc { PredicateInferrer.new(compiler.predicates) }
|
32
32
|
|
33
33
|
# @!attribute [r] primitive_inferrer
|
34
34
|
# PrimitiveInferrer used to get a list of primitive classes from configured type
|
35
35
|
# @return [PrimitiveInferrer]
|
36
36
|
# @api private
|
37
|
-
option :primitive_inferrer, default: proc {
|
37
|
+
option :primitive_inferrer, default: proc { PrimitiveInferrer.new }
|
38
38
|
|
39
39
|
# @overload value(*predicates, **predicate_opts)
|
40
40
|
# Set predicates without and with arguments
|
@@ -57,11 +57,12 @@ module Dry
|
|
57
57
|
# @return [Macros::Core]
|
58
58
|
#
|
59
59
|
# @api public
|
60
|
-
def value(*predicates,
|
60
|
+
def value(*predicates, &block)
|
61
61
|
append_macro(Macros::Value) do |macro|
|
62
|
-
macro.call(*predicates,
|
62
|
+
macro.call(*predicates, &block)
|
63
63
|
end
|
64
64
|
end
|
65
|
+
ruby2_keywords :value if respond_to?(:ruby2_keywords, true)
|
65
66
|
|
66
67
|
# Prepends `:filled?` predicate
|
67
68
|
#
|
@@ -74,11 +75,12 @@ module Dry
|
|
74
75
|
# @return [Macros::Core]
|
75
76
|
#
|
76
77
|
# @api public
|
77
|
-
def filled(*args,
|
78
|
+
def filled(*args, &block)
|
78
79
|
append_macro(Macros::Filled) do |macro|
|
79
|
-
macro.call(*args,
|
80
|
+
macro.call(*args, &block)
|
80
81
|
end
|
81
82
|
end
|
83
|
+
ruby2_keywords :filled if respond_to?(:ruby2_keywords, true)
|
82
84
|
|
83
85
|
# Specify a nested hash without enforced `hash?` type-check
|
84
86
|
#
|
@@ -99,6 +101,7 @@ module Dry
|
|
99
101
|
macro.call(*args, &block)
|
100
102
|
end
|
101
103
|
end
|
104
|
+
ruby2_keywords :schema if respond_to?(:ruby2_keywords, true)
|
102
105
|
|
103
106
|
# Specify a nested hash with enforced `hash?` type-check
|
104
107
|
#
|
@@ -113,6 +116,7 @@ module Dry
|
|
113
116
|
macro.call(*args, &block)
|
114
117
|
end
|
115
118
|
end
|
119
|
+
ruby2_keywords :hash if respond_to?(:ruby2_keywords, true)
|
116
120
|
|
117
121
|
# Specify predicates that should be applied to each element of an array
|
118
122
|
#
|
@@ -136,6 +140,7 @@ module Dry
|
|
136
140
|
macro.value(*args, &block)
|
137
141
|
end
|
138
142
|
end
|
143
|
+
ruby2_keywords :each if respond_to?(:ruby2_keywords, true)
|
139
144
|
|
140
145
|
# Like `each` but sets `array?` type-check
|
141
146
|
#
|
@@ -155,6 +160,7 @@ module Dry
|
|
155
160
|
macro.value(*args, &block)
|
156
161
|
end
|
157
162
|
end
|
163
|
+
ruby2_keywords :array if respond_to?(:ruby2_keywords, true)
|
158
164
|
|
159
165
|
# Set type spec
|
160
166
|
#
|
@@ -171,6 +177,11 @@ module Dry
|
|
171
177
|
self
|
172
178
|
end
|
173
179
|
|
180
|
+
# @api private
|
181
|
+
def custom_type?
|
182
|
+
schema_dsl.custom_type?(name)
|
183
|
+
end
|
184
|
+
|
174
185
|
private
|
175
186
|
|
176
187
|
# @api private
|
@@ -189,29 +200,32 @@ module Dry
|
|
189
200
|
|
190
201
|
# @api private
|
191
202
|
def extract_type_spec(*args, nullable: false, set_type: true)
|
192
|
-
type_spec = args[0]
|
193
|
-
|
194
|
-
is_type_spec = type_spec.is_a?(Dry::Schema::Processor) ||
|
195
|
-
type_spec.is_a?(Symbol) &&
|
196
|
-
type_spec.to_s.end_with?(QUESTION_MARK)
|
197
|
-
|
198
|
-
type_spec = nil if is_type_spec
|
203
|
+
type_spec = args[0] unless schema_or_predicate?(args[0])
|
199
204
|
|
200
205
|
predicates = Array(type_spec ? args[1..-1] : args)
|
206
|
+
type_rule = nil
|
201
207
|
|
202
208
|
if type_spec
|
203
209
|
resolved_type = resolve_type(type_spec, nullable)
|
204
210
|
|
205
|
-
|
206
|
-
|
207
|
-
|
211
|
+
if type_spec.is_a?(::Array)
|
212
|
+
type_rule = type_spec.map { |ts| new(chain: false).value(ts) }.reduce(:|)
|
213
|
+
else
|
214
|
+
type_predicates = predicate_inferrer[resolved_type]
|
208
215
|
|
209
|
-
|
216
|
+
predicates.replace(type_predicates + predicates) unless type_predicates.empty?
|
210
217
|
|
211
|
-
|
218
|
+
return self if predicates.empty?
|
219
|
+
end
|
212
220
|
end
|
213
221
|
|
214
|
-
|
222
|
+
type(resolved_type) if set_type && resolved_type
|
223
|
+
|
224
|
+
if type_rule
|
225
|
+
yield(*predicates, type_spec: nil, type_rule: type_rule)
|
226
|
+
else
|
227
|
+
yield(*predicates, type_spec: type_spec, type_rule: nil)
|
228
|
+
end
|
215
229
|
end
|
216
230
|
|
217
231
|
# @api private
|
@@ -224,6 +238,13 @@ module Dry
|
|
224
238
|
schema_dsl.resolve_type([:nil, resolved])
|
225
239
|
end
|
226
240
|
end
|
241
|
+
|
242
|
+
# @api private
|
243
|
+
def schema_or_predicate?(arg)
|
244
|
+
arg.is_a?(Dry::Schema::Processor) ||
|
245
|
+
arg.is_a?(Symbol) &&
|
246
|
+
arg.to_s.end_with?(QUESTION_MARK)
|
247
|
+
end
|
227
248
|
end
|
228
249
|
end
|
229
250
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "dry/types/type"
|
4
|
+
require "dry/schema/macros/dsl"
|
5
5
|
|
6
6
|
module Dry
|
7
7
|
module Schema
|
@@ -12,12 +12,12 @@ module Dry
|
|
12
12
|
class Each < DSL
|
13
13
|
# @api private
|
14
14
|
def value(*args, **opts)
|
15
|
-
extract_type_spec(*args, set_type: false) do |*predicates, type_spec:|
|
15
|
+
extract_type_spec(*args, set_type: false) do |*predicates, type_spec:, type_rule:|
|
16
16
|
if type_spec && !type_spec.is_a?(Dry::Types::Type)
|
17
17
|
type(schema_dsl.array[type_spec])
|
18
18
|
end
|
19
19
|
|
20
|
-
super(*predicates, type_spec: type_spec, **opts)
|
20
|
+
super(*predicates, type_spec: type_spec, type_rule: type_rule, **opts)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/schema/macros/value"
|
4
4
|
|
5
5
|
module Dry
|
6
6
|
module Schema
|
@@ -15,23 +15,23 @@ module Dry
|
|
15
15
|
|
16
16
|
if opts[:type_spec] && !filter_empty_string?
|
17
17
|
value(predicates[0], :filled?, *predicates[1..predicates.size - 1], **opts, &block)
|
18
|
+
elsif opts[:type_rule]
|
19
|
+
value(:filled?).value(*predicates, **opts, &block)
|
18
20
|
else
|
19
21
|
value(:filled?, *predicates, **opts, &block)
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
25
|
# @api private
|
24
|
-
# rubocop:disable Style/GuardClause
|
25
26
|
def ensure_valid_predicates(predicates)
|
26
27
|
if predicates.include?(:empty?)
|
27
|
-
raise ::Dry::Schema::InvalidSchemaError,
|
28
|
+
raise ::Dry::Schema::InvalidSchemaError, "Using filled with empty? predicate is invalid"
|
28
29
|
end
|
29
30
|
|
30
31
|
if predicates.include?(:filled?)
|
31
|
-
raise ::Dry::Schema::InvalidSchemaError,
|
32
|
+
raise ::Dry::Schema::InvalidSchemaError, "Using filled with filled? is redundant"
|
32
33
|
end
|
33
34
|
end
|
34
|
-
# rubocop:enable Style/GuardClause
|
35
35
|
|
36
36
|
# @api private
|
37
37
|
def filter_empty_string?
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/schema/macros/schema"
|
4
4
|
|
5
5
|
module Dry
|
6
6
|
module Schema
|
@@ -11,8 +11,26 @@ module Dry
|
|
11
11
|
class Hash < Schema
|
12
12
|
# @api private
|
13
13
|
def call(*args, &block)
|
14
|
-
|
15
|
-
|
14
|
+
if args.size >= 1 && args[0].respond_to?(:keys)
|
15
|
+
hash_type = args[0]
|
16
|
+
type_predicates = predicate_inferrer[hash_type]
|
17
|
+
all_predicats = type_predicates + args.drop(1)
|
18
|
+
|
19
|
+
super(*all_predicats) do
|
20
|
+
hash_type.each do |key|
|
21
|
+
if key.required?
|
22
|
+
required(key.name).value(key.type)
|
23
|
+
else
|
24
|
+
optional(key.name).value(key.type)
|
25
|
+
end
|
26
|
+
instance_exec(&block) if block
|
27
|
+
end
|
28
|
+
end
|
29
|
+
else
|
30
|
+
trace << hash?
|
31
|
+
|
32
|
+
super(*args, &block)
|
33
|
+
end
|
16
34
|
end
|
17
35
|
end
|
18
36
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "dry/schema/processor"
|
4
|
+
require "dry/schema/macros/dsl"
|
5
|
+
require "dry/schema/constants"
|
6
6
|
|
7
7
|
module Dry
|
8
8
|
module Schema
|
@@ -30,6 +30,7 @@ module Dry
|
|
30
30
|
(filter_schema_dsl[name] || filter_schema_dsl.optional(name)).value(*args, &block)
|
31
31
|
self
|
32
32
|
end
|
33
|
+
ruby2_keywords(:filter) if respond_to?(:ruby2_keywords, true)
|
33
34
|
|
34
35
|
# @overload value(type_spec, *predicates, **predicate_opts)
|
35
36
|
# Set type specification and predicates
|
@@ -53,8 +54,8 @@ module Dry
|
|
53
54
|
#
|
54
55
|
# @api public
|
55
56
|
def value(*args, **opts, &block)
|
56
|
-
extract_type_spec(*args) do |*predicates, type_spec:|
|
57
|
-
super(*predicates, type_spec: type_spec, **opts, &block)
|
57
|
+
extract_type_spec(*args) do |*predicates, type_spec:, type_rule:|
|
58
|
+
super(*predicates, type_spec: type_spec, type_rule: type_rule, **opts, &block)
|
58
59
|
end
|
59
60
|
end
|
60
61
|
|
@@ -69,8 +70,8 @@ module Dry
|
|
69
70
|
#
|
70
71
|
# @api public
|
71
72
|
def filled(*args, **opts, &block)
|
72
|
-
extract_type_spec(*args) do |*predicates, type_spec:|
|
73
|
-
super(*predicates, type_spec: type_spec, **opts, &block)
|
73
|
+
extract_type_spec(*args) do |*predicates, type_spec:, type_rule:|
|
74
|
+
super(*predicates, type_spec: type_spec, type_rule: type_rule, **opts, &block)
|
74
75
|
end
|
75
76
|
end
|
76
77
|
|
@@ -85,9 +86,9 @@ module Dry
|
|
85
86
|
#
|
86
87
|
# @api public
|
87
88
|
def maybe(*args, **opts, &block)
|
88
|
-
extract_type_spec(*args, nullable: true) do |*predicates, type_spec:|
|
89
|
+
extract_type_spec(*args, nullable: true) do |*predicates, type_spec:, type_rule:|
|
89
90
|
append_macro(Macros::Maybe) do |macro|
|
90
|
-
macro.call(*predicates, **opts, &block)
|
91
|
+
macro.call(*predicates, type_spec: type_spec, type_rule: type_rule, **opts, &block)
|
91
92
|
end
|
92
93
|
end
|
93
94
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/schema/macros/dsl"
|
4
4
|
|
5
5
|
module Dry
|
6
6
|
module Schema
|
@@ -12,11 +12,11 @@ module Dry
|
|
12
12
|
# @api private
|
13
13
|
def call(*args, **opts, &block)
|
14
14
|
if args.include?(:empty?)
|
15
|
-
raise ::Dry::Schema::InvalidSchemaError,
|
15
|
+
raise ::Dry::Schema::InvalidSchemaError, "Using maybe with empty? predicate is invalid"
|
16
16
|
end
|
17
17
|
|
18
18
|
if args.include?(:nil?)
|
19
|
-
raise ::Dry::Schema::InvalidSchemaError,
|
19
|
+
raise ::Dry::Schema::InvalidSchemaError, "Using maybe with nil? predicate is redundant"
|
20
20
|
end
|
21
21
|
|
22
22
|
value(*args, **opts, &block)
|
@@ -30,8 +30,7 @@ module Dry
|
|
30
30
|
[
|
31
31
|
[:not, [:predicate, [:nil?, [[:input, Undefined]]]]],
|
32
32
|
trace.to_rule.to_ast
|
33
|
-
]
|
34
|
-
]
|
33
|
+
]]
|
35
34
|
end
|
36
35
|
end
|
37
36
|
end
|