dry-schema 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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