dry-validation 0.8.0 → 0.9.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG.md +39 -1
  4. data/benchmarks/benchmark_schema_invalid_huge.rb +52 -0
  5. data/benchmarks/profile_schema_huge_invalid.rb +30 -0
  6. data/config/errors.yml +3 -2
  7. data/dry-validation.gemspec +2 -2
  8. data/lib/dry/validation.rb +20 -32
  9. data/lib/dry/validation/constants.rb +6 -0
  10. data/lib/dry/validation/error.rb +5 -2
  11. data/lib/dry/validation/error_compiler.rb +46 -116
  12. data/lib/dry/validation/executor.rb +105 -0
  13. data/lib/dry/validation/hint_compiler.rb +36 -68
  14. data/lib/dry/validation/message.rb +86 -0
  15. data/lib/dry/validation/message_compiler.rb +141 -0
  16. data/lib/dry/validation/message_set.rb +70 -0
  17. data/lib/dry/validation/messages/abstract.rb +1 -1
  18. data/lib/dry/validation/messages/i18n.rb +5 -0
  19. data/lib/dry/validation/predicate_registry.rb +8 -3
  20. data/lib/dry/validation/result.rb +6 -7
  21. data/lib/dry/validation/schema.rb +21 -227
  22. data/lib/dry/validation/schema/check.rb +1 -1
  23. data/lib/dry/validation/schema/class_interface.rb +193 -0
  24. data/lib/dry/validation/schema/deprecated.rb +1 -2
  25. data/lib/dry/validation/schema/key.rb +4 -0
  26. data/lib/dry/validation/schema/value.rb +12 -7
  27. data/lib/dry/validation/schema_compiler.rb +20 -1
  28. data/lib/dry/validation/type_specs.rb +70 -0
  29. data/lib/dry/validation/version.rb +1 -1
  30. data/spec/fixtures/locales/pl.yml +1 -1
  31. data/spec/integration/custom_predicates_spec.rb +37 -0
  32. data/spec/integration/error_compiler_spec.rb +39 -39
  33. data/spec/integration/form/predicates/key_spec.rb +10 -18
  34. data/spec/integration/form/predicates/size/fixed_spec.rb +8 -12
  35. data/spec/integration/form/predicates/size/range_spec.rb +7 -7
  36. data/spec/integration/hints_spec.rb +17 -0
  37. data/spec/integration/messages/i18n_spec.rb +2 -2
  38. data/spec/integration/schema/check_rules_spec.rb +2 -2
  39. data/spec/integration/schema/defining_base_schema_spec.rb +38 -0
  40. data/spec/integration/schema/dynamic_predicate_args_spec.rb +18 -0
  41. data/spec/integration/schema/macros/each_spec.rb +2 -2
  42. data/spec/integration/schema/macros/input_spec.rb +102 -10
  43. data/spec/integration/schema/macros/maybe_spec.rb +30 -0
  44. data/spec/integration/schema/nested_schemas_spec.rb +200 -0
  45. data/spec/integration/schema/nested_values_spec.rb +3 -1
  46. data/spec/integration/schema/option_with_default_spec.rb +54 -20
  47. data/spec/integration/schema/predicates/size/fixed_spec.rb +10 -10
  48. data/spec/integration/schema/predicates/size/range_spec.rb +8 -10
  49. data/spec/unit/error_compiler_spec.rb +1 -1
  50. data/spec/unit/hint_compiler_spec.rb +2 -2
  51. metadata +18 -7
  52. data/examples/rule_ast.rb +0 -25
  53. data/lib/dry/validation/error_compiler/input.rb +0 -135
