dry-schema 0.3.0 → 0.4.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.
@@ -12,6 +12,7 @@ module Dry
12
12
  extend Dry::Core::Cache
13
13
 
14
14
  TYPE_TO_PREDICATE = {
15
+ DateTime => :date_time?,
15
16
  FalseClass => :false?,
16
17
  Integer => :int?,
17
18
  NilClass => :nil?,
@@ -27,38 +28,68 @@ module Dry
27
28
  #
28
29
  # @api private
29
30
  class Compiler
31
+ # @!attribute [r] registry
32
+ # @return [PredicateRegistry]
33
+ # @api private
34
+ attr_reader :registry
35
+
36
+ # @api private
37
+ def initialize(registry)
38
+ @registry = registry
39
+ end
40
+
41
+ # @api private
42
+ def infer_predicate(type)
43
+ TYPE_TO_PREDICATE.fetch(type) { :"#{type.name.split('::').last.downcase}?" }
44
+ end
45
+
46
+ # @api private
30
47
  def visit(node)
31
48
  meth, rest = node
32
49
  public_send(:"visit_#{meth}", rest)
33
50
  end
34
51
 
35
- def visit_definition(node)
52
+ # @api private
53
+ def visit_nominal(node)
36
54
  type = node[0]
55
+ predicate = infer_predicate(type)
37
56
 
38
- TYPE_TO_PREDICATE.fetch(type) {
39
- :"#{type.name.split('::').last.downcase}?"
40
- }
57
+ if registry.key?(predicate)
58
+ predicate
59
+ else
60
+ { type?: type }
61
+ end
62
+ end
63
+
64
+ # @api private
65
+ def visit_hash(_)
66
+ :hash?
41
67
  end
42
68
 
43
- def visit_array(*)
69
+ # @api private
70
+ def visit_array(_)
44
71
  :array?
45
72
  end
46
73
 
74
+ # @api private
47
75
  def visit_safe(node)
48
76
  other, * = node
49
77
  visit(other)
50
78
  end
51
79
 
80
+ # @api private
52
81
  def visit_constructor(node)
53
82
  other, * = node
54
83
  visit(other)
55
84
  end
56
85
 
86
+ # @api private
57
87
  def visit_enum(node)
58
88
  other, * = node
59
89
  visit(other)
60
90
  end
61
91
 
92
+ # @api private
62
93
  def visit_sum(node)
63
94
  left, right = node
64
95
 
@@ -71,27 +102,38 @@ module Dry
71
102
  end
72
103
  end
73
104
 
105
+ # @api private
74
106
  def visit_constrained(node)
75
107
  other, * = node
76
108
  visit(other)
77
109
  end
78
110
  end
79
111
 
112
+ # @!attribute [r] compiler
113
+ # @return [Compiler]
114
+ # @api private
115
+ attr_reader :compiler
116
+
117
+ # @api private
118
+ def initialize(registry)
119
+ @compiler = Compiler.new(registry)
120
+ end
121
+
80
122
  # Infer predicate identifier from the provided type
81
123
  #
82
124
  # @return [Symbol]
83
125
  #
84
126
  # @api private
85
- def self.[](type)
86
- fetch_or_store(type.hash) {
87
- predicates = Array(compiler.visit(type.to_ast)).flatten
88
- Array(REDUCED_TYPES[predicates] || predicates).flatten
89
- }
90
- end
127
+ def [](type)
128
+ self.class.fetch_or_store(type.hash) do
129
+ predicates = compiler.visit(type.to_ast)
91
130
 
92
- # @api private
93
- def self.compiler
94
- @compiler ||= Compiler.new
131
+ if predicates.is_a?(Hash)
132
+ predicates
133
+ else
134
+ Array(REDUCED_TYPES[predicates] || predicates).flatten
135
+ end
136
+ end
95
137
  end
96
138
  end
97
139
  end
@@ -32,42 +32,41 @@ module Dry
32
32
 
33
33
  param :steps, default: -> { EMPTY_ARRAY.dup }
34
34
 
35
- # Define a schema for your processor class
36
- #
37
- # @see Params
38
- # @see JSON
39
- #
40
- # @return [Class]
41
- #
42
- # @api public
43
- def self.define(&block)
44
- @__definition__ ||= DSL.new(
45
- processor_type: self, parent: superclass.definition, **config, &block
46
- )
47
- self
48
- end
49
-
50
- # Return DSL configured via #define
51
- #
52
- # @return [DSL]
53
- #
54
- # @api private
55
- def self.definition
56
- @__definition__ ||= nil
57
- end
35
+ class << self
36
+ # @!attribute [r] definition
37
+ # Return DSL configured via #define
38
+ # @return [DSL]
39
+ # @api private
40
+ attr_reader :definition
41
+
42
+ # Define a schema for your processor class
43
+ #
44
+ # @see Params
45
+ # @see JSON
46
+ #
47
+ # @return [Class]
48
+ #
49
+ # @api public
50
+ def define(&block)
51
+ @definition ||= DSL.new(
52
+ processor_type: self, parent: superclass.definition, **config, &block
53
+ )
54
+ self
55
+ end
58
56
 
59
- # Build a new processor object
60
- #
61
- # @return [Processor]
62
- #
63
- # @api public
64
- def self.new(&block)
65
- if block
66
- super.tap(&block)
67
- elsif definition
68
- definition.call
69
- else
70
- raise ArgumentError, 'Cannot create a schema without a definition'
57
+ # Build a new processor object
58
+ #
59
+ # @return [Processor]
60
+ #
61
+ # @api public
62
+ def new(&block)
63
+ if block
64
+ super.tap(&block)
65
+ elsif definition
66
+ definition.call
67
+ else
68
+ raise ArgumentError, 'Cannot create a schema without a definition'
69
+ end
71
70
  end
72
71
  end
73
72
 
@@ -96,6 +95,16 @@ module Dry
96
95
  end
97
96
  end
98
97
  end
98
+ alias_method :[], :call
99
+
100
+ # Return a proc that acts like a schema object
101
+ #
102
+ # @return [Proc]
103
+ #
104
+ # @api public
105
+ def to_proc
106
+ ->(input) { call(input) }
107
+ end
99
108
 
100
109
  # Return the key map
101
110
  #
@@ -103,7 +112,18 @@ module Dry
103
112
  #
104
113
  # @api public
105
114
  def key_map
106
- @__key_map__ ||= steps.detect { |s| s.is_a?(KeyCoercer) }.key_map
115
+ @key_map ||= steps.detect { |s| s.is_a?(KeyCoercer) }.key_map
116
+ end
117
+
118
+ # Return string represntation
119
+ #
120
+ # @return [String]
121
+ #
122
+ # @api public
123
+ def inspect
124
+ <<~STR.strip
125
+ #<#{self.class.name} keys=#{key_map.map(&:dump)} rules=#{rules.map { |k, v| [k, v.to_s] }.to_h}>
126
+ STR
107
127
  end
108
128
 
109
129
  # Return the type schema
@@ -112,7 +132,7 @@ module Dry
112
132
  #
113
133
  # @api private
114
134
  def type_schema
115
- @__type_schema__ ||= steps.detect { |s| s.is_a?(ValueCoercer) }.type_schema
135
+ @type_schema ||= steps.detect { |s| s.is_a?(ValueCoercer) }.type_schema
116
136
  end
117
137
 
118
138
  # Return the rules config
@@ -121,7 +141,7 @@ module Dry
121
141
  #
122
142
  # @api private
123
143
  def config
124
- @__config__ ||= steps.detect { |s| s.is_a?(RuleApplier) }.config
144
+ @config ||= rule_applier.config
125
145
  end
126
146
 
127
147
  # Return AST representation of the rules
@@ -153,8 +173,7 @@ module Dry
153
173
  #
154
174
  # @api private
155
175
  def rule_applier
156
- # TODO: make this more explicit through class types
157
- @__rule_applier__ ||= steps.last
176
+ @rule_applier ||= steps.last
158
177
  end
159
178
  alias_method :to_rule, :rule_applier
160
179
  end
@@ -107,7 +107,7 @@ module Dry
107
107
  #
108
108
  # @api public
109
109
  def errors(options = EMPTY_HASH)
110
- message_set(options).dump
110
+ message_set(options)
111
111
  end
112
112
 
113
113
  # Return the message set
@@ -130,7 +130,7 @@ module Dry
130
130
  #
131
131
  # @api public
132
132
  def inspect
133
- "#<#{self.class}#{to_h.inspect} errors=#{errors.inspect}>"
133
+ "#<#{self.class}#{to_h.inspect} errors=#{errors.to_h.inspect}>"
134
134
  end
135
135
 
136
136
  private
@@ -20,10 +20,10 @@ module Dry
20
20
  param :rules
21
21
 
22
22
  # @api private
23
- option :config, default: proc { Config.new }
23
+ option :config, default: -> { Config.new }
24
24
 
25
25
  # @api private
26
- option :message_compiler, default: proc { MessageCompiler.new(Messages.setup(config)) }
26
+ option :message_compiler, default: -> { MessageCompiler.new(Messages.setup(config.messages)) }
27
27
 
28
28
  # @api private
29
29
  def call(input)
@@ -31,6 +31,7 @@ module Dry
31
31
 
32
32
  rules.each do |name, rule|
33
33
  next if input.error?(name)
34
+
34
35
  result = rule.(input)
35
36
  results << result if result.failure?
36
37
  end
@@ -40,8 +41,8 @@ module Dry
40
41
 
41
42
  # @api private
42
43
  def to_ast
43
- if config.namespace
44
- [:namespace, [config.namespace, [:set, rules.values.map(&:to_ast)]]]
44
+ if config.messages.namespace
45
+ [:namespace, [config.messages.namespace, [:set, rules.values.map(&:to_ast)]]]
45
46
  else
46
47
  [:set, rules.values.map(&:to_ast)]
47
48
  end
@@ -29,13 +29,15 @@ module Dry
29
29
  end
30
30
 
31
31
  # @api private
32
- def evaluate(*predicates, **opts, &block)
32
+ def evaluate(*predicates, **opts)
33
33
  pred_opts = opts.dup
34
34
  pred_opts.delete(:type_spec)
35
35
 
36
36
  predicates.each do |predicate|
37
37
  if predicate.respond_to?(:call)
38
38
  append(predicate)
39
+ elsif predicate.is_a?(::Hash)
40
+ evaluate_hash_predicates(predicate)
39
41
  elsif predicate.is_a?(::Array)
40
42
  append(predicate.map { |pred| __send__(pred) }.reduce(:|))
41
43
  else
@@ -43,10 +45,16 @@ module Dry
43
45
  end
44
46
  end
45
47
 
46
- pred_opts.each do |predicate, *args|
48
+ evaluate_hash_predicates(pred_opts)
49
+
50
+ self
51
+ end
52
+
53
+ # @api private
54
+ def evaluate_hash_predicates(predicates)
55
+ predicates.each do |predicate, *args|
47
56
  append(__send__(predicate, *args))
48
57
  end
49
-
50
58
  self
51
59
  end
52
60
 
@@ -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 = nil)
21
+ def self.new(types = Dry::Types, namespace = :nominal)
22
22
  super
