dry-validation 1.4.2 → 1.5.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +65 -0
- data/dry-validation.gemspec +4 -2
- data/lib/dry-validation.rb +1 -1
- data/lib/dry/validation.rb +6 -8
- data/lib/dry/validation/config.rb +2 -2
- data/lib/dry/validation/constants.rb +5 -5
- data/lib/dry/validation/contract.rb +13 -13
- data/lib/dry/validation/contract/class_interface.rb +40 -32
- data/lib/dry/validation/evaluator.rb +31 -11
- data/lib/dry/validation/extensions/hints.rb +1 -3
- data/lib/dry/validation/extensions/monads.rb +1 -1
- data/lib/dry/validation/extensions/predicates_as_macros.rb +2 -2
- data/lib/dry/validation/failures.rb +8 -3
- data/lib/dry/validation/function.rb +2 -2
- data/lib/dry/validation/macro.rb +2 -2
- data/lib/dry/validation/macros.rb +3 -3
- data/lib/dry/validation/message.rb +3 -3
- data/lib/dry/validation/message_set.rb +4 -50
- data/lib/dry/validation/messages/resolver.rb +29 -4
- data/lib/dry/validation/result.rb +15 -8
- data/lib/dry/validation/rule.rb +7 -7
- data/lib/dry/validation/schema_ext.rb +1 -28
- data/lib/dry/validation/values.rb +10 -5
- data/lib/dry/validation/version.rb +1 -1
- metadata +4 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e10a66994158c6865c81439277cbbe57a629189cd20257c500658821dd520431
|
4
|
+
data.tar.gz: 00017e8bc8bf56b4890f5ff441f303556276892681e2c4d732a5ffda52bd54b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4dcb6dba84761e057a2bb72e2b4fbd47bba9c568ee0b1bc52e6b5bd48bbd6e7dc804f418746b7d61b9a98fbaede7be075fe6f2b6610209ec934ca8857a1898c4
|
7
|
+
data.tar.gz: 4a5b3cdd5a6afea0b99a368dc2ce8b244474897692f753e00231b0c77ef4fa7f9ff363b538b1e968ca0a1aa54294efcf0ec44108acaddbcdb1fa267a02ab6b16
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,68 @@
|
|
1
|
+
## 1.5.4 2020-08-21
|
2
|
+
|
3
|
+
|
4
|
+
### Fixed
|
5
|
+
|
6
|
+
- Full messages work correctly with rule failures now (issue #661 fixed via #662) (@stind)
|
7
|
+
- Providing a custom message template for array errors works correctly (issue #663 fixed via #665) (@tadeusz-niemiec)
|
8
|
+
|
9
|
+
|
10
|
+
[Compare v1.5.3...v1.5.4](https://github.com/dry-rb/dry-validation/compare/v1.5.3...v1.5.4)
|
11
|
+
|
12
|
+
## 1.5.3 2020-07-27
|
13
|
+
|
14
|
+
|
15
|
+
### Added
|
16
|
+
|
17
|
+
- You can now access current value's index via `rule(:foo).each do |index:|` (issue #606 done via #657) (@mrbongiolo)
|
18
|
+
|
19
|
+
### Fixed
|
20
|
+
|
21
|
+
- Using `.each(:foo)` works as expected when there are errors related to other keys (issue #659 fixed via #660) (@solnic)
|
22
|
+
|
23
|
+
### Changed
|
24
|
+
|
25
|
+
- `Result#error?` is now a public API and it takes into consideration both schema and rule errors (issue #655 fixed via #656) (@PragTob)
|
26
|
+
|
27
|
+
[Compare v1.5.2...v1.5.3](https://github.com/dry-rb/dry-validation/compare/v1.5.2...v1.5.3)
|
28
|
+
|
29
|
+
## 1.5.2 2020-07-14
|
30
|
+
|
31
|
+
|
32
|
+
### Fixed
|
33
|
+
|
34
|
+
- `key?` predicate in rules no longer crashes when the rule path points to a non-existent array value (issue #653 fixed via #654) (@solnic)
|
35
|
+
|
36
|
+
|
37
|
+
[Compare v1.5.1...v1.5.2](https://github.com/dry-rb/dry-validation/compare/v1.5.1...v1.5.2)
|
38
|
+
|
39
|
+
## 1.5.1 2020-06-18
|
40
|
+
|
41
|
+
|
42
|
+
### Fixed
|
43
|
+
|
44
|
+
- dry-monads no longer required for the `:hints` extension (@schokomarie)
|
45
|
+
- Using `full: true` option works as expected with custom rule messages (issue #618 fixed via #651) (@sirfilip)
|
46
|
+
- Using `locale: ...` option works as expected with hints (issue #589 fixed via 652) (@sirfilip)
|
47
|
+
|
48
|
+
|
49
|
+
[Compare v1.5.0...v1.5.1](https://github.com/dry-rb/dry-validation/compare/v1.5.0...v1.5.1)
|
50
|
+
|
51
|
+
## 1.5.0 2020-03-11
|
52
|
+
|
53
|
+
|
54
|
+
### Added
|
55
|
+
|
56
|
+
- `schema_error?` rule helper (@waiting-for-dev)
|
57
|
+
- `rule_error?` rule helper (@waiting-for-dev)
|
58
|
+
|
59
|
+
### Changed
|
60
|
+
|
61
|
+
- dry-schema dependency was bumped to `~> 1.5` (@solnic)
|
62
|
+
- [internal] `KeyMap` patches have been removed since dry-schema now provides required functionality (@solnic)
|
63
|
+
|
64
|
+
[Compare v1.4.2...v1.5.0](https://github.com/dry-rb/dry-validation/compare/v1.4.2...v1.5.0)
|
65
|
+
|
1
66
|
## 1.4.2 2020-01-18
|
2
67
|
|
3
68
|
|
data/dry-validation.gemspec
CHANGED
@@ -16,6 +16,8 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.description = spec.summary
|
17
17
|
spec.homepage = 'https://dry-rb.org/gems/dry-validation'
|
18
18
|
spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-validation.gemspec", "lib/**/*", "config/*.yml"]
|
19
|
+
spec.bindir = 'bin'
|
20
|
+
spec.executables = []
|
19
21
|
spec.require_paths = ['lib']
|
20
22
|
|
21
23
|
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
@@ -23,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
23
25
|
spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-validation'
|
24
26
|
spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-validation/issues'
|
25
27
|
|
26
|
-
spec.required_ruby_version =
|
28
|
+
spec.required_ruby_version = ">= 2.4.0"
|
27
29
|
|
28
30
|
# to update dependencies edit project.yml
|
29
31
|
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
@@ -31,7 +33,7 @@ Gem::Specification.new do |spec|
|
|
31
33
|
spec.add_runtime_dependency "dry-core", "~> 0.4"
|
32
34
|
spec.add_runtime_dependency "dry-equalizer", "~> 0.2"
|
33
35
|
spec.add_runtime_dependency "dry-initializer", "~> 3.0"
|
34
|
-
spec.add_runtime_dependency "dry-schema", "~> 1.
|
36
|
+
spec.add_runtime_dependency "dry-schema", "~> 1.5"
|
35
37
|
|
36
38
|
spec.add_development_dependency "bundler"
|
37
39
|
spec.add_development_dependency "rake"
|
data/lib/dry-validation.rb
CHANGED
data/lib/dry/validation.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "dry/validation/constants"
|
4
|
+
require "dry/validation/contract"
|
5
|
+
require "dry/validation/macros"
|
6
6
|
|
7
7
|
# Main namespace
|
8
8
|
#
|
@@ -16,15 +16,15 @@ module Dry
|
|
16
16
|
extend Macros::Registrar
|
17
17
|
|
18
18
|
register_extension(:monads) do
|
19
|
-
require
|
19
|
+
require "dry/validation/extensions/monads"
|
20
20
|
end
|
21
21
|
|
22
22
|
register_extension(:hints) do
|
23
|
-
require
|
23
|
+
require "dry/validation/extensions/hints"
|
24
24
|
end
|
25
25
|
|
26
26
|
register_extension(:predicates_as_macros) do
|
27
|
-
require
|
27
|
+
require "dry/validation/extensions/predicates_as_macros"
|
28
28
|
end
|
29
29
|
|
30
30
|
# Define a contract and build its instance
|
@@ -46,11 +46,9 @@ module Dry
|
|
46
46
|
#
|
47
47
|
# @api public
|
48
48
|
#
|
49
|
-
# rubocop:disable Naming/MethodName
|
50
49
|
def self.Contract(options = EMPTY_HASH, &block)
|
51
50
|
Contract.build(options, &block)
|
52
51
|
end
|
53
|
-
# rubocop:enable Naming/MethodName
|
54
52
|
|
55
53
|
# This is needed by Macros::Registrar
|
56
54
|
#
|
@@ -1,22 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "pathname"
|
4
|
+
require "dry/core/constants"
|
5
5
|
|
6
6
|
module Dry
|
7
7
|
module Validation
|
8
8
|
include Dry::Core::Constants
|
9
9
|
|
10
|
-
DOT =
|
10
|
+
DOT = "."
|
11
11
|
|
12
12
|
# Root path is used for base errors in hash representation of error messages
|
13
13
|
ROOT_PATH = [nil].freeze
|
14
14
|
|
15
15
|
# Path to the default errors locale file
|
16
|
-
DEFAULT_ERRORS_NAMESPACE =
|
16
|
+
DEFAULT_ERRORS_NAMESPACE = "dry_validation"
|
17
17
|
|
18
18
|
# Path to the default errors locale file
|
19
|
-
DEFAULT_ERRORS_PATH = Pathname(__FILE__).join(
|
19
|
+
DEFAULT_ERRORS_PATH = Pathname(__FILE__).join("../../../../config/errors.yml").realpath.freeze
|
20
20
|
|
21
21
|
# Mapping for block kwarg options used by block_options
|
22
22
|
#
|
@@ -1,18 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "concurrent/map"
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
5
|
+
require "dry/equalizer"
|
6
|
+
require "dry/initializer"
|
7
|
+
require "dry/schema/path"
|
8
8
|
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
9
|
+
require "dry/validation/config"
|
10
|
+
require "dry/validation/constants"
|
11
|
+
require "dry/validation/rule"
|
12
|
+
require "dry/validation/evaluator"
|
13
|
+
require "dry/validation/messages/resolver"
|
14
|
+
require "dry/validation/result"
|
15
|
+
require "dry/validation/contract/class_interface"
|
16
16
|
|
17
17
|
module Dry
|
18
18
|
module Validation
|
@@ -123,14 +123,14 @@ module Dry
|
|
123
123
|
return path.expand.any? { |nested_path| error?(result, nested_path) }
|
124
124
|
end
|
125
125
|
|
126
|
-
return true if result.
|
126
|
+
return true if result.schema_error?(path)
|
127
127
|
|
128
128
|
path
|
129
129
|
.to_a[0..-2]
|
130
130
|
.any? { |key|
|
131
131
|
curr_path = Schema::Path[path.keys[0..path.keys.index(key)]]
|
132
132
|
|
133
|
-
return false unless result.
|
133
|
+
return false unless result.schema_error?(curr_path)
|
134
134
|
|
135
135
|
result.errors.any? { |err|
|
136
136
|
(other = Schema::Path[err.path]).same_root?(curr_path) && other == curr_path
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
3
|
+
require "dry/schema"
|
4
|
+
require "dry/schema/messages"
|
5
|
+
require "dry/schema/path"
|
6
|
+
require "dry/schema/key_map"
|
7
7
|
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
8
|
+
require "dry/validation/constants"
|
9
|
+
require "dry/validation/macros"
|
10
|
+
require "dry/validation/schema_ext"
|
11
11
|
|
12
12
|
module Dry
|
13
13
|
module Validation
|
@@ -23,7 +23,7 @@ module Dry
|
|
23
23
|
# @api private
|
24
24
|
def inherited(klass)
|
25
25
|
super
|
26
|
-
klass.instance_variable_set(
|
26
|
+
klass.instance_variable_set("@config", config.dup)
|
27
27
|
end
|
28
28
|
|
29
29
|
# Configuration
|
@@ -154,28 +154,15 @@ module Dry
|
|
154
154
|
private
|
155
155
|
|
156
156
|
# @api private
|
157
|
-
# rubocop:disable Metrics/AbcSize
|
158
157
|
def ensure_valid_keys(*keys)
|
159
|
-
valid_paths = key_map.to_dot_notation
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
last.map { |last_key|
|
168
|
-
path_key = [*path.to_a[0..-2], last_key]
|
169
|
-
[path_key, Schema::Path[path_key]]
|
170
|
-
}
|
171
|
-
else
|
172
|
-
[[key, path]]
|
173
|
-
end
|
174
|
-
}
|
175
|
-
.reject { |(_, path)|
|
176
|
-
valid_paths.any? { |valid_path| valid_path.include?(path) }
|
177
|
-
}
|
178
|
-
.map(&:first)
|
158
|
+
valid_paths = key_map.to_dot_notation
|
159
|
+
key_paths = key_paths(keys)
|
160
|
+
|
161
|
+
invalid_keys = key_paths.map { |(key, path)|
|
162
|
+
unless valid_paths.any? { |vp| vp.include?(path) || vp.include?("#{path}[]") }
|
163
|
+
key
|
164
|
+
end
|
165
|
+
}.compact.uniq
|
179
166
|
|
180
167
|
return if invalid_keys.empty?
|
181
168
|
|
@@ -183,7 +170,28 @@ module Dry
|
|
183
170
|
#{name}.rule specifies keys that are not defined by the schema: #{invalid_keys.inspect}
|
184
171
|
STR
|
185
172
|
end
|
186
|
-
|
173
|
+
|
174
|
+
# @api private
|
175
|
+
def key_paths(keys)
|
176
|
+
keys.map { |key|
|
177
|
+
case key
|
178
|
+
when Hash
|
179
|
+
path = Schema::Path[key]
|
180
|
+
if path.multi_value?
|
181
|
+
*head, tail = Array(path)
|
182
|
+
[key].product(
|
183
|
+
tail.map { |el| [*head, *el] }.map { |parts| parts.join(DOT) }
|
184
|
+
)
|
185
|
+
else
|
186
|
+
[[key, path.to_a.join(DOT)]]
|
187
|
+
end
|
188
|
+
when Array
|
189
|
+
[[key, Schema::Path[key].to_a.join(DOT)]]
|
190
|
+
else
|
191
|
+
[[key, key.to_s]]
|
192
|
+
end
|
193
|
+
}.flatten(1)
|
194
|
+
end
|
187
195
|
|
188
196
|
# @api private
|
189
197
|
def key_map
|
@@ -192,7 +200,7 @@ module Dry
|
|
192
200
|
|
193
201
|
# @api private
|
194
202
|
def core_schema_opts
|
195
|
-
{
|
203
|
+
{parent: superclass&.__schema__, config: config}
|
196
204
|
end
|
197
205
|
|
198
206
|
# @api private
|
@@ -200,7 +208,7 @@ module Dry
|
|
200
208
|
return __schema__ if external_schemas.empty? && block.nil?
|
201
209
|
|
202
210
|
unless __schema__.nil?
|
203
|
-
raise ::Dry::Validation::DuplicateSchemaError,
|
211
|
+
raise ::Dry::Validation::DuplicateSchemaError, "Schema has already been defined"
|
204
212
|
end
|
205
213
|
|
206
214
|
schema_opts = core_schema_opts
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/initializer"
|
4
|
+
require "dry/core/deprecations"
|
4
5
|
|
5
|
-
require
|
6
|
-
require
|
6
|
+
require "dry/validation/constants"
|
7
|
+
require "dry/validation/failures"
|
7
8
|
|
8
9
|
module Dry
|
9
10
|
module Validation
|
@@ -16,6 +17,9 @@ module Dry
|
|
16
17
|
# @api public
|
17
18
|
class Evaluator
|
18
19
|
extend Dry::Initializer
|
20
|
+
extend Dry::Core::Deprecations[:'dry-validation']
|
21
|
+
|
22
|
+
deprecate :error?, :schema_error?
|
19
23
|
|
20
24
|
# @!attribute [r] _contract
|
21
25
|
# @return [Contract]
|
@@ -142,7 +146,7 @@ module Dry
|
|
142
146
|
#
|
143
147
|
# @return [Object]
|
144
148
|
#
|
145
|
-
# @public
|
149
|
+
# @api public
|
146
150
|
def value
|
147
151
|
values[key_name]
|
148
152
|
end
|
@@ -151,27 +155,43 @@ module Dry
|
|
151
155
|
#
|
152
156
|
# This is useful when dealing with rules for optional keys
|
153
157
|
#
|
154
|
-
# @example
|
158
|
+
# @example use the default key name
|
155
159
|
# rule(:age) do
|
156
160
|
# key.failure(:invalid) if key? && value < 18
|
157
161
|
# end
|
158
162
|
#
|
163
|
+
# @example specify the key name
|
164
|
+
# rule(:start_date, :end_date) do
|
165
|
+
# if key?(:start_date) && !key?(:end_date)
|
166
|
+
# key(:end_date).failure("must provide an end_date with start_date")
|
167
|
+
# end
|
168
|
+
# end
|
169
|
+
#
|
159
170
|
# @return [Boolean]
|
160
171
|
#
|
161
172
|
# @api public
|
162
|
-
def key?
|
163
|
-
values.key?(
|
173
|
+
def key?(name = key_name)
|
174
|
+
values.key?(name)
|
164
175
|
end
|
165
176
|
|
166
|
-
# Check if there are any errors under the provided path
|
177
|
+
# Check if there are any errors on the schema under the provided path
|
178
|
+
#
|
179
|
+
# @param path [Symbol, String, Array] A Path-compatible spec
|
167
180
|
#
|
168
|
-
# @
|
181
|
+
# @return [Boolean]
|
182
|
+
#
|
183
|
+
# @api public
|
184
|
+
def schema_error?(path)
|
185
|
+
result.schema_error?(path)
|
186
|
+
end
|
187
|
+
|
188
|
+
# Check if there are any errors on the current rule
|
169
189
|
#
|
170
190
|
# @return [Boolean]
|
171
191
|
#
|
172
192
|
# @api public
|
173
|
-
def
|
174
|
-
|
193
|
+
def rule_error?
|
194
|
+
!key(path).empty?
|
175
195
|
end
|
176
196
|
|
177
197
|
# @api private
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'dry/monads/result'
|
4
|
-
|
5
3
|
module Dry
|
6
4
|
module Validation
|
7
5
|
# Hints extension
|
@@ -46,7 +44,7 @@ module Dry
|
|
46
44
|
#
|
47
45
|
# @api public
|
48
46
|
def messages(new_options = EMPTY_HASH)
|
49
|
-
errors.with(hints.to_a, options.merge(**new_options))
|
47
|
+
errors.with(hints(new_options).to_a, options.merge(**new_options))
|
50
48
|
end
|
51
49
|
|
52
50
|
# Return hint messages
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "dry/schema/path"
|
4
|
+
require "dry/validation/constants"
|
5
5
|
|
6
6
|
module Dry
|
7
7
|
module Validation
|
@@ -57,9 +57,14 @@ module Dry
|
|
57
57
|
#
|
58
58
|
# @api public
|
59
59
|
def failure(message, tokens = EMPTY_HASH)
|
60
|
-
opts << {
|
60
|
+
opts << {message: message, tokens: tokens, path: path}
|
61
61
|
self
|
62
62
|
end
|
63
|
+
|
64
|
+
# @api private
|
65
|
+
def empty?
|
66
|
+
opts.empty?
|
67
|
+
end
|
63
68
|
end
|
64
69
|
end
|
65
70
|
end
|
data/lib/dry/validation/macro.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "dry/container"
|
4
|
+
require "dry/validation/macro"
|
5
5
|
|
6
6
|
module Dry
|
7
7
|
module Validation
|
@@ -25,7 +25,7 @@ module Dry
|
|
25
25
|
# end
|
26
26
|
#
|
27
27
|
# @param [Symbol] name The name of the macro
|
28
|
-
# @param [Array]
|
28
|
+
# @param [Array] args Optional default positional arguments for the macro
|
29
29
|
#
|
30
30
|
# @return [self]
|
31
31
|
#
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/schema/message_set"
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
5
|
+
require "dry/validation/constants"
|
6
|
+
require "dry/validation/message"
|
7
7
|
|
8
8
|
module Dry
|
9
9
|
module Validation
|
@@ -57,7 +57,6 @@ module Dry
|
|
57
57
|
@empty = nil
|
58
58
|
source_messages << message
|
59
59
|
messages << message
|
60
|
-
initialize_placeholders!
|
61
60
|
self
|
62
61
|
end
|
63
62
|
|
@@ -86,58 +85,13 @@ module Dry
|
|
86
85
|
# @api private
|
87
86
|
def freeze
|
88
87
|
source_messages.select { |err| err.respond_to?(:evaluate) }.each do |err|
|
89
|
-
idx = source_messages.index(err)
|
88
|
+
idx = messages.index(err) || source_messages.index(err)
|
90
89
|
msg = err.evaluate(locale: locale, full: options[:full])
|
91
90
|
messages[idx] = msg
|
92
91
|
end
|
93
92
|
to_h
|
94
93
|
self
|
95
94
|
end
|
96
|
-
|
97
|
-
private
|
98
|
-
|
99
|
-
# @api private
|
100
|
-
def unique_paths
|
101
|
-
source_messages.uniq(&:path).map(&:path)
|
102
|
-
end
|
103
|
-
|
104
|
-
# @api private
|
105
|
-
def messages_map
|
106
|
-
@messages_map ||= reduce(placeholders) { |hash, msg|
|
107
|
-
node = msg.path.reduce(hash) { |a, e| a.is_a?(Hash) ? a[e] : a.last[e] }
|
108
|
-
(node[0].is_a?(::Array) ? node[0] : node) << msg.dump
|
109
|
-
hash
|
110
|
-
}
|
111
|
-
end
|
112
|
-
|
113
|
-
# @api private
|
114
|
-
#
|
115
|
-
# rubocop:disable Metrics/AbcSize
|
116
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
117
|
-
def initialize_placeholders!
|
118
|
-
@placeholders = unique_paths.sort_by(&:size).each_with_object(EMPTY_HASH.dup) { |path, hash|
|
119
|
-
curr_idx = 0
|
120
|
-
last_idx = path.size - 1
|
121
|
-
node = hash
|
122
|
-
|
123
|
-
while curr_idx <= last_idx
|
124
|
-
key = path[curr_idx]
|
125
|
-
|
126
|
-
next_node =
|
127
|
-
if node.is_a?(Array) && key.is_a?(Symbol)
|
128
|
-
node_hash = (node << [] << {}).last
|
129
|
-
node_hash[key] || (node_hash[key] = curr_idx < last_idx ? {} : [])
|
130
|
-
else
|
131
|
-
node[key] || (node[key] = curr_idx < last_idx ? {} : [])
|
132
|
-
end
|
133
|
-
|
134
|
-
node = next_node
|
135
|
-
curr_idx += 1
|
136
|
-
end
|
137
|
-
}
|
138
|
-
end
|
139
|
-
# rubocop:enable Metrics/AbcSize
|
140
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
141
95
|
end
|
142
96
|
end
|
143
97
|
end
|
@@ -1,10 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/validation/message"
|
4
|
+
require "dry/schema/message_compiler"
|
4
5
|
|
5
6
|
module Dry
|
6
7
|
module Validation
|
7
8
|
module Messages
|
9
|
+
FULL_MESSAGE_WHITESPACE = Dry::Schema::MessageCompiler::FULL_MESSAGE_WHITESPACE
|
10
|
+
|
8
11
|
# Resolve translated messages from failure arguments
|
9
12
|
#
|
10
13
|
# @api public
|
@@ -33,7 +36,7 @@ module Dry
|
|
33
36
|
when Symbol
|
34
37
|
Message[->(**opts) { message(message, path: path, tokens: tokens, **opts) }, path, meta]
|
35
38
|
when String
|
36
|
-
Message[message, path, meta]
|
39
|
+
Message[->(**opts) { [message_text(message, path: path, **opts), meta] }, path, meta]
|
37
40
|
when Hash
|
38
41
|
meta = message.dup
|
39
42
|
text = meta.delete(:text) { |key|
|
@@ -69,6 +72,11 @@ module Dry
|
|
69
72
|
template, meta = messages[rule, msg_opts.merge(path: keys.last)] unless template
|
70
73
|
end
|
71
74
|
|
75
|
+
if !template && keys.size > 1
|
76
|
+
non_index_keys = keys.reject { |k| k.is_a?(Integer) }
|
77
|
+
template, meta = messages[rule, msg_opts.merge(path: non_index_keys.join(DOT))]
|
78
|
+
end
|
79
|
+
|
72
80
|
unless template
|
73
81
|
raise MissingMessageError, <<~STR
|
74
82
|
Message template for #{rule.inspect} under #{keys.join(DOT).inspect} was not found
|
@@ -78,12 +86,29 @@ module Dry
|
|
78
86
|
parsed_tokens = parse_tokens(tokens)
|
79
87
|
text = template.(template.data(parsed_tokens))
|
80
88
|
|
81
|
-
[
|
89
|
+
[message_text(text, path: path, locale: locale, full: full), meta]
|
82
90
|
end
|
83
91
|
# rubocop:enable Metrics/AbcSize
|
84
92
|
|
85
93
|
private
|
86
94
|
|
95
|
+
def message_text(text, path:, locale: nil, full: false)
|
96
|
+
return text unless full
|
97
|
+
|
98
|
+
key = key_text(path: path, locale: locale)
|
99
|
+
|
100
|
+
[key, text].compact.join(FULL_MESSAGE_WHITESPACE[locale])
|
101
|
+
end
|
102
|
+
|
103
|
+
def key_text(path:, locale: nil)
|
104
|
+
locale ||= messages.default_locale
|
105
|
+
|
106
|
+
keys = path.to_a.compact
|
107
|
+
msg_opts = {path: keys, locale: locale}
|
108
|
+
|
109
|
+
messages.rule(keys.last, msg_opts) || keys.last
|
110
|
+
end
|
111
|
+
|
87
112
|
def parse_tokens(tokens)
|
88
113
|
Hash[
|
89
114
|
tokens.map do |key, token|
|
@@ -95,7 +120,7 @@ module Dry
|
|
95
120
|
def parse_token(token)
|
96
121
|
case token
|
97
122
|
when Array
|
98
|
-
token.join(
|
123
|
+
token.join(", ")
|
99
124
|
else
|
100
125
|
token
|
101
126
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "concurrent/map"
|
4
|
+
require "dry/equalizer"
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
6
|
+
require "dry/validation/constants"
|
7
|
+
require "dry/validation/message_set"
|
8
|
+
require "dry/validation/values"
|
9
9
|
|
10
10
|
module Dry
|
11
11
|
module Validation
|
@@ -101,8 +101,15 @@ module Dry
|
|
101
101
|
|
102
102
|
# Check if values include an error for the provided key
|
103
103
|
#
|
104
|
-
# @api
|
104
|
+
# @api public
|
105
105
|
def error?(key)
|
106
|
+
errors.any? { |msg| Schema::Path[msg.path].include?(Schema::Path[key]) }
|
107
|
+
end
|
108
|
+
|
109
|
+
# Check if the base schema (without rules) includes an error for the provided key
|
110
|
+
#
|
111
|
+
# @api private
|
112
|
+
def schema_error?(key)
|
106
113
|
schema_result.error?(key)
|
107
114
|
end
|
108
115
|
|
@@ -116,7 +123,7 @@ module Dry
|
|
116
123
|
key_path = Schema::Path[key]
|
117
124
|
err_path = Schema::Path[error.path]
|
118
125
|
|
119
|
-
|
126
|
+
next unless key_path.same_root?(err_path)
|
120
127
|
|
121
128
|
key_path == err_path
|
122
129
|
}
|
@@ -179,7 +186,7 @@ module Dry
|
|
179
186
|
super
|
180
187
|
end
|
181
188
|
|
182
|
-
if RUBY_VERSION >=
|
189
|
+
if RUBY_VERSION >= "2.7"
|
183
190
|
# Pattern matching
|
184
191
|
#
|
185
192
|
# @api private
|
data/lib/dry/validation/rule.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/equalizer"
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
5
|
+
require "dry/validation/constants"
|
6
|
+
require "dry/validation/function"
|
7
7
|
|
8
8
|
module Dry
|
9
9
|
module Validation
|
@@ -65,8 +65,8 @@ module Dry
|
|
65
65
|
# for a given array item.
|
66
66
|
#
|
67
67
|
# @example
|
68
|
-
# rule(:nums).each do
|
69
|
-
# key.failure("must be greater than 0") if value < 0
|
68
|
+
# rule(:nums).each do |index:|
|
69
|
+
# key([:number, index]).failure("must be greater than 0") if value < 0
|
70
70
|
# end
|
71
71
|
# rule(:nums).each(min: 3)
|
72
72
|
# rule(address: :city) do
|
@@ -86,9 +86,9 @@ module Dry
|
|
86
86
|
values[root].each_with_index do |_, idx|
|
87
87
|
path = [*Schema::Path[root].to_a, idx]
|
88
88
|
|
89
|
-
next if result.
|
89
|
+
next if result.schema_error?(path)
|
90
90
|
|
91
|
-
evaluator = with(macros: macros, keys: [path], &block)
|
91
|
+
evaluator = with(macros: macros, keys: [path], index: idx, &block)
|
92
92
|
|
93
93
|
failures.concat(evaluator.failures)
|
94
94
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require 'dry/schema/key_map'
|
3
|
+
require "dry/schema/path"
|
5
4
|
|
6
5
|
module Dry
|
7
6
|
module Schema
|
@@ -16,31 +15,5 @@ module Dry
|
|
16
15
|
to_a[0..-2].product(last).map { |spec| self.class[spec] }
|
17
16
|
end
|
18
17
|
end
|
19
|
-
|
20
|
-
# @api private
|
21
|
-
#
|
22
|
-
# TODO: this should be moved to dry-schema at some point
|
23
|
-
class Key
|
24
|
-
# @api private
|
25
|
-
def to_dot_notation
|
26
|
-
[name.to_s]
|
27
|
-
end
|
28
|
-
|
29
|
-
# @api private
|
30
|
-
class Hash < Key
|
31
|
-
# @api private
|
32
|
-
def to_dot_notation
|
33
|
-
[name].product(members.flat_map(&:to_dot_notation)).map { |e| e.join(DOT) }
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# @api private
|
39
|
-
class KeyMap
|
40
|
-
# @api private
|
41
|
-
def to_dot_notation
|
42
|
-
@to_dot_notation ||= map(&:to_dot_notation).flatten
|
43
|
-
end
|
44
|
-
end
|
45
18
|
end
|
46
19
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "dry/equalizer"
|
4
|
+
require "dry/schema/path"
|
5
|
+
require "dry/validation/constants"
|
6
6
|
|
7
7
|
module Dry
|
8
8
|
module Validation
|
@@ -35,7 +35,10 @@ module Dry
|
|
35
35
|
# key.failure('must be > 18') if values[:age] <= 18
|
36
36
|
# end
|
37
37
|
#
|
38
|
-
# @param [Symbol]
|
38
|
+
# @param args [Symbol, String, Hash, Array<Symbol>] If given as a single
|
39
|
+
# Symbol, String, Array or Hash, build a key array using
|
40
|
+
# {Dry::Schema::Path} digging for data. If given as positional
|
41
|
+
# arguments, use these with Hash#dig on the data directly.
|
39
42
|
#
|
40
43
|
# @return [Object]
|
41
44
|
#
|
@@ -53,7 +56,7 @@ module Dry
|
|
53
56
|
vals = self.class.new(data.dig(*keys))
|
54
57
|
vals.fetch_values(*last) { nil }
|
55
58
|
else
|
56
|
-
raise ArgumentError,
|
59
|
+
raise ArgumentError, "+key+ must be a valid path specification"
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
@@ -65,6 +68,8 @@ module Dry
|
|
65
68
|
if e.is_a?(Array)
|
66
69
|
result = e.all? { |k| key?(k, a) }
|
67
70
|
return result
|
71
|
+
elsif e.is_a?(Symbol) && a.is_a?(Array)
|
72
|
+
return false
|
68
73
|
else
|
69
74
|
return false unless a.is_a?(Array) ? (e >= 0 && e < a.size) : a.key?(e)
|
70
75
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-validation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4
|
4
|
+
version: 1.5.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -92,20 +92,14 @@ dependencies:
|
|
92
92
|
requirements:
|
93
93
|
- - "~>"
|
94
94
|
- !ruby/object:Gem::Version
|
95
|
-
version: '1.
|
96
|
-
- - ">="
|
97
|
-
- !ruby/object:Gem::Version
|
98
|
-
version: 1.4.3
|
95
|
+
version: '1.5'
|
99
96
|
type: :runtime
|
100
97
|
prerelease: false
|
101
98
|
version_requirements: !ruby/object:Gem::Requirement
|
102
99
|
requirements:
|
103
100
|
- - "~>"
|
104
101
|
- !ruby/object:Gem::Version
|
105
|
-
version: '1.
|
106
|
-
- - ">="
|
107
|
-
- !ruby/object:Gem::Version
|
108
|
-
version: 1.4.3
|
102
|
+
version: '1.5'
|
109
103
|
- !ruby/object:Gem::Dependency
|
110
104
|
name: bundler
|
111
105
|
requirement: !ruby/object:Gem::Requirement
|