dry-schema 0.1.0 → 1.0.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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +166 -0
  3. data/LICENSE +1 -1
  4. data/README.md +13 -4
  5. data/config/errors.yml +59 -54
  6. data/lib/dry/schema/compiler.rb +24 -0
  7. data/lib/dry/schema/config.rb +23 -27
  8. data/lib/dry/schema/constants.rb +27 -3
  9. data/lib/dry/schema/dsl.rb +36 -49
  10. data/lib/dry/schema/extensions/hints/compiler_methods.rb +19 -0
  11. data/lib/dry/schema/extensions/hints/message_compiler_methods.rb +84 -0
  12. data/lib/dry/schema/extensions/hints/message_set_methods.rb +44 -0
  13. data/lib/dry/schema/extensions/hints/result_methods.rb +47 -0
  14. data/lib/dry/schema/extensions/hints.rb +56 -0
  15. data/lib/dry/schema/extensions/monads.rb +15 -4
  16. data/lib/dry/schema/extensions.rb +6 -0
  17. data/lib/dry/schema/json.rb +4 -2
  18. data/lib/dry/schema/key.rb +8 -10
  19. data/lib/dry/schema/key_coercer.rb +6 -2
  20. data/lib/dry/schema/key_map.rb +5 -4
  21. data/lib/dry/schema/macros/array.rb +39 -0
  22. data/lib/dry/schema/macros/core.rb +2 -0
  23. data/lib/dry/schema/macros/dsl.rb +149 -4
  24. data/lib/dry/schema/macros/each.rb +12 -1
  25. data/lib/dry/schema/macros/filled.rb +14 -7
  26. data/lib/dry/schema/macros/hash.rb +6 -32
  27. data/lib/dry/schema/macros/key.rb +38 -60
  28. data/lib/dry/schema/macros/maybe.rb +5 -3
  29. data/lib/dry/schema/macros/optional.rb +8 -1
  30. data/lib/dry/schema/macros/required.rb +3 -1
  31. data/lib/dry/schema/macros/schema.rb +46 -0
  32. data/lib/dry/schema/macros/value.rb +18 -2
  33. data/lib/dry/schema/macros.rb +4 -0
  34. data/lib/dry/schema/message/or.rb +54 -0
  35. data/lib/dry/schema/message.rb +56 -72
  36. data/lib/dry/schema/message_compiler/visitor_opts.rb +28 -1
  37. data/lib/dry/schema/message_compiler.rb +85 -74
  38. data/lib/dry/schema/message_set.rb +82 -50
  39. data/lib/dry/schema/messages/abstract.rb +84 -44
  40. data/lib/dry/schema/messages/i18n.rb +45 -9
  41. data/lib/dry/schema/messages/namespaced.rb +22 -5
  42. data/lib/dry/schema/messages/template.rb +68 -0
  43. data/lib/dry/schema/messages/yaml.rb +76 -22
  44. data/lib/dry/schema/messages.rb +19 -24
  45. data/lib/dry/schema/namespaced_rule.rb +37 -0
  46. data/lib/dry/schema/params.rb +4 -2
  47. data/lib/dry/schema/path.rb +102 -0
  48. data/lib/dry/schema/predicate.rb +15 -0
  49. data/lib/dry/schema/predicate_inferrer.rb +116 -23
  50. data/lib/dry/schema/predicate_registry.rb +2 -0
  51. data/lib/dry/schema/processor.rb +70 -39
  52. data/lib/dry/schema/result.rb +16 -31
  53. data/lib/dry/schema/rule_applier.rb +10 -3
  54. data/lib/dry/schema/trace.rb +16 -3
  55. data/lib/dry/schema/type_registry.rb +5 -3
  56. data/lib/dry/schema/types.rb +3 -1
  57. data/lib/dry/schema/value_coercer.rb +10 -4
  58. data/lib/dry/schema/version.rb +3 -1
  59. data/lib/dry/schema.rb +39 -13
  60. data/lib/dry-schema.rb +2 -0
  61. metadata +43 -47
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/logic/operators'
2
4
 
3
5
  require 'dry/schema/macros/core'
@@ -14,10 +16,37 @@ module Dry
14
16
  undef :eql?
15
17
  undef :nil?
16
18
 
