dry-schema 1.3.4 → 1.5.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 +253 -101
- data/LICENSE +1 -1
- data/README.md +6 -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 +4 -4
- data/lib/dry/schema/config.rb +15 -6
- data/lib/dry/schema/constants.rb +19 -9
- data/lib/dry/schema/dsl.rb +144 -38
- 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 +66 -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 +53 -21
- data/lib/dry/schema/macros/each.rb +4 -4
- data/lib/dry/schema/macros/filled.rb +5 -6
- data/lib/dry/schema/macros/hash.rb +21 -3
- data/lib/dry/schema/macros/key.rb +10 -10
- 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 +40 -19
- 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 +79 -66
- data/lib/dry/schema/messages/i18n.rb +36 -10
- data/lib/dry/schema/messages/namespaced.rb +13 -3
- data/lib/dry/schema/messages/template.rb +19 -44
- data/lib/dry/schema/messages/yaml.rb +72 -13
- data/lib/dry/schema/params.rb +1 -1
- data/lib/dry/schema/path.rb +44 -5
- data/lib/dry/schema/predicate.rb +2 -2
- data/lib/dry/schema/predicate_inferrer.rb +4 -184
- data/lib/dry/schema/predicate_registry.rb +3 -24
- data/lib/dry/schema/primitive_inferrer.rb +3 -86
- data/lib/dry/schema/processor.rb +54 -50
- data/lib/dry/schema/processor_steps.rb +139 -0
- data/lib/dry/schema/result.rb +52 -5
- data/lib/dry/schema/rule_applier.rb +8 -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/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
[gem]: https://rubygems.org/gems/dry-schema
|
2
|
-
[
|
3
|
-
[
|
2
|
+
[actions]: https://github.com/dry-rb/dry-schema/actions
|
3
|
+
[codacy]: https://www.codacy.com/gh/dry-rb/dry-schema
|
4
4
|
[chat]: https://dry-rb.zulipchat.com
|
5
5
|
[inchpages]: http://inch-ci.org/github/dry-rb/dry-schema
|
6
6
|
|
7
7
|
# dry-schema [][chat]
|
8
8
|
|
9
9
|
[][gem]
|
10
|
-
[][actions]
|
11
|
+
[][codacy]
|
12
|
+
[][codacy]
|
13
13
|
[][inchpages]
|
14
14
|
|
15
15
|
## Links
|
@@ -19,7 +19,7 @@
|
|
19
19
|
|
20
20
|
## Supported Ruby versions
|
21
21
|
|
22
|
-
This library officially supports following Ruby versions:
|
22
|
+
This library officially supports the following Ruby versions:
|
23
23
|
|
24
24
|
* MRI >= `2.4`
|
25
25
|
* jruby >= `9.2`
|
data/config/errors.yml
CHANGED
@@ -3,6 +3,8 @@ en:
|
|
3
3
|
or: "or"
|
4
4
|
|
5
5
|
errors:
|
6
|
+
unexpected_key: "is not allowed"
|
7
|
+
|
6
8
|
array?: "must be an array"
|
7
9
|
|
8
10
|
empty?: "must be empty"
|
@@ -101,5 +103,7 @@ en:
|
|
101
103
|
default: "must be %{size} bytes long"
|
102
104
|
range: "must be within %{size_left} - %{size_right} bytes long"
|
103
105
|
|
106
|
+
uuid_v4?: "is not a valid UUID"
|
107
|
+
|
104
108
|
not:
|
105
109
|
empty?: "cannot be empty"
|
data/dry-schema.gemspec
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# this file is managed by dry-rb/devtools project
|
3
|
+
|
4
|
+
lib = File.expand_path('lib', __dir__)
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
+
require 'dry/schema/version'
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = 'dry-schema'
|
10
|
+
spec.authors = ["Piotr Solnica"]
|
11
|
+
spec.email = ["piotr.solnica@gmail.com"]
|
12
|
+
spec.license = 'MIT'
|
13
|
+
spec.version = Dry::Schema::VERSION.dup
|
14
|
+
|
15
|
+
spec.summary = "Coercion and validation for data structures"
|
16
|
+
spec.description = <<~TEXT
|
17
|
+
dry-schema provides a DSL for defining schemas with keys and rules that should be applied to
|
18
|
+
values. It supports coercion, input sanitization, custom types and localized error messages
|
19
|
+
(with or without I18n gem). It's also used as the schema engine in dry-validation.
|
20
|
+
TEXT
|
21
|
+
spec.homepage = 'https://dry-rb.org/gems/dry-schema'
|
22
|
+
spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-schema.gemspec", "lib/**/*", "config/*.yml"]
|
23
|
+
spec.bindir = 'bin'
|
24
|
+
spec.executables = []
|
25
|
+
spec.require_paths = ['lib']
|
26
|
+
|
27
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
28
|
+
spec.metadata['changelog_uri'] = 'https://github.com/dry-rb/dry-schema/blob/master/CHANGELOG.md'
|
29
|
+
spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-schema'
|
30
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-schema/issues'
|
31
|
+
|
32
|
+
spec.required_ruby_version = ">= 2.4.0"
|
33
|
+
|
34
|
+
# to update dependencies edit project.yml
|
35
|
+
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
36
|
+
spec.add_runtime_dependency "dry-configurable", "~> 0.8", ">= 0.8.3"
|
37
|
+
spec.add_runtime_dependency "dry-core", "~> 0.4"
|
38
|
+
spec.add_runtime_dependency "dry-equalizer", "~> 0.2"
|
39
|
+
spec.add_runtime_dependency "dry-initializer", "~> 3.0"
|
40
|
+
spec.add_runtime_dependency "dry-logic", "~> 1.0"
|
41
|
+
spec.add_runtime_dependency "dry-types", "~> 1.4"
|
42
|
+
|
43
|
+
spec.add_development_dependency "bundler"
|
44
|
+
spec.add_development_dependency "rake"
|
45
|
+
spec.add_development_dependency "rspec"
|
46
|
+
end
|
data/lib/dry-schema.rb
CHANGED
data/lib/dry/schema.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/core/extensions"
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
5
|
+
require "dry/schema/config"
|
6
|
+
require "dry/schema/constants"
|
7
|
+
require "dry/schema/dsl"
|
8
|
+
require "dry/schema/params"
|
9
|
+
require "dry/schema/json"
|
9
10
|
|
10
11
|
module Dry
|
11
12
|
# Main interface
|
@@ -14,6 +15,18 @@ module Dry
|
|
14
15
|
module Schema
|
15
16
|
extend Dry::Core::Extensions
|
16
17
|
|
18
|
+
# Configuration
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# Dry::Schema.config.messages.backend = :i18n
|
22
|
+
#
|
23
|
+
# @return [Config]
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
def self.config
|
27
|
+
@config ||= Config.new
|
28
|
+
end
|
29
|
+
|
17
30
|
# Define a schema
|
18
31
|
#
|
19
32
|
# @example
|
@@ -30,7 +43,7 @@ module Dry
|
|
30
43
|
#
|
31
44
|
# @api public
|
32
45
|
def self.define(**options, &block)
|
33
|
-
DSL.new(options, &block).call
|
46
|
+
DSL.new(**options, &block).call
|
34
47
|
end
|
35
48
|
|
36
49
|
# Define a schema suitable for HTTP params
|
@@ -74,4 +87,4 @@ module Dry
|
|
74
87
|
end
|
75
88
|
end
|
76
89
|
|
77
|
-
require
|
90
|
+
require "dry/schema/extensions"
|
data/lib/dry/schema/compiler.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "dry/logic/rule_compiler"
|
4
|
+
require "dry/schema/namespaced_rule"
|
5
|
+
require "dry/schema/predicate_registry"
|
6
6
|
|
7
7
|
module Dry
|
8
8
|
module Schema
|
@@ -35,7 +35,7 @@ module Dry
|
|
35
35
|
# @return [NamespacedRule]
|
36
36
|
#
|
37
37
|
# @api private
|
38
|
-
def visit_namespace(node,
|
38
|
+
def visit_namespace(node, _opts = EMPTY_HASH)
|
39
39
|
namespace, rest = node
|
40
40
|
NamespacedRule.new(namespace, visit(rest))
|
41
41
|
end
|
data/lib/dry/schema/config.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "dry/equalizer"
|
4
|
+
require "dry/configurable"
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
6
|
+
require "dry/schema/constants"
|
7
|
+
require "dry/schema/predicate_registry"
|
8
|
+
require "dry/schema/type_container"
|
9
9
|
|
10
10
|
module Dry
|
11
11
|
module Schema
|
@@ -51,6 +51,15 @@ module Dry
|
|
51
51
|
setting(:default_locale, nil)
|
52
52
|
end
|
53
53
|
|
54
|
+
# @!method validate_keys
|
55
|
+
#
|
56
|
+
# On/off switch for key validator
|
57
|
+
#
|
58
|
+
# @return [Boolean]
|
59
|
+
#
|
60
|
+
# @api public
|
61
|
+
setting(:validate_keys, false)
|
62
|
+
|
54
63
|
# @api private
|
55
64
|
def respond_to_missing?(meth, include_private = false)
|
56
65
|
super || config.respond_to?(meth, include_private)
|
@@ -58,7 +67,7 @@ module Dry
|
|
58
67
|
|
59
68
|
# @api private
|
60
69
|
def inspect
|
61
|
-
"#<#{self.class} #{to_h.map { |k,v| ["#{k}=", v.inspect] }.map(&:join).join(
|
70
|
+
"#<#{self.class} #{to_h.map { |k, v| ["#{k}=", v.inspect] }.map(&:join).join(" ")}>"
|
62
71
|
end
|
63
72
|
|
64
73
|
private
|
data/lib/dry/schema/constants.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "pathname"
|
4
|
+
require "dry/core/constants"
|
5
5
|
|
6
6
|
module Dry
|
7
7
|
# Common constants used across the library
|
@@ -10,15 +10,24 @@ module Dry
|
|
10
10
|
module Schema
|
11
11
|
include Core::Constants
|
12
12
|
|
13
|
-
LIST_SEPARATOR =
|
14
|
-
QUESTION_MARK =
|
15
|
-
DOT =
|
13
|
+
LIST_SEPARATOR = ", "
|
14
|
+
QUESTION_MARK = "?"
|
15
|
+
DOT = "."
|
16
|
+
|
17
|
+
# core processor steps in the default execution order
|
18
|
+
STEPS_IN_ORDER = %i[
|
19
|
+
key_validator
|
20
|
+
key_coercer
|
21
|
+
filter_schema
|
22
|
+
value_coercer
|
23
|
+
rule_applier
|
24
|
+
].freeze
|
16
25
|
|
17
26
|
# Path to the default set of localized messages bundled within the gem
|
18
|
-
DEFAULT_MESSAGES_PATH = Pathname(__dir__).join(
|
27
|
+
DEFAULT_MESSAGES_PATH = Pathname(__dir__).join("../../../config/errors.yml").realpath.freeze
|
19
28
|
|
20
29
|
# Default namespace used for localized messages in YAML files
|
21
|
-
DEFAULT_MESSAGES_ROOT =
|
30
|
+
DEFAULT_MESSAGES_ROOT = "dry_schema"
|
22
31
|
|
23
32
|
# An error raised when DSL is used in an incorrect way
|
24
33
|
InvalidSchemaError = Class.new(StandardError)
|
@@ -26,10 +35,11 @@ module Dry
|
|
26
35
|
# An error raised when a localized message cannot be found
|
27
36
|
MissingMessageError = Class.new(StandardError) do
|
28
37
|
# @api private
|
29
|
-
def initialize(path)
|
38
|
+
def initialize(path, paths = [])
|
30
39
|
*rest, rule = path
|
31
40
|
super(<<~STR)
|
32
|
-
Message template for #{rule.inspect} under #{rest.join(DOT).inspect} was not found
|
41
|
+
Message template for #{rule.inspect} under #{rest.join(DOT).inspect} was not found. Searched in:
|
42
|
+
#{paths.map { |string| "\"#{string}\"" }.join("\n")}
|
33
43
|
STR
|
34
44
|
end
|
35
45
|
end
|
data/lib/dry/schema/dsl.rb
CHANGED
@@ -1,18 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
|
11
|
-
require
|
12
|
-
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
3
|
+
require "dry/initializer"
|
4
|
+
|
5
|
+
require "dry/schema"
|
6
|
+
require "dry/schema/constants"
|
7
|
+
require "dry/schema/path"
|
8
|
+
require "dry/schema/config"
|
9
|
+
require "dry/schema/compiler"
|
10
|
+
require "dry/schema/types"
|
11
|
+
require "dry/schema/macros"
|
12
|
+
|
13
|
+
require "dry/schema/processor"
|
14
|
+
require "dry/schema/processor_steps"
|
15
|
+
require "dry/schema/key_map"
|
16
|
+
require "dry/schema/key_coercer"
|
17
|
+
require "dry/schema/key_validator"
|
18
|
+
require "dry/schema/value_coercer"
|
19
|
+
require "dry/schema/rule_applier"
|
16
20
|
|
17
21
|
module Dry
|
18
22
|
module Schema
|
@@ -50,8 +54,6 @@ module Dry
|
|
50
54
|
|
51
55
|
extend Dry::Initializer
|
52
56
|
|
53
|
-
include ::Dry::Equalizer(:options)
|
54
|
-
|
55
57
|
# @return [Compiler] The rule compiler object
|
56
58
|
option :compiler, default: -> { Compiler.new }
|
57
59
|
|
@@ -64,18 +66,24 @@ module Dry
|
|
64
66
|
# @return [Compiler] A key=>type map defined within the DSL
|
65
67
|
option :types, default: -> { EMPTY_HASH.dup }
|
66
68
|
|
67
|
-
# @return [
|
68
|
-
option :parent,
|
69
|
+
# @return [Array] Optional parent DSL objects, that will be used to merge keys and rules
|
70
|
+
option :parent, Types::Coercible::Array, default: -> { EMPTY_ARRAY.dup }, as: :parents
|
69
71
|
|
70
72
|
# @return [Config] Configuration object exposed via `#configure` method
|
71
|
-
option :config, optional: true, default: proc {
|
73
|
+
option :config, optional: true, default: proc { default_config }
|
74
|
+
|
75
|
+
# @return [ProcessorSteps] Steps for the processor
|
76
|
+
option :steps, default: proc { ProcessorSteps.new }
|
77
|
+
|
78
|
+
# @return [Path, Array] Path under which the schema is defined
|
79
|
+
option :path, -> *args { Path[*args] if args.any? }, default: proc { EMPTY_ARRAY }
|
72
80
|
|
73
81
|
# Build a new DSL object and evaluate provided block
|
74
82
|
#
|
75
83
|
# @param [Hash] options
|
76
84
|
# @option options [Class] :processor The processor type (`Params`, `JSON` or a custom sub-class)
|
77
85
|
# @option options [Compiler] :compiler An instance of a rule compiler (must be compatible with `Schema::Compiler`) (optional)
|
78
|
-
# @option options [DSL] :parent
|
86
|
+
# @option options [Array[DSL]] :parent One or more instances of the parent DSL (optional)
|
79
87
|
# @option options [Config] :config A configuration object (optional)
|
80
88
|
#
|
81
89
|
# @see Schema.define
|
@@ -169,7 +177,7 @@ module Dry
|
|
169
177
|
def key(name, macro:, &block)
|
170
178
|
raise ArgumentError, "Key +#{name}+ is not a symbol" unless name.is_a?(::Symbol)
|
171
179
|
|
172
|
-
set_type(name, Types::Any)
|
180
|
+
set_type(name, Types::Any.meta(default: true))
|
173
181
|
|
174
182
|
macro = macro.new(
|
175
183
|
name: name,
|
@@ -189,11 +197,31 @@ module Dry
|
|
189
197
|
#
|
190
198
|
# @api private
|
191
199
|
def call
|
192
|
-
|
193
|
-
|
194
|
-
|
200
|
+
all_steps = parents.map(&:steps) + [steps]
|
201
|
+
|
202
|
+
result_steps = all_steps.inject { |result, steps| result.merge(steps) }
|
203
|
+
|
204
|
+
result_steps[:key_validator] = key_validator if config.validate_keys
|
205
|
+
result_steps[:key_coercer] = key_coercer
|
206
|
+
result_steps[:value_coercer] = value_coercer
|
207
|
+
result_steps[:rule_applier] = rule_applier
|
208
|
+
result_steps[:filter_schema] = filter_schema.rule_applier if filter_rules?
|
195
209
|
|
196
|
-
processor_type.new(schema_dsl: self, steps:
|
210
|
+
processor_type.new(schema_dsl: self, steps: result_steps)
|
211
|
+
end
|
212
|
+
|
213
|
+
# Merge with another dsl
|
214
|
+
#
|
215
|
+
# @return [DSL]
|
216
|
+
#
|
217
|
+
# @api private
|
218
|
+
def merge(other)
|
219
|
+
new(
|
220
|
+
parent: parents + other.parents,
|
221
|
+
macros: macros + other.macros,
|
222
|
+
types: types.merge(other.types),
|
223
|
+
steps: steps.merge(other.steps)
|
224
|
+
)
|
197
225
|
end
|
198
226
|
|
199
227
|
# Cast this DSL into a rule object
|
@@ -212,7 +240,46 @@ module Dry
|
|
212
240
|
#
|
213
241
|
# @api public
|
214
242
|
def array
|
215
|
-
-> member_type { type_registry[
|
243
|
+
-> member_type { type_registry["array"].of(resolve_type(member_type)) }
|
244
|
+
end
|
245
|
+
|
246
|
+
# Method allows steps injection to the processor
|
247
|
+
#
|
248
|
+
# @example
|
249
|
+
# before(:rule_applier) do |input|
|
250
|
+
# input.compact
|
251
|
+
# end
|
252
|
+
#
|
253
|
+
# @return [DSL]
|
254
|
+
#
|
255
|
+
# @api public
|
256
|
+
def before(key, &block)
|
257
|
+
steps.before(key, &block)
|
258
|
+
self
|
259
|
+
end
|
260
|
+
|
261
|
+
# Method allows steps injection to the processor
|
262
|
+
#
|
263
|
+
# @example
|
264
|
+
# after(:rule_applier) do |input|
|
265
|
+
# input.compact
|
266
|
+
# end
|
267
|
+
#
|
268
|
+
# @return [DSL]
|
269
|
+
#
|
270
|
+
# @api public
|
271
|
+
def after(key, &block)
|
272
|
+
steps.after(key, &block)
|
273
|
+
self
|
274
|
+
end
|
275
|
+
|
276
|
+
# The parent (last from parents) which is used for copying non mergeable configuration
|
277
|
+
#
|
278
|
+
# @return DSL
|
279
|
+
#
|
280
|
+
# @api public
|
281
|
+
def parent
|
282
|
+
@parent ||= parents.last
|
216
283
|
end
|
217
284
|
|
218
285
|
# Return type schema used by the value coercer
|
@@ -221,8 +288,9 @@ module Dry
|
|
221
288
|
#
|
222
289
|
# @api private
|
223
290
|
def type_schema
|
224
|
-
|
225
|
-
|
291
|
+
our_schema = type_registry["hash"].schema(types).lax
|
292
|
+
schemas = [*parents.map(&:type_schema), our_schema]
|
293
|
+
schemas.inject { |result, schema| result.schema(schema.to_a) }
|
226
294
|
end
|
227
295
|
|
228
296
|
# Return a new DSL instance using the same processor type
|
@@ -230,8 +298,8 @@ module Dry
|
|
230
298
|
# @return [Dry::Types::Safe]
|
231
299
|
#
|
232
300
|
# @api private
|
233
|
-
def new(options
|
234
|
-
self.class.new(options
|
301
|
+
def new(**options, &block)
|
302
|
+
self.class.new(**options, processor_type: processor_type, config: config, &block)
|
235
303
|
end
|
236
304
|
|
237
305
|
# Set a type for the given key name
|
@@ -244,11 +312,20 @@ module Dry
|
|
244
312
|
# @api private
|
245
313
|
def set_type(name, spec)
|
246
314
|
type = resolve_type(spec)
|
247
|
-
meta = {
|
315
|
+
meta = {required: false, maybe: type.optional?}
|
248
316
|
|
249
317
|
types[name] = type.meta(meta)
|
250
318
|
end
|
251
319
|
|
320
|
+
# Check if a custom type was set under provided key name
|
321
|
+
#
|
322
|
+
# @return [Bool]
|
323
|
+
#
|
324
|
+
# @api private
|
325
|
+
def custom_type?(name)
|
326
|
+
!types[name].meta[:default].equal?(true)
|
327
|
+
end
|
328
|
+
|
252
329
|
# Resolve type object from the provided spec
|
253
330
|
#
|
254
331
|
# @param [Symbol, Array<Symbol>, Dry::Types::Type] spec
|
@@ -276,14 +353,18 @@ module Dry
|
|
276
353
|
#
|
277
354
|
# @api private
|
278
355
|
def filter_schema_dsl
|
279
|
-
@filter_schema_dsl ||= new(parent:
|
356
|
+
@filter_schema_dsl ||= new(parent: parent_filter_schemas)
|
280
357
|
end
|
281
358
|
|
282
359
|
# Check if any filter rules were defined
|
283
360
|
#
|
284
361
|
# @api private
|
285
362
|
def filter_rules?
|
286
|
-
|
363
|
+
if instance_variable_defined?("@filter_schema_dsl") && !filter_schema_dsl.macros.empty?
|
364
|
+
return true
|
365
|
+
end
|
366
|
+
|
367
|
+
parents.any?(&:filter_rules?)
|
287
368
|
end
|
288
369
|
|
289
370
|
protected
|
@@ -323,10 +404,17 @@ module Dry
|
|
323
404
|
private
|
324
405
|
|
325
406
|
# @api private
|
326
|
-
def
|
327
|
-
|
407
|
+
def parent_filter_schemas
|
408
|
+
parents.select(&:filter_rules?).map(&:filter_schema)
|
409
|
+
end
|
328
410
|
|
329
|
-
|
411
|
+
# Build a key validator
|
412
|
+
#
|
413
|
+
# @return [KeyValidator]
|
414
|
+
#
|
415
|
+
# @api private
|
416
|
+
def key_validator
|
417
|
+
KeyValidator.new(key_map: key_map + parent_key_map)
|
330
418
|
end
|
331
419
|
|
332
420
|
# Build a key coercer
|
@@ -366,13 +454,19 @@ module Dry
|
|
366
454
|
|
367
455
|
# Build a key spec needed by the key map
|
368
456
|
#
|
457
|
+
# TODO: we need a key-map compiler using Types AST
|
458
|
+
#
|
369
459
|
# @api private
|
370
460
|
def key_spec(name, type)
|
371
461
|
if type.respond_to?(:keys)
|
372
|
-
{
|
462
|
+
{name => key_map(type.name_key_map)}
|
373
463
|
elsif type.respond_to?(:member)
|
374
464
|
kv = key_spec(name, type.member)
|
375
465
|
kv.equal?(name) ? name : kv.flatten(1)
|
466
|
+
elsif type.meta[:maybe] && type.respond_to?(:right)
|
467
|
+
key_spec(name, type.right)
|
468
|
+
elsif type.respond_to?(:type)
|
469
|
+
key_spec(name, type.type)
|
376
470
|
else
|
377
471
|
name
|
378
472
|
end
|
@@ -380,12 +474,24 @@ module Dry
|
|
380
474
|
|
381
475
|
# @api private
|
382
476
|
def parent_rules
|
383
|
-
parent
|
477
|
+
parents.reduce({}) { |rules, parent| rules.merge(parent.rules) }
|
384
478
|
end
|
385
479
|
|
386
480
|
# @api private
|
387
481
|
def parent_key_map
|
388
|
-
parent
|
482
|
+
parents.reduce([]) { |key_map, parent| parent.key_map + key_map }
|
483
|
+
end
|
484
|
+
|
485
|
+
# @api private
|
486
|
+
def default_config
|
487
|
+
parents.each_cons(2) do |left, right|
|
488
|
+
unless left.config == right.config
|
489
|
+
raise ArgumentError,
|
490
|
+
"Parent configs differ, left=#{left.inspect}, right=#{right.inspect}"
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
(parent || Schema).config.dup
|
389
495
|
end
|
390
496
|
end
|
391
497
|
end
|