dry-schema 1.2.0 → 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.
@@ -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
@@ -29,33 +29,28 @@ module Dry
29
29
  end
30
30
 
31
31
  # @api private
32
- def evaluate(*predicates, **opts)
33
- pred_opts = opts.dup
34
- pred_opts.delete(:type_spec)
35
-
36
- predicates.each do |predicate|
37
- if predicate.respond_to?(:call)
38
- append(predicate)
39
- elsif predicate.is_a?(::Hash)
40
- evaluate_hash_predicates(predicate)
41
- elsif predicate.is_a?(::Array)
42
- append(predicate.map { |pred| __send__(pred) }.reduce(:|))
43
- else
44
- append(__send__(predicate))
45
- end
32
+ def evaluate(*args, type_spec: ::Dry::Schema::Undefined, **opts)
33
+ predicates = opts.empty? ? args : args.push(opts)
34
+ evaluate_predicates(predicates).each do |rule|
35
+ append(rule)
46
36
  end
47
37
 
48
- evaluate_hash_predicates(pred_opts)
49
-
50
38
  self
51
39
  end
52
40
 
53
41
  # @api private
54
- def evaluate_hash_predicates(predicates)
55
- predicates.each do |predicate, *args|
56
- append(__send__(predicate, *args))
42
+ def evaluate_predicates(predicates)
43
+ predicates.flat_map do |predicate|
44
+ if predicate.respond_to?(:call)
45
+ predicate
46
+ elsif predicate.is_a?(::Array)
47
+ predicate.map { |pred| evaluate_predicates(pred).reduce(:&) }.reduce(:|)
48
+ elsif predicate.is_a?(::Hash)
49
+ predicate.map { |pred, *args| __send__(pred, *args) }
50
+ else
51
+ __send__(predicate)
52
+ end
57
53
  end
58
- self
59
54
  end
60
55
 
61
56
  # @api private
@@ -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 = :nominal)
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 = :nominal)
26
+ def initialize(types, namespace = :strict)
27
27
  @types = types
28
28
  @namespace = namespace
29
29
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module Schema
5
- VERSION = '1.2.0'
5
+ VERSION = '1.4.1'
6
6
  end
7
7
  end
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.2.0
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-06-13 00:00:00.000000000 Z
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.0'
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.0'
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