@@ -0,0 +1,193 @@
1
+ require 'dry/validation/messages/yaml'
2
+ require 'dry/validation/messages/i18n'
3
+
4
+ require 'dry/validation/type_specs'
5
+
6
+ module Dry
7
+ module Validation
8
+ class Schema
9
+ extend Dry::Configurable
10
+ extend TypeSpecs
11
+
12
+ NOOP_INPUT_PROCESSOR = -> input { input }
13
+
14
+ setting :path
15
+ setting :predicates, Logic::Predicates
16
+ setting :registry
17
+ setting :messages, :yaml
18
+ setting :messages_file
19
+ setting :namespace
20
+ setting :rules, []
21
+ setting :checks, []
22
+ setting :options, {}
23
+ setting :input, nil
24
+ setting :input_rule, nil
25
+ setting :dsl_extensions, nil
26
+
27
+ setting :input_processor_map, {
28
+ sanitizer: InputProcessorCompiler::Sanitizer.new,
29
+ json: InputProcessorCompiler::JSON.new,
30
+ form: InputProcessorCompiler::Form.new,
31
+ }.freeze
32
+
33
+ setting :type_specs, false
34
+
35
+ def self.new(rules = config.rules, **options)
36
+ super(rules, default_options.merge(options))
37
+ end
38
+
39
+ def self.define(options = {}, &block)
40
+ source = options.fetch(:schema_class)
41
+ config = source.config
42
+
43
+ dsl_ext = config.dsl_extensions
44
+
45
+ dsl = Schema::Value.new(options.merge(registry: source.registry))
46
+ dsl_ext.__send__(:extend_object, dsl) if dsl_ext
47
+ dsl.predicates(options[:predicates]) if options.key?(:predicates)
48
+ dsl.instance_exec(&block) if block
49
+
50
+ target = dsl.schema_class
51
+
52
+ if config.input
53
+ config.input_rule = dsl.__send__(:infer_predicates, Array(target.config.input))
54
+ end
55
+
56
+ rules = target.config.rules + (options.fetch(:rules, []) + dsl.rules)
57
+
58
+ target.configure do |cfg|
59
+ cfg.rules = rules
60
+ cfg.checks = cfg.checks + dsl.checks
61
+ cfg.path = dsl.path
62
+ cfg.type_map = target.build_type_map(dsl.type_map) if cfg.type_specs
63
+ end
64
+
65
+ target
66
+ end
67
+
68
+ def self.define!(options = {}, &block)
69
+ define(schema_class: self, &block)
70
+ end
71
+
72
+ def self.predicates(predicate_set = nil)
73
+ if predicate_set
74
+ config.predicates = predicate_set
75
+ set_registry!
76
+ else
77
+ config.predicates
78
+ end
79
+ end
80
+
81
+ def self.option(name, default = nil)
82
+ attr_reader(*name)
83
+ options.update(name => default)
84
+ end
85
+
86
+ def self.create_class(target, other = nil, &block)
87
+ klass =
88
+ if other.is_a?(self)
89
+ Class.new(other.class)
90
+ elsif other.is_a?(Class) && other < Types::Struct
91
+ Validation.Schema(parent: target, build: false) do
92
+ other.schema.each { |attr, type| required(attr).filled(type) }
93
+ end
94
+ elsif other.respond_to?(:schema) && other.schema.is_a?(self)
95
+ Class.new(other.schema.class)
96
+ else
97
+ Validation.Schema(target.schema_class, parent: target, build: false, &block)
98
+ end
99
+
100
+ klass.config.path = target.path if other
101
+ klass.config.input_processor = :noop
102
+
103
+ klass
104
+ end
105
+
106
+ def self.clone
107
+ klass = Class.new(self)
108
+ klass.config.rules = []
109
+ klass.config.registry = registry
110
+ klass
111
+ end
112
+
113
+ def self.to_ast
114
+ [:schema, self]
115
+ end
116
+
117
+ def self.registry
118
+ config.registry
119
+ end
120
+
121
+ def self.type_map
122
+ config.type_map
123
+ end
124
+
125
+ def self.rules
126
+ config.rules
127
+ end
128
+
129
+ def self.options
130
+ config.options
131
+ end
132
+
133
+ def self.messages
134
+ default = default_messages
135
+
136
+ if config.messages_file && config.namespace
137
+ default.merge(config.messages_file).namespaced(config.namespace)
138
+ elsif config.messages_file
139
+ default.merge(config.messages_file)
140
+ elsif config.namespace
141
+ default.namespaced(config.namespace)
142
+ else
143
+ default
144
+ end
145
+ end
146
+
147
+ def self.default_messages
148
+ case config.messages
149
+ when :yaml then Messages.default
150
+ when :i18n then Messages::I18n.new
151
+ else
152
+ raise "+#{config.messages}+ is not a valid messages identifier"
153
+ end
154
+ end
155
+
156
+ def self.error_compiler
157
+ @error_compiler ||= ErrorCompiler.new(messages)
158
+ end
159
+
160
+ def self.hint_compiler
161
+ @hint_compiler ||= HintCompiler.new(messages, rules: rule_ast)
162
+ end
163
+
164
+ def self.rule_ast
165
+ @rule_ast ||= config.rules.map(&:to_ast)
166
+ end
167
+
168
+ def self.default_options
169
+ @default_options ||= { predicate_registry: registry,
170
+ error_compiler: error_compiler,
171
+ hint_compiler: hint_compiler,
172
+ input_processor: input_processor,
173
+ checks: config.checks }
174
+ end
175
+
176
+ def self.inherited(klass)
177
+ super
178
+
179
+ klass.config.options = klass.config.options.dup
180
+
181
+ if registry && self != Schema
182
+ klass.config.registry = registry.new(self)
183
+ else
184
+ klass.set_registry!
185
+ end
186
+ end
187
+
188
+ def self.set_registry!
189
+ config.registry = PredicateRegistry[self, config.predicates]
190
+ end
191
+ end
192
+ end
193
+ end
@@ -9,8 +9,7 @@ module Dry
9
9
  if type_map.is_a?(Dry::Types::Safe) && config.input_processor != :noop