23
23
  end
24
24
 
25
25
  # @api private
26
- def initialize(types, namespace = nil)
26
+ def initialize(types, namespace = :nominal)
27
27
  @types = types
28
28
  @namespace = namespace
29
29
  end
@@ -8,7 +8,7 @@ module Dry
8
8
  #
9
9
  # @api public
10
10
  module Types
11
- include Dry::Types.module
11
+ include Dry.Types
12
12
  end
13
13
  end
14
14
  end
@@ -20,9 +20,11 @@ module Dry
20
20
  if input.success?
21
21
  type_schema[Hash(input)]
22
22
  else
23
- type_schema.member_types.reduce(EMPTY_HASH.dup) do |hash, (name, type)|
24
- hash[name] = input.error?(name) ? input[name] : type[input[name]]
25
- hash
23
+ type_schema.each_with_object(EMPTY_HASH.dup) do |key, hash|
24
+ name = key.name
25
+ value = input[name]
26
+
27
+ hash[name] = input.error?(name) ? value : key[value]
26
28
  end
27
29
  end
28
30
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module Schema
5
- VERSION = '0.3.0'
5
+ VERSION = '0.4.0'
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: 0.3.0
4
+ version: 0.4.0
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-03-04 00:00:00.000000000 Z
11
+ date: 2019-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -28,22 +28,22 @@ dependencies:
28
28
  name: dry-configurable
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '0.1'
34
31
  - - ">="
