dry-schema 1.3.1 → 1.4.1
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 +174 -107
- data/README.md +3 -1
- data/config/errors.yml +9 -0
- data/lib/dry/schema/constants.rb +3 -2
- data/lib/dry/schema/dsl.rb +63 -16
- data/lib/dry/schema/macros/dsl.rb +21 -4
- data/lib/dry/schema/macros/filled.rb +0 -7
- data/lib/dry/schema/macros/key.rb +0 -1
- data/lib/dry/schema/macros/schema.rb +2 -7
- data/lib/dry/schema/macros/value.rb +21 -2
- data/lib/dry/schema/message_compiler.rb +2 -1
- data/lib/dry/schema/messages/abstract.rb +42 -12
- data/lib/dry/schema/messages/i18n.rb +9 -0
- data/lib/dry/schema/messages/namespaced.rb +6 -1
- data/lib/dry/schema/messages/yaml.rb +12 -0
- data/lib/dry/schema/namespaced_rule.rb +2 -1
- data/lib/dry/schema/predicate_registry.rb +2 -23
- data/lib/dry/schema/processor.rb +9 -26
- data/lib/dry/schema/processor_steps.rb +116 -0
- data/lib/dry/schema/type_registry.rb +2 -2
- data/lib/dry/schema/version.rb +1 -1
- metadata +5 -5
- data/lib/dry/schema/primitive_inferrer.rb +0 -98
@@ -1,35 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'dry/logic/predicates'
|
4
|
+
require 'dry/types/predicate_registry'
|
4
5
|
|
5
6
|
module Dry
|
6
7
|
module Schema
|
7
8
|
# A registry with predicate objects from `Dry::Logic::Predicates`
|
8
9
|
#
|
9
10
|
# @api private
|
10
|
-
class PredicateRegistry
|
11
|
-
# @api private
|
12
|
-
attr_reader :predicates
|
13
|
-
|
14
|
-
# @api private
|
15
|
-
attr_reader :has_predicate
|
16
|
-
|
17
|
-
# @api private
|
18
|
-
def initialize(predicates = Dry::Logic::Predicates)
|
19
|
-
@predicates = predicates
|
20
|
-
@has_predicate = ::Kernel.instance_method(:respond_to?).bind(@predicates)
|
21
|
-
end
|
22
|
-
|
23
|
-
# @api private
|
24
|
-
def [](name)
|
25
|
-
predicates[name]
|
26
|
-
end
|
27
|
-
|
28
|
-
# @api private
|
29
|
-
def key?(name)
|
30
|
-
has_predicate.(name)
|
31
|
-
end
|
32
|
-
|
11
|
+
class PredicateRegistry < Dry::Types::PredicateRegistry
|
33
12
|
# @api private
|
34
13
|
def arg_list(name, *values)
|
35
14
|
predicate = self[name]
|
data/lib/dry/schema/processor.rb
CHANGED
@@ -5,6 +5,7 @@ require 'dry/initializer'
|
|
5
5
|
|
6
6
|
require 'dry/schema/type_registry'
|
7
7
|
require 'dry/schema/type_container'
|
8
|
+
require 'dry/schema/processor_steps'
|
8
9
|
require 'dry/schema/rule_applier'
|
9
10
|
require 'dry/schema/key_coercer'
|
10
11
|
require 'dry/schema/value_coercer'
|
@@ -12,14 +13,9 @@ require 'dry/schema/value_coercer'
|
|
12
13
|
module Dry
|
13
14
|
module Schema
|
14
15
|
# Processes input data using objects configured within the DSL
|
16
|
+
# Processing is split into steps represented by `ProcessorSteps`.
|
15
17
|
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# 1. Prepare input hash using a key map
|
19
|
-
# 2. Apply pre-coercion filtering rules (optional step, used only when `filter` was used)
|
20
|
-
# 3. Apply value coercions based on type specifications
|
21
|
-
# 4. Apply rules
|
22
|
-
#
|
18
|
+
# @see ProcessorSteps
|
23
19
|
# @see Params
|
24
20
|
# @see JSON
|
25
21
|
#
|
@@ -29,10 +25,10 @@ module Dry
|
|
29
25
|
extend Dry::Configurable
|
30
26
|
|
31
27
|
setting :key_map_type
|
32
|
-
setting :type_registry_namespace, :
|
28
|
+
setting :type_registry_namespace, :strict
|
33
29
|
setting :filter_empty_string, false
|
34
30
|
|
35
|
-
option :steps, default: -> {
|
31
|
+
option :steps, default: -> { ProcessorSteps.new }
|
36
32
|
|
37
33
|
option :schema_dsl
|
38
34
|
|
@@ -77,16 +73,6 @@ module Dry
|
|
77
73
|
end
|
78
74
|
end
|
79
75
|
|
80
|
-
# Append a step
|
81
|
-
#
|
82
|
-
# @return [Processor]
|
83
|
-
#
|
84
|
-
# @api private
|
85
|
-
def <<(step)
|
86
|
-
steps << step
|
87
|
-
self
|
88
|
-
end
|
89
|
-
|
90
76
|
# Apply processing steps to the provided input
|
91
77
|
#
|
92
78
|
# @param [Hash] input
|
@@ -96,10 +82,7 @@ module Dry
|
|
96
82
|
# @api public
|
97
83
|
def call(input)
|
98
84
|
Result.new(input, message_compiler: message_compiler) do |result|
|
99
|
-
steps.
|
100
|
-
output = step.(result)
|
101
|
-
result.replace(output) if output.is_a?(::Hash)
|
102
|
-
end
|
85
|
+
steps.call(result)
|
103
86
|
end
|
104
87
|
end
|
105
88
|
alias_method :[], :call
|
@@ -119,7 +102,7 @@ module Dry
|
|
119
102
|
#
|
120
103
|
# @api public
|
121
104
|
def key_map
|
122
|
-
|
105
|
+
steps[:key_coercer].key_map
|
123
106
|
end
|
124
107
|
|
125
108
|
# Return string represntation
|
@@ -139,7 +122,7 @@ module Dry
|
|
139
122
|
#
|
140
123
|
# @api private
|
141
124
|
def type_schema
|
142
|
-
|
125
|
+
steps[:value_coercer].type_schema
|
143
126
|
end
|
144
127
|
|
145
128
|
# Return the rules config
|
@@ -180,7 +163,7 @@ module Dry
|
|
180
163
|
#
|
181
164
|
# @api private
|
182
165
|
def rule_applier
|
183
|
-
|
166
|
+
steps[:rule_applier]
|
184
167
|
end
|
185
168
|
alias_method :to_rule, :rule_applier
|
186
169
|
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/initializer'
|
4
|
+
|
5
|
+
module Dry
|
6
|
+
module Schema
|
7
|
+
# Steps for the Dry::Schema::Processor
|
8
|
+
#
|
9
|
+
# There are 4 main steps:
|
10
|
+
#
|
11
|
+
# 1. `key_coercer` - Prepare input hash using a key map
|
12
|
+
# 2. `filter_schema` - Apply pre-coercion filtering rules
|
13
|
+
# (optional step, used only when `filter` was used)
|
14
|
+
# 3. `value_coercer` - Apply value coercions based on type specifications
|
15
|
+
# 4. `rule_applier` - Apply rules
|
16
|
+
#
|
17
|
+
# @see Processor
|
18
|
+
#
|
19
|
+
# @api public
|
20
|
+
class ProcessorSteps
|
21
|
+
extend Dry::Initializer
|
22
|
+
|
23
|
+
STEPS_IN_ORDER = %i[key_coercer filter_schema value_coercer rule_applier].freeze
|
24
|
+
|
25
|
+
option :steps, default: -> { EMPTY_HASH.dup }
|
26
|
+
option :before_steps, default: -> { EMPTY_HASH.dup }
|
27
|
+
option :after_steps, default: -> { EMPTY_HASH.dup }
|
28
|
+
|
29
|
+
# Executes steps and callbacks in order
|
30
|
+
#
|
31
|
+
# @param [Result] result
|
32
|
+
#
|
33
|
+
# @return [Result]
|
34
|
+
#
|
35
|
+
# @api public
|
36
|
+
def call(result)
|
37
|
+
STEPS_IN_ORDER.each do |name|
|
38
|
+
before_steps[name]&.each { |step| process_step(step, result) }
|
39
|
+
process_step(steps[name], result)
|
40
|
+
after_steps[name]&.each { |step| process_step(step, result) }
|
41
|
+
end
|
42
|
+
result
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns step by name
|
46
|
+
#
|
47
|
+
# @param [Symbol] name The step name
|
48
|
+
#
|
49
|
+
# @api public
|
50
|
+
def [](name)
|
51
|
+
steps[name]
|
52
|
+
end
|
53
|
+
|
54
|
+
# Sets step by name
|
55
|
+
#
|
56
|
+
# @param [Symbol] name The step name
|
57
|
+
#
|
58
|
+
# @api public
|
59
|
+
def []=(name, value)
|
60
|
+
validate_step_name(name)
|
61
|
+
steps[name] = value
|
62
|
+
end
|
63
|
+
|
64
|
+
# Add passed block before mentioned step
|
65
|
+
#
|
66
|
+
# @param [Symbol] name The step name
|
67
|
+
#
|
68
|
+
# @return [ProcessorSteps]
|
69
|
+
#
|
70
|
+
# @api public
|
71
|
+
def after(name, &block)
|
72
|
+
validate_step_name(name)
|
73
|
+
after_steps[name] ||= EMPTY_ARRAY.dup
|
74
|
+
after_steps[name] << block.to_proc
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
# Add passed block before mentioned step
|
79
|
+
#
|
80
|
+
# @param [Symbol] name The step name
|
81
|
+
#
|
82
|
+
# @return [ProcessorSteps]
|
83
|
+
#
|
84
|
+
# @api public
|
85
|
+
def before(name, &block)
|
86
|
+
validate_step_name(name)
|
87
|
+
before_steps[name] ||= EMPTY_ARRAY.dup
|
88
|
+
before_steps[name] << block.to_proc
|
89
|
+
self
|
90
|
+
end
|
91
|
+
|
92
|
+
# @api private
|
93
|
+
def process_step(step, result)
|
94
|
+
return unless step
|
95
|
+
|
96
|
+
output = step.(result)
|
97
|
+
result.replace(output) if output.is_a?(::Hash)
|
98
|
+
end
|
99
|
+
|
100
|
+
# @api private
|
101
|
+
def validate_step_name(name)
|
102
|
+
return if STEPS_IN_ORDER.include?(name)
|
103
|
+
|
104
|
+
raise ArgumentError, "Undefined step name #{name}. Available names: #{STEPS_IN_ORDER}"
|
105
|
+
end
|
106
|
+
|
107
|
+
# @api private
|
108
|
+
def initialize_copy(source)
|
109
|
+
super
|
110
|
+
@steps = source.steps.dup
|
111
|
+
@before_steps = source.before_steps.dup
|
112
|
+
@after_steps = source.after_steps.dup
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -18,12 +18,12 @@ module Dry
|
|
18
18
|
attr_reader :namespace
|
19
19
|
|
20
20
|
# @api private
|
21
|
-
def self.new(types = Dry::Types, namespace = :
|
21
|
+
def self.new(types = Dry::Types, namespace = :strict)
|
22
22
|
super
|
23
23
|
end
|
24
24
|
|
25
25
|
# @api private
|
26
|
-
def initialize(types, namespace = :
|
26
|
+
def initialize(types, namespace = :strict)
|
27
27
|
@types = types
|
28
28
|
@namespace = namespace
|
29
29
|
end
|
data/lib/dry/schema/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-schema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-10-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -106,14 +106,14 @@ dependencies:
|
|
106
106
|
requirements:
|
107
107
|
- - "~>"
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: '1.
|
109
|
+
version: '1.2'
|
110
110
|
type: :runtime
|
111
111
|
prerelease: false
|
112
112
|
version_requirements: !ruby/object:Gem::Requirement
|
113
113
|
requirements:
|
114
114
|
- - "~>"
|
115
115
|
- !ruby/object:Gem::Version
|
116
|
-
version: '1.
|
116
|
+
version: '1.2'
|
117
117
|
- !ruby/object:Gem::Dependency
|
118
118
|
name: bundler
|
119
119
|
requirement: !ruby/object:Gem::Requirement
|
@@ -217,8 +217,8 @@ files:
|
|
217
217
|
- lib/dry/schema/predicate.rb
|
218
218
|
- lib/dry/schema/predicate_inferrer.rb
|
219
219
|
- lib/dry/schema/predicate_registry.rb
|
220
|
-
- lib/dry/schema/primitive_inferrer.rb
|
221
220
|
- lib/dry/schema/processor.rb
|
221
|
+
- lib/dry/schema/processor_steps.rb
|
222
222
|
- lib/dry/schema/result.rb
|
223
223
|
- lib/dry/schema/rule_applier.rb
|
224
224
|
- lib/dry/schema/trace.rb
|
@@ -1,98 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'dry/core/cache'
|
4
|
-
|
5
|
-
module Dry
|
6
|
-
module Schema
|
7
|
-
# PrimitiveInferrer is used internally by `Macros::Filled`
|
8
|
-
# for inferring a list of possible primitives that a given
|
9
|
-
# type can handle.
|
10
|
-
#
|
11
|
-
# @api private
|
12
|
-
class PrimitiveInferrer
|
13
|
-
extend Dry::Core::Cache
|
14
|
-
|
15
|
-
# Compiler reduces type AST into a list of primitives
|
16
|
-
#
|
17
|
-
# @api private
|
18
|
-
class Compiler
|
19
|
-
# @api private
|
20
|
-
def visit(node)
|
21
|
-
meth, rest = node
|
22
|
-
public_send(:"visit_#{meth}", rest)
|
23
|
-
end
|
24
|
-
|
25
|
-
# @api private
|
26
|
-
def visit_nominal(node)
|
27
|
-
type, _ = node
|
28
|
-
type
|
29
|
-
end
|
30
|
-
|
31
|
-
# @api private
|
32
|
-
def visit_hash(_)
|
33
|
-
Hash
|
34
|
-
end
|
35
|
-
|
36
|
-
# @api private
|
37
|
-
def visit_array(_)
|
38
|
-
Array
|
39
|
-
end
|
40
|
-
|
41
|
-
# @api private
|
42
|
-
def visit_lax(node)
|
43
|
-
visit(node)
|
44
|
-
end
|
45
|
-
|
46
|
-
# @api private
|
47
|
-
def visit_constructor(node)
|
48
|
-
other, * = node
|
49
|
-
visit(other)
|
50
|
-
end
|
51
|
-
|
52
|
-
# @api private
|
53
|
-
def visit_enum(node)
|
54
|
-
other, * = node
|
55
|
-
visit(other)
|
56
|
-
end
|
57
|
-
|
58
|
-
# @api private
|
59
|
-
def visit_sum(node)
|
60
|
-
left, right = node
|
61
|
-
|
62
|
-
[visit(left), visit(right)].flatten(1)
|
63
|
-
end
|
64
|
-
|
65
|
-
# @api private
|
66
|
-
def visit_constrained(node)
|
67
|
-
other, * = node
|
68
|
-
visit(other)
|
69
|
-
end
|
70
|
-
|
71
|
-
# @api private
|
72
|
-
def visit_any(_)
|
73
|
-
Object
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
# @return [Compiler]
|
78
|
-
# @api private
|
79
|
-
attr_reader :compiler
|
80
|
-
|
81
|
-
# @api private
|
82
|
-
def initialize
|
83
|
-
@compiler = Compiler.new
|
84
|
-
end
|
85
|
-
|
86
|
-
# Infer predicate identifier from the provided type
|
87
|
-
#
|
88
|
-
# @return [Symbol]
|
89
|
-
#
|
90
|
-
# @api private
|
91
|
-
def [](type)
|
92
|
-
self.class.fetch_or_store(type.hash) do
|
93
|
-
Array(compiler.visit(type.to_ast)).freeze
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|