10
10
  type_map
11
11
  elsif type_map.size > 0 && config.input_processor != :noop
12
- lookup_type("hash", config.input_processor)
13
- .public_send(config.hash_type, type_map)
12
+ build_hash_type(type_map)
14
13
  elsif input_processor_compiler
15
14
  input_processor_compiler.(rule_ast)
16
15
  else
@@ -26,6 +26,10 @@ module Dry
26
26
  create_rule([type, [name, value.each(*predicates, &block).to_ast]])
27
27
  end
28
28
 
29
+ def schema(other = nil, &block)
30
+ create_rule([type, [name, value.schema(other, &block).to_ast]])
31
+ end
32
+
29
33
  def hash?(&block)
30
34
  predicate = registry[:hash?]
31
35
 
@@ -18,8 +18,8 @@ module Dry
18
18
  @registry = options[:registry] = schema_class.predicates(mod)
19
19
  end
20
20
 
21
- def input(type)
22
- schema_class.config.input = type
21
+ def input(*predicates)
22
+ schema_class.config.input = predicates
23
23
  self
24
24
  end
25
25
 
@@ -115,9 +115,8 @@ module Dry
115
115
  end
116
116
 
117
117
  def configure(&block)
118
- klass = ::Class.new(schema_class, &block)
119
- @schema_class = klass
120
- @registry = klass.registry
118
+ schema_class.class_eval(&block)
119
+ @registry = schema_class.registry
121
120
  self
122
121
  end
123
122
 
@@ -146,7 +145,7 @@ module Dry
146
145
  end
147
146
 
148
147
  def predicate(name, *args)
149
- registry.ensure_valid_predicate(name, args)
148
+ registry.ensure_valid_predicate(name, args, schema_class)
150
149
  registry[name].curry(*args)
151
150
  end
152
151
 
@@ -164,9 +163,13 @@ module Dry
164
163
  end
165
164
  end
166
165
 
166
+ def dyn_arg?(name)
167
+ schema_class.instance_methods.include?(name)
168
+ end
169
+
167
170
  private
168
171
 