35
32
  - !ruby/object:Gem::Version
36
- version: 0.1.3
33
+ version: 0.8.0
34
+ - - "~>"
35
+ - !ruby/object:Gem::Version
36
+ version: '0.8'
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
- - - "~>"
42
- - !ruby/object:Gem::Version
43
- version: '0.1'
44
41
  - - ">="
45
42
  - !ruby/object:Gem::Version
46
- version: 0.1.3
43
+ version: 0.8.0
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.8'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: dry-core
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -118,20 +118,20 @@ dependencies:
118
118
  requirements:
119
119
  - - ">="
120
120
  - !ruby/object:Gem::Version
121
- version: 0.14.0
121
+ version: 0.15.0
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '0.14'
124
+ version: '0.15'
125
125
  type: :runtime
126
126
  prerelease: false
127
127
  version_requirements: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - ">="
130
130
  - !ruby/object:Gem::Version
131
- version: 0.14.0
131
+ version: 0.15.0
132
132
  - - "~>"
133
133
  - !ruby/object:Gem::Version
134
- version: '0.14'
134
+ version: '0.15'
135
135
  - !ruby/object:Gem::Dependency
136
136
  name: bundler
137
137
  requirement: !ruby/object:Gem::Requirement
@@ -257,7 +257,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
257
257
  - !ruby/object:Gem::Version
258
258
  version: '0'
259
259
  requirements: []
260
- rubygems_version: 3.0.1
260
+ rubygems_version: 3.0.3
261
261
  signing_key:
262
262
  specification_version: 4
263
263
  summary: Schema coercion and validation