17
- # @api private
19
+ # @!attribute [r] chain
20
+ # Indicate if the macro should append its rules to the provided trace
21
+ # @return [Boolean]
22
+ # @api private
18
23
  option :chain, default: -> { true }
19
24
 
20
- # Specify predicates that should be applied to a value
25
+ # @!attribute [r] predicate_inferrer
26
+ # PredicateInferrer is used to infer predicate type-check from a type spec
27
+ # @return [PredicateInferrer]
28
+ # @api private
29
+ option :predicate_inferrer, default: proc { PredicateInferrer.new(compiler.predicates) }
30
+
31
+ # @overload value(*predicates, **predicate_opts)
32
+ # Set predicates without and with arguments
33
+ #
34
+ # @param [Array<Symbol>] predicates
35
+ # @param [Hash] predicate_opts
36
+ #
37
+ # @example with a predicate
38
+ # required(:name).value(:filled?)
39
+ #
40
+ # @example with a predicate with arguments
41
+ # required(:name).value(min_size?: 2)
42
+ #
43
+ # @example with a predicate with and without arguments
44
+ # required(:name).value(:filled?, min_size?: 2)
45
+ #
46
+ # @example with a block
47
+ # required(:name).value { filled? & min_size?(2) }
48
+ #
49
+ # @return [Macros::Core]
21
50
  #
22
51
  # @api public
23
52
  def value(*predicates, **opts, &block)
@@ -28,6 +57,14 @@ module Dry
28
57
 
29
58
  # Prepends `:filled?` predicate
30
59
  #
60
+ # @example with a type spec
61
+ # required(:name).filled(:string)
62
+ #
63
+ # @example with a type spec and a predicate
64
+ # required(:name).filled(:string, format?: /\w+/)
65
+ #
66
+ # @return [Macros::Core]
67
+ #
31
68
  # @api public
32
69
  def filled(*args, &block)
33
70
  append_macro(Macros::Filled) do |macro|
@@ -35,10 +72,35 @@ module Dry
35
72
  end
36
73
  end
37
74
 
38
- # Specify a nested schema
75
+ # Specify a nested hash without enforced `hash?` type-check
76
+ #
77
+ # This is a simpler building block than `hash` macro, use it
78
+ # when you want to provide `hash?` type-check with other rules
79
+ # manually.
80
+ #
81
+ # @example
82
+ # required(:tags).value(:hash, min_size?: 1).schema do
83
+ # required(:name).value(:string)
84
+ # end
85
+ #
86
+ # @return [Macros::Core]
39
87
  #
40
88
  # @api public
41
89
  def schema(*args, &block)
90
+ append_macro(Macros::Schema) do |macro|
91
+ macro.call(*args, &block)
92
+ end
93
+ end
94
+
95
+ # Specify a nested hash with enforced `hash?` type-check
96
+ #
97
+ # @example
98
+ # required(:tags).hash do
99
+ # required(:name).value(:string)
100
+ # end
101
+ #
102
+ # @api public
103
+ def hash(*args, &block)
42
104
  append_macro(Macros::Hash) do |macro|
43
105
  macro.call(*args, &block)
44
106
  end
@@ -46,6 +108,20 @@ module Dry
46
108
 
47
109
  # Specify predicates that should be applied to each element of an array
48
110
  #
111
+ # This is a simpler building block than `array` macro, use it
112
+ # when you want to provide `array?` type-check with other rules
113
+ # manually.
114
+ #
115
+ # @example a list of strings
116
+ # required(:tags).value(:array, min_size?: 2).each(:str?)
117
+ #
118
+ # @example a list of hashes
119
+ # required(:tags).value(:array, min_size?: 2).each(:hash) do
120
+ # required(:name).filled(:string)
121
+ # end
122
+ #
123
+ # @return [Macros::Core]
124
+ #
49
125
  # @api public
50
126
  def each(*args, &block)
51
127
  append_macro(Macros::Each) do |macro|
@@ -53,10 +129,44 @@ module Dry
53
129
  end
54
130
  end
55
131
 