169
- def infer_predicates(predicates, infer_on)
172
+ def infer_predicates(predicates, infer_on = self)
170
173
  predicates.map { |predicate|
171
174
  name, *args = ::Kernel.Array(predicate).first
172
175
 
@@ -179,6 +182,8 @@ module Dry
179
182
  end
180
183
 
181
184
  def method_missing(meth, *args, &block)
185
+ return schema_class.instance_method(meth) if dyn_arg?(meth)
186
+
182
187
  val_rule = create_rule([:val, predicate(meth, *args).to_ast])
183
188
 
184
189
  if block
@@ -29,8 +29,27 @@ module Dry
29
29
  end
30
30
 
31
31
  class SchemaCompiler < Logic::RuleCompiler
32
+ attr_reader :schema, :options
33
+
34
+ def initialize(*args, options)
35
+ super(*args)
36
+ @options = options
37
+ @schema = predicates.schema
38
+ end
39
+
40
+ def visit_predicate(node)
41
+ super.evaluate_args!(schema)
42
+ end
43
+
32
44
  def visit_schema(klass)
33
- klass.new
45
+ opt_keys = klass.config.options.keys
46
+ opt_vals = options.values_at(*opt_keys).compact
47
+
48
+ if opt_vals.empty?
49
+ klass.new
50
+ else
51
+ klass.new(klass.config.rules, Hash[opt_keys.zip(opt_vals)])
52
+ end
34
53
  end
35
54
 
36
55
  def visit_guard(node)
@@ -0,0 +1,70 @@
1
+ module Dry
2
+ module Validation
3
+ module TypeSpecs
4
+ def self.extended(klass)
5
+ super
6
+ klass.class_eval do
7
+ setting :input_processor, :noop
8
+ setting :hash_type, :weak
9
+ setting :type_map, {}
10
+ end
11
+ end
12
+
13
+ def build_type_map(type_specs, category = config.input_processor)
14
+ if type_specs.is_a?(Array)
15
+ build_array_type(type_specs[0], category)
16
+ else
17
+ type_specs.reduce({}) { |res, (name, spec)|
18
+ res.update(name => resolve_spec(spec, category))
19
+ }
20
+ end
21
+ end
22
+
23
+ def build_hash_type(spec = type_map)
24
+ lookup_type("hash", config.input_processor)
25
+ .public_send(config.hash_type, spec)
26
+ end
27
+
28
+ def build_array_type(spec, category)
29
+ member_schema = build_type_map(spec, category)
30
+ member_type = lookup_type("hash", category)
31
+ .public_send(config.hash_type, member_schema)
32
+
33
+ lookup_type("array", category).member(member_type)
34
+ end
35
+
36
+ def build_sum_type(spec, category)
37
+ spec
38
+ .map { |id| id.is_a?(Symbol) ? lookup_type(id, category) : id }
39
+ .reduce(:|)
40
+ end
41
+
42
+ def resolve_spec(spec, category)
43
+ case spec
44
+ when Symbol
45
+ lookup_type(spec, category)
46
+ when Hash
47
+ build_hash_type(spec)
48
+ when Array
49
+ if spec.size == 1
50
+ if spec[0].is_a?(Hash)
51
+ build_array_type(spec[0], category)
52
+ else
53
+ array_member = lookup_type(spec[0], category)
54
+ lookup_type("array", category).member(array_member)
55
+ end
56
+ else
57
+ build_sum_type(spec, category)
58
+ end
59
+ else
60
+ spec
61
+ end
62
+ end
63
+
64
+ def lookup_type(name, category)
65
+ id = "#{category}.#{name}"
66
+ Types.type_keys.include?(id) ? Types[id] : Types[name.to_s]
67
+ end
68
+ end
69
+ end
70
+ end
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module Validation
3
- VERSION = '0.8.0'.freeze
3
+ VERSION = '0.9.0'.freeze
4
4
  end
5
5
  end
@@ -4,7 +4,7 @@ pl:
4
4
  size?:
5
5
  arg:
6
6
  default: "wielkość musi być równa %{size}"
7
- range: "wielkość musi być między %{left} a %{right}"
7
+ range: "wielkość musi być między %{size_left} a %{size_right}"
8
8
  rules:
9
9
  email:
10
10
  filled?: "Proszę podać adres email"
@@ -187,4 +187,41 @@ RSpec.describe Dry::Validation do
187
187
 
188
188
  expect(schema.(foo: { bar: "1" })).to be_success
189
189
  end
190
+
191
+ it 'works with interpolation of messages' do
192
+ schema = Dry::Validation.Schema do
193
+ configure do
194
+ option :categories, []
195
+
196
+ def self.messages
197
+ Dry::Validation::Messages.default.merge(
198
+ en: {
199
+ errors: {
200
+ valid_category?: 'must be one of the categories: %{categories}'
201
+ }
202
+ },
203
+ pl: {
204
+ errors: {
205
+ valid_category?: 'musi być jedną z: %{categories}'
206
+ }
207
+ }
208
+ )
209
+ end
210
+
211
+ def valid_category?(categories, value)
212
+ categories.include?(value)
213
+ end
214
+ end
215
+
216
+ required(:category).filled(valid_category?: categories)
217
+ end.with(categories: %w(foo bar))
218
+
219
+ expect(schema.(category: 'baz').messages).to eql(
220
+ category: ['must be one of the categories: foo, bar']
221
+ )
222
+
223
+ expect(schema.(category: 'baz').messages(locale: :pl)).to eql(
224
+ category: ['musi być jedną z: foo, bar']
225
+ )
226
+ end
190
227
  end
@@ -48,7 +48,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
48
48
  end
49
49
 
50
50
  it 'converts error ast into another format' do
51
- expect(error_compiler.(ast)).to eql(
51
+ expect(error_compiler.(ast).to_h).to eql(
52
52
  name: ["+name+ key is missing in the hash"],
53
53
  gender: ["Please provide your gender"],
54
54
  age: ["must be greater than 18"],
@@ -80,7 +80,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
80
80
  end
81
81
 
82
82
  it 'converts error ast into another format' do
83
- expect(error_compiler.(ast)).to eql(
83
+ expect(error_compiler.(ast).to_h).to eql(
84
84
  settings: { newsletter: ['must be false'] }
85
85
  )
86
86
  end
@@ -103,7 +103,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
103
103
  end
104
104
 
105
105
  it 'converts error ast into another format' do
106
- expect(error_compiler.(ast)).to eql(
106
+ expect(error_compiler.(ast).to_h).to eql(
107
107
  payments: { 1 => { method: ['+method+ key is missing in the hash'] } }
108
108
  )
109
109
  end
@@ -116,7 +116,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
116
116
  [:input, [:num, [:result, ['2', [:val, p(:int?)]]]]]
117
117
  )
118
118
 
119
- expect(msg).to eql(num: ['num must be an integer'])
119
+ expect(msg).to eql('num must be an integer')
120
120
  end
121
121
  end
122
122
 
@@ -126,7 +126,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
126
126
  [:input, [:email, [:result, ['oops', [:val, p(:email?)]]]]]
127
127
  )
128
128
 
129
- expect(msg).to eql(email: ['adres email nie jest poprawny'])
129
+ expect(msg).to eql('adres email nie jest poprawny')
130
130
  end
131
131
  end
132
132
 
@@ -136,7 +136,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
136
136
  [:input, [:tags, [:result, [nil, [:val, p(:empty?)]]]]]
137
137
  )
138
138
 
139
- expect(msg).to eql(tags: ['must be empty'])
139
+ expect(msg).to eql('must be empty')
140
140
  end
141
141
  end
142
142
 
@@ -146,7 +146,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
146
146
  [:input, [:num, [:result, [2, [:val, p(:excluded_from?, [1, 2, 3])]]]]]
147
147
  )
148
148
 
149
- expect(msg).to eql(num: ['must not be one of: 1, 2, 3'])
149
+ expect(msg).to eql('must not be one of: 1, 2, 3')
150
150
  end
151
151
  end
152
152
 
@@ -156,7 +156,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
156
156
  [:input, [:array, [:result, [[1, 2, 3], [:val, p(:excludes?, 2)]]]]]
157
157
  )