132
+ # Like `each` but sets `array?` type-check
133
+ #
134
+ # @example a list of strings
135
+ # required(:tags).array(:str?)
136
+ #
137
+ # @example a list of hashes
138
+ # required(:tags).array(:hash) do
139
+ # required(:name).filled(:string)
140
+ # end
141
+ #
142
+ # @return [Macros::Core]
143
+ #
144
+ # @api public
145
+ def array(*args, &block)
146
+ append_macro(Macros::Array) do |macro|
147
+ macro.value(*args, &block)
148
+ end
149
+ end
150
+
151
+ # Set type spec
152
+ #
153
+ # @example
154
+ # required(:name).type(:string).value(min_size?: 2)
155
+ #
156
+ # @param [Symbol, Array, Dry::Types::Type] spec
157
+ #
158
+ # @return [Macros::Key]
159
+ #
160
+ # @api public
161
+ def type(spec)
162
+ schema_dsl.set_type(name, spec)
163
+ self
164
+ end
165
+
56
166
  private
57
167
 
58
168
  # @api private
59
- def append_macro(macro_type, &block)
169
+ def append_macro(macro_type)
60
170
  macro = macro_type.new(schema_dsl: schema_dsl, name: name)
61
171
 
62
172
  yield(macro)
@@ -68,6 +178,41 @@ module Dry
68
178
  macro
69
179
  end
70
180
  end
181
+
182
+ # @api private
183
+ def extract_type_spec(*args, nullable: false, set_type: true)
184
+ type_spec = args[0]
185
+
186
+ is_type_spec = type_spec.is_a?(Dry::Schema::Processor) ||
187
+ type_spec.is_a?(Symbol) &&
188
+ type_spec.to_s.end_with?(QUESTION_MARK)
189
+
190
+ type_spec = nil if is_type_spec
191
+
192
+ predicates = Array(type_spec ? args[1..-1] : args)
193
+
194
+ if type_spec
195
+ resolved_type = schema_dsl.resolve_type(
196
+ nullable && !type_spec.is_a?(::Array) ? [:nil, type_spec] : type_spec
197
+ )
198
+
199
+ type(resolved_type) if set_type
200
+
201
+ type_predicates = predicate_inferrer[resolved_type]
202
+
203
+ unless type_predicates.empty? || predicates.include?(type_predicates)
204
+ if type_predicates.is_a?(::Array) && type_predicates.size.equal?(1)
205
+ predicates.unshift(type_predicates[0])
206
+ else
207
+ predicates.unshift(type_predicates)
208
+ end
209
+ end
210
+
211
+ return self if predicates.empty?
212
+ end
213
+
214
+ yield(*predicates, type_spec: type_spec)
215
+ end
71
216
  end
72
217
  end
73
218
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/macros/dsl'
2
4
 
3
5
  module Dry
@@ -5,8 +7,17 @@ module Dry
5
7
  module Macros
6
8
  # Macro used to specify predicates for each element of an array
7
9
  #
8
- # @api public
10
+ # @api private
9
11
  class Each < DSL
12
+ # @api private
13
+ def value(*args, **opts)
14
+ extract_type_spec(*args, set_type: false) do |*predicates, type_spec:|
15
+ type(schema_dsl.array[type_spec]) if type_spec
16
+
17
+ super(*predicates, type_spec: type_spec, **opts)
18
+ end
19
+ end
20
+
10
21
  # @api private
11
22
  def to_ast(*)
12
23
  [:each, trace.to_ast]
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/macros/value'
2
4
 
3
5
  module Dry
@@ -5,18 +7,23 @@ module Dry
5
7
  module Macros
6
8
  # Macro used to prepend `:filled?` predicate
7
9
  #
8
- # @api public
10
+ # @api private
9
11
  class Filled < Value
10
- def call(*args, &block)
11
- if args.include?(:empty?)
12
- raise ::Dry::Schema::InvalidSchemaError, "Using filled with empty? predicate is invalid"
12
+ # @api private
13
+ def call(*predicates, **opts, &block)
14
+ if predicates.include?(:empty?)
15
+ raise ::Dry::Schema::InvalidSchemaError, 'Using filled with empty? predicate is invalid'
13
16
  end
14
17
 
15
- if args.include?(:filled?)
16
- raise ::Dry::Schema::InvalidSchemaError, "Using filled with filled? is redundant"
18
+ if predicates.include?(:filled?)
19
+ raise ::Dry::Schema::InvalidSchemaError, 'Using filled with filled? is redundant'
17
20
  end