158
158
 
159
- expect(msg).to eql(array: ['must not include 2'])
159
+ expect(msg).to eql('must not include 2')
160
160
  end
161
161
  end
162
162
 
@@ -166,7 +166,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
166
166
  [:input, [:num, [:result, [2, [:val, p(:included_in?, [1, 2, 3])]]]]]
167
167
  )
168
168
 
169
- expect(msg).to eql(num: ['must be one of: 1, 2, 3'])
169
+ expect(msg).to eql('must be one of: 1, 2, 3')
170
170
  end
171
171
  end
172
172
 
@@ -176,7 +176,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
176
176
  [:input, [:num, [:result, [[1, 2, 3], [:val, p(:includes?, 2)]]]]]
177
177
  )
178
178
 
179
- expect(msg).to eql(num: ['must include 2'])
179
+ expect(msg).to eql('must include 2')
180
180
  end
181
181
  end
182
182
 
@@ -186,7 +186,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
186
186
  [:input, [:num, [:result, [2, [:val, p(:gt?, 3)]]]]]
187
187
  )
188
188
 
189
- expect(msg).to eql(num: ['must be greater than 3'])
189
+ expect(msg).to eql('must be greater than 3')
190
190
  end
191
191
  end
192
192
 
@@ -196,7 +196,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
196
196
  [:input, [:num, [:result, [2, [:val, p(:gteq?, 3)]]]]]
197
197
  )
198
198
 
199
- expect(msg).to eql(num: ['must be greater than or equal to 3'])
199
+ expect(msg).to eql('must be greater than or equal to 3')
200
200
  end
201
201
  end
202
202
 
@@ -206,7 +206,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
206
206
  [:input, [:num, [:result, [2, [:val, p(:lt?, 3)]]]]]
207
207
  )
208
208
 
209
- expect(msg).to eql(num: ['must be less than 3'])
209
+ expect(msg).to eql('must be less than 3')
210
210
  end
211
211
  end
212
212
 