18
21
 
19
- value(:filled?, *args, &block)
22
+ if opts[:type_spec]
23
+ value(predicates[0], :filled?, *predicates[1..predicates.size - 1], **opts, &block)
24
+ else
25
+ value(:filled?, *predicates, **opts, &block)
26
+ end
20
27
  end
21
28
  end
22
29
  end
@@ -1,44 +1,18 @@
1
- require 'dry/schema/macros/value'
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/schema/macros/schema'
2
4
 
3
5
  module Dry
4
6
  module Schema
5
7
  module Macros
6
8
  # Macro used to specify a nested schema
7
9
  #
8
- # @api public
9
- class Hash < Value
10
+ # @api private
11
+ class Hash < Schema
10
12
  # @api private
11
13
  def call(*args, &block)
12
14
  trace << hash?
13
-
14
- super(*args) unless args.empty?
15
-
16
- if block
17
- definition = schema_dsl.new(&block)
18
-
19
- parent_type = schema_dsl.types[name]
20
- definition_schema = definition.type_schema
21
-
22
- schema_type =
23
- if parent_type.respond_to?(:of)
24
- parent_type.of(definition_schema)
25
- else
26
- definition_schema
27
- end
28
-
29
- final_type =
30
- if schema_dsl.maybe?(parent_type)
31
- schema_type.optional
32
- else
33
- schema_type
34
- end
35
-
36
- schema_dsl.set_type(name, final_type)
37
-
38
- trace << definition.to_rule
39
- end
40
-
41
- self
15
+ super(*args, &block)
42
16
  end
43
17
  end
44
18
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/predicate_inferrer'
2
4
  require 'dry/schema/processor'
3
5
  require 'dry/schema/macros/dsl'
@@ -6,18 +8,20 @@ require 'dry/schema/constants'
6
8
  module Dry
7
9
  module Schema
8
10
  module Macros
9
- # Base macro for specifying rules applied to a value found under the key
10
- #
11
- # @see DSL#key
11
+ # Base macro for specifying rules applied to a value found under a key
12
12
  #
13
13
  # @api public
14
14
  class Key < DSL
15
+ # @return [Schema::DSL]
16
+ # @api private
15
17
  option :filter_schema, optional: true, default: proc { schema_dsl&.new }
16
18
 
17
- # Specify predicates that should be used to filter out values
18
- # before coercion is applied
19
+ # Specify predicates that should be applied before coercion
19
20
  #
20
- # @see Macros::DSL#value
21
+ # @example check format before coercing to a date
22
+ # required(:publish_date).filter(format?: /\d{4}-\d{2}-\d{2}).value(:date)
23
+ #
24
+ # @see Macros::Key#value
21
25
  #
22
26
  # @return [Macros::Key]
23
27
  #
@@ -27,59 +31,67 @@ module Dry
27
31
  self
28
32
  end
29
33
 
30
- # Set type specification and predicates
34
+ # @overload value(type_spec, *predicates, **predicate_opts)
35
+ # Set type specification and predicates
31
36
  #
32
- # @see Macros::DSL#value
37
+ # @param [Symbol,Types::Type,Array] type_spec
38
+ # @param [Array<Symbol>] predicates
39
+ # @param [Hash] predicate_opts
40
+ #
41
+ # @example with a predicate
42
+ # required(:name).value(:string, :filled?)
43
+ #
44
+ # @example with a predicate with arguments
45
+ # required(:name).value(:string, min_size?: 2)
46
+ #
47
+ # @example with a block
48
+ # required(:name).value(:string) { filled? & min_size?(2) }
33
49
  #
34
50
  # @return [Macros::Key]
35
51
  #
52
+ # @see Macros::DSL#value
53
+ #
36
54
  # @api public
37
55
  def value(*args, **opts, &block)
38
- extract_type_spec(*args) do |*predicates|
56
+ extract_type_spec(*args) do |*predicates, type_spec:|
39
57
  super(*predicates, **opts, &block)
40
58
  end
41
59
  end
42
60
 
43
61
  # Set type specification and predicates for a filled value
44
62
  #
45
- # @see Macros::DSL#value
63
+ # @example
64
+ # required(:name).filled(:string)
65
+ #
66
+ # @see Macros::Key#value
46
67
  #