@@ -216,7 +216,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
216
216
  [:input, [:num, [:result, [2, [:val, p(:lteq?, 3)]]]]]
217
217
  )
218
218
 
219
- expect(msg).to eql(num: ['must be less than or equal to 3'])
219
+ expect(msg).to eql('must be less than or equal to 3')
220
220
  end
221
221
  end
222
222
 
@@ -226,7 +226,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
226
226
  [:input, [:address, [:result, ['', [:val, p(:hash?, [])]]]]]
227
227
  )
228
228
 
229
- expect(msg).to eql(address: ['must be a hash'])
229
+ expect(msg).to eql('must be a hash')
230
230
  end
231
231
  end
232
232
 
@@ -236,7 +236,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
236
236
  [:input, [:phone_numbers, [:result, ['', [:val, p(:array?)]]]]]
237
237
  )
238
238
 
239
- expect(msg).to eql(phone_numbers: ['must be an array'])
239
+ expect(msg).to eql('must be an array')
240
240
  end
241
241
  end
242
242
 
@@ -246,7 +246,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
246
246
  [:input, [:num, [:result, ['2', [:val, p(:int?)]]]]]
247
247
  )
248
248
 
249
- expect(msg).to eql(num: ['must be an integer'])
249
+ expect(msg).to eql('must be an integer')
250
250
  end
251
251
  end
252
252
 
@@ -256,7 +256,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
256
256
  [:input, [:num, [:result, ['2', [:val, p(:float?)]]]]]
257
257
  )
258
258
 
259
- expect(msg).to eql(num: ['must be a float'])
259
+ expect(msg).to eql('must be a float')
260
260
  end
261
261
  end
262
262
 
@@ -266,7 +266,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
266
266
  [:input, [:num, [:result, ['2', [:val, p(:decimal?)]]]]]
267
267
  )
268
268
 
269
- expect(msg).to eql(num: ['must be a decimal'])
269
+ expect(msg).to eql('must be a decimal')
270
270
  end
271
271
  end
272
272
 
@@ -276,7 +276,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
276
276
  [:input, [:num, [:result, ['2', [:val, p(:date?)]]]]]
277
277
  )
278
278
 
279
- expect(msg).to eql(num: ['must be a date'])
279
+ expect(msg).to eql('must be a date')
280
280
  end
281
281
  end
282
282
 
@@ -286,7 +286,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
286
286
  [:input, [:num, [:result, ['2', [:val, p(:date_time?)]]]]]
287
287
  )
288
288
 
289
- expect(msg).to eql(num: ['must be a date time'])
289
+ expect(msg).to eql('must be a date time')
290
290
  end
291
291
  end
292
292
 
@@ -296,7 +296,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
296
296
  [:input, [:num, [:result, ['2', [:val, p(:time?)]]]]]
297
297
  )
298
298
 
299
- expect(msg).to eql(num: ['must be a time'])
299
+ expect(msg).to eql('must be a time')
300
300
  end
301
301
  end
302
302
 
@@ -306,7 +306,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
306
306
  [:input, [:num, [:result, ['abcd', [:val, p(:max_size?, 3)]]]]]
307
307
  )
308
308
 
309
- expect(msg).to eql(num: ['size cannot be greater than 3'])
309
+ expect(msg).to eql('size cannot be greater than 3')
310
310
  end
311
311
  end
312
312
 
@@ -316,7 +316,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
316
316
  [:input, [:num, [:result, ['ab', [:val, p(:min_size?, 3)]]]]]
317
317
  )
318
318
 
319
- expect(msg).to eql(num: ['size cannot be less than 3'])
319
+ expect(msg).to eql('size cannot be less than 3')
320
320
  end
321
321
  end
322
322
 
@@ -326,7 +326,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
326
326
  [:input, [:num, [:result, [nil, [:val, p(:none?)]]]]]
327
327
  )
328
328
 
329
- expect(msg).to eql(num: ['cannot be defined'])
329
+ expect(msg).to eql('cannot be defined')
330
330
  end
331
331
  end
332
332
 
@@ -336,7 +336,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
336
336
  [:input, [:numbers, [:result, [[1], [:val, p(:size?, 3)]]]]]
337
337
  )
338
338
 
339
- expect(msg).to eql(numbers: ['size must be 3'])
339
+ expect(msg).to eql('size must be 3')
340
340
  end
341
341
 
342
342
  it 'returns valid message when val is array and arg is range' do
@@ -344,7 +344,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
344
344
  [:input, [:numbers, [:result, [[1], [:val, p(:size?, 3..4)]]]]]
345
345
  )
346
346
 
347
- expect(msg).to eql(numbers: ['size must be within 3 - 4'])
347
+ expect(msg).to eql('size must be within 3 - 4')
348
348
  end
349
349
 
350
350
  it 'returns valid message when arg is int' do
@@ -352,7 +352,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
352
352
  [:input, [:num, [:result, ['ab', [:val, p(:size?, 3)]]]]]
353
353
  )
354
354
 
355
- expect(msg).to eql(num: ['length must be 3'])
355
+ expect(msg).to eql('length must be 3')
356
356
  end
357
357
 
358
358
  it 'returns valid message when arg is range' do
@@ -360,7 +360,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
360
360
  [:input, [:num, [:result, ['ab', [:val, p(:size?, 3..4)]]]]]
361
361
  )
362
362
 
363
- expect(msg).to eql(num: ['length must be within 3 - 4'])
363
+ expect(msg).to eql('length must be within 3 - 4')
364
364
  end
365
365
  end
366
366
 
@@ -370,7 +370,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
370
370
  [:input, [:num, [:result, [3, [:val, p(:str?)]]]]]
371
371
  )
372
372
 
373
- expect(msg).to eql(num: ['must be a string'])
373
+ expect(msg).to eql('must be a string')
374
374
  end
375
375
  end
376
376
 
@@ -380,7 +380,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
380
380
  [:input, [:num, [:result, [3, [:val, p(:bool?)]]]]]
381
381
  )
382
382
 
383
- expect(msg).to eql(num: ['must be boolean'])
383
+ expect(msg).to eql('must be boolean')
384
384
  end
385
385
  end
386
386
 
@@ -390,7 +390,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
390
390
  [:input, [:str, [:result, ['Bar', [:val, p(:format?, /^F/)]]]]]
391
391
  )
392
392
 
393
- expect(msg).to eql(str: ['is in invalid format'])
393
+ expect(msg).to eql('is in invalid format')
394
394
  end
395
395
  end
396
396
 
@@ -400,7 +400,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
400
400
  [:input, [:str, [:result, ["not a number", [:val, p(:number?)]]]]]
401
401
  )
402
402
 
403
- expect(msg).to eql(str: ['must be a number'])
403
+ expect(msg).to eql('must be a number')
404
404
  end
405
405
  end
406
406
 
@@ -410,7 +410,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
410
410
  [:input, [:str, [:result, [1, [:val, p(:odd?)]]]]]
411
411
  )
412
412
 
413
- expect(msg).to eql(str: ['must be odd'])
413
+ expect(msg).to eql('must be odd')
414
414
  end
415
415
  end
416
416
 
@@ -420,7 +420,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
420
420
  [:input, [:str, [:result, [2, [:val, p(:even?)]]]]]
421
421
  )
422
422
 
423
- expect(msg).to eql(str: ['must be even'])
423
+ expect(msg).to eql('must be even')
424
424
  end
425
425
  end
426
426
 
@@ -430,7 +430,7 @@ RSpec.describe Dry::Validation::ErrorCompiler do
430
430
  [:input, [:str, [:result, ['Foo', [:val, p(:eql?, 'Bar')]]]]]
431
431
  )
432
432
 
433
- expect(msg).to eql(str: ['must be equal to Bar'])
433
+ expect(msg).to eql('must be equal to Bar')
434
434
  end
435
435
  end
436
436
 
@@ -440,17 +440,17 @@ RSpec.describe Dry::Validation::ErrorCompiler do
440
440
  [:input, [:str, [:result, ['Foo', [:val, p(:not_eql?, 'Foo')]]]]]
441
441
  )
442
442
 
443
- expect(msg).to eql(str: ['must not be equal to Foo'])
443
+ expect(msg).to eql('must not be equal to Foo')
444
444
  end
445
445
  end
446
446
 
447
- describe ':type??' do
447
+ describe ':type?' do
448
448
  it 'returns valid message' do
449
449
  msg = error_compiler.visit(
450
450
  [:input, [:age, [:result, ['1', [:val, p(:type?, Integer)]]]]]
451
451
  )
452
452
 
453
- expect(msg).to eql(age: ['must be Integer'])
453
+ expect(msg).to eql('must be Integer')
454
454
  end
455
455
  end
456
456
  end