47
68
  # @return [Macros::Key]
48
69
  #
49
70
  # @api public
50
71
  def filled(*args, **opts, &block)
51
- extract_type_spec(*args) do |*predicates|
52
- super(*predicates, **opts, &block)
72
+ extract_type_spec(*args) do |*predicates, type_spec:|
73
+ super(*predicates, type_spec: type_spec, **opts, &block)
53
74
  end
54
75
  end
55
76
 
56
77
  # Set type specification and predicates for a maybe value
57
78
  #
58
- # @see Macros::DSL#value
79
+ # @example
80
+ # required(:name).maybe(:string)
81
+ #
82
+ # @see Macros::Key#value
59
83
  #
60
84
  # @return [Macros::Key]
61
85
  #
62
86
  # @api public
63
87
  def maybe(*args, **opts, &block)
64
- extract_type_spec(*args, nullable: true) do |*predicates|
88
+ extract_type_spec(*args, nullable: true) do |*predicates, type_spec:|
65
89
  append_macro(Macros::Maybe) do |macro|
66
90
  macro.call(*predicates, **opts, &block)
67
91
  end
68
92
  end
69
93
  end
70
94
 
71
- # Set type spec
72
- #
73
- # @param [Symbol, Array, Dry::Types::Type]
74
- #
75
- # @return [Macros::Key]
76
- #
77
- # @api public
78
- def type(spec)
79
- schema_dsl.set_type(name, spec)
80
- self
81
- end
82
-
83
95
  # Coerce macro to a rule
84
96
  #
85
97
  # @return [Dry::Logic::Rule]
@@ -97,40 +109,6 @@ module Dry
97
109
  def to_ast
98
110
  [:predicate, [:key?, [[:name, name], [:input, Undefined]]]]
99
111
  end
100
-
101
- private
102
-
103
- # @api private
104
- def extract_type_spec(*args, nullable: false)
105
- type_spec = args[0]
106
-
107
- if type_spec.kind_of?(Schema::Processor) || type_spec.is_a?(Symbol) && type_spec.to_s.end_with?(QUESTION_MARK)
108
- type_spec = nil
109
- end
110
-
111
- predicates = Array(type_spec ? args[1..-1] : args)
112
-
113
- if type_spec
114
- type(nullable && !type_spec.is_a?(::Array) ? [:nil, type_spec] : type_spec)
115
- type_predicates = PredicateInferrer[schema_dsl.types[name]]
116
-
117
- unless predicates.include?(type_predicates)
118
- type_predicates.each do |pred|
119
- unless compiler.supports?(pred)
120
- raise ArgumentError, "Predicate +#{pred.inspect}+ inferred from #{type_spec.inspect} type spec is not supported"
121
- end
122
- end
123
-
124
- if type_predicates.size.equal?(1)
125
- predicates.unshift(type_predicates[0])
126
- else
127
- predicates.unshift(type_predicates)
128
- end
129
- end
130
- end
131
-
132
- yield(*predicates)
133
- end
134
112
  end
135
113
  end
136
114
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/macros/dsl'
2
4
 
3
5
  module Dry
@@ -5,16 +7,16 @@ module Dry
5
7
  module Macros
6
8
  # Macro used to specify predicates for a value that can be `nil`
7
9
  #
8
- # @api public
10
+ # @api private
9
11
  class Maybe < DSL
10
12
  # @api private
11
13
  def call(*args, **opts, &block)
12
14
  if args.include?(:empty?)
13
- raise ::Dry::Schema::InvalidSchemaError, "Using maybe with empty? predicate is invalid"
15
+ raise ::Dry::Schema::InvalidSchemaError, 'Using maybe with empty? predicate is invalid'
14
16
  end
15
17
 
16
18
  if args.include?(:nil?)
17
- raise ::Dry::Schema::InvalidSchemaError, "Using maybe with nil? predicate is redundant"
19
+ raise ::Dry::Schema::InvalidSchemaError, 'Using maybe with nil? predicate is redundant'
18
20
  end
19
21
 
20
22
  value(*args, **opts, &block)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/macros/key'
2
4
 
3
5
  module Dry
@@ -5,12 +7,17 @@ module Dry
5
7
  module Macros
6
8
  # A Key specialization used for keys that can be skipped
7
9
  #
8
- # @api public
10
+ # @api private
9
11
  class Optional < Key
10
12
  # @api private
11
13
  def operation
12
14
  :then
13
15
  end
16
+
17
+ # @api private
18
+ def to_rule
19
+ super unless trace.captures.empty?
20
+ end
14
21
  end
15
22
  end
16
23
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/macros/key'
2
4
 
3
5
  module Dry
@@ -5,7 +7,7 @@ module Dry
5
7
  module Macros
6
8
  # A Key specialization used for keys that must be present
7
9
  #
8
- # @api public
10
+ # @api private
9
11
  class Required < Key
10
12
  # @api private
11
13
  def operation
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/schema/macros/value'
4
+
5
+ module Dry
6
+ module Schema
7
+ module Macros
8
+ # Macro used to specify a nested schema
9
+ #
10
+ # @api private
11
+ class Schema < Value
12
+ # @api private
13
+ def call(*args, &block)
14
+ super(*args) unless args.empty?
15
+
16
+ if block
17
+ definition = schema_dsl.new(&block)
18
+
19
+ parent_type = schema_dsl.types[name]
20
+ definition_schema = definition.type_schema
21
+
22
+ schema_type =
23
+ if parent_type.respond_to?(:of)
24
+ parent_type.of(definition_schema)
25
+ else
26
+ definition_schema
27
+ end
28
+
29
+ final_type =
30
+ if parent_type.optional?
31
+ schema_type.optional
32
+ else
33
+ schema_type
34
+ end
35
+
36
+ schema_dsl.set_type(name, final_type)
37
+
38
+ trace << definition.to_rule
39
+ end
40
+
41
+ self
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/macros/dsl'
2
4
 
3
5
  module Dry
@@ -5,12 +7,26 @@ module Dry
5
7
  module Macros
6
8
  # A macro used for specifying predicates to be applied to values from a hash
7
9
  #
8
- # @api public
10
+ # @api private
9
11
  class Value < DSL
10
12
  # @api private
11
13
  def call(*predicates, **opts, &block)
12
- trace.evaluate(*predicates, **opts, &block)
14
+ schema = predicates.detect { |predicate| predicate.is_a?(Processor) }
15
+
16
+ if schema
17
+ current_type = schema_dsl.types[name]
18
+
19
+ updated_type =
20
+ if current_type.respond_to?(:of)
21
+ current_type.of(schema.type_schema)
22
+ else
23
+ schema.type_schema
24
+ end
25
+
26
+ schema_dsl.set_type(name, updated_type)
27
+ end
13
28
 
29
+ trace.evaluate(*predicates, **opts)
14
30
  trace.append(new(chain: false).instance_exec(&block)) if block
15
31
 
16
32
  if trace.captures.empty?
@@ -1,5 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/schema/macros/array'
1
4
  require 'dry/schema/macros/each'
2
5
  require 'dry/schema/macros/filled'
6
+ require 'dry/schema/macros/schema'
3
7
  require 'dry/schema/macros/hash'
4
8
  require 'dry/schema/macros/maybe'
5
9
  require 'dry/schema/macros/optional'
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/equalizer'
4
+
5
+ module Dry
6
+ module Schema
7
+ # Message objects used by message sets
8
+ #
9
+ # @api public
10
+ class Message
11
+ # A message sub-type used by OR operations
12
+ #
13
+ # @api public
14
+ class Or
15
+ # @api private
16
+ attr_reader :left
17
+
18
+ # @api private
19
+ attr_reader :right
20
+
21
+ # @api private
22
+ attr_reader :path
23
+
24
+ # @api private
25
+ attr_reader :messages
26
+
27
+ # @api private
28
+ def initialize(left, right, messages)
29
+ @left = left
30
+ @right = right
31
+ @messages = messages
32
+ @path = left.path
33
+ end
34
+
35
+ # Dump a message into a string
36
+ #
37
+ # @see Message#dump
38
+ #
39
+ # @return [String]
40
+ #
41
+ # @api public
42
+ def dump
43
+ to_a.map(&:dump).join(" #{messages[:or][:text]} ")
44
+ end
45
+ alias to_s dump
46
+
47
+ # @api private
48
+ def to_a
49
+ [left, right]
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end