dry-validation 1.5.2 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 83395b144bcdc666d13ac3cb100e2a7488ba9caa638067f03beee031964da26a
4
- data.tar.gz: fa5f1480a6bff63238c76ffc6ee8c574ccc113048843d5f79c9fdc216b899d23
3
+ metadata.gz: 9df6f1e542743b8e5af8438caec2b5fe705f3bba96ed9f4791eacb1efc2a627d
4
+ data.tar.gz: d027d77079c1771691f11d8f143ceb9e92834b03fb4123cdcdf48e3711dd2fba
5
5
  SHA512:
6
- metadata.gz: 7d14bcf252cbf7cd6a2d58f936d65da3e71343388b87924f51f56cd7812fecff33bab17f4193cf354cc76fd7d3bbbd2081e847b0c8b54b466c1781599aeba25b
7
- data.tar.gz: 11d241432260233c0b7f8fe03b69e1a2cd44e0e7fd241a90ba5f3eb65eff4f21e7c8c88e3fa5c903dc65dbbd78de537a03368ba47cf714a295c7da8784286af8
6
+ metadata.gz: 76059d5e724680569c71ab794849379e2404b63053073fbe57394ed6031cfd0aff67b210f92b15f985feef77a986cafa7f442397e91ec3deac436f289379b126
7
+ data.tar.gz: e5e1a9a3ae536767cbba5584061e04dc01a065bccd9936b8d30482b499e4a865309400c3eff5f589a5661ba25ed1403e4a77cadc83f215b8fd6cf588dd217aa7
@@ -1,15 +1,79 @@
1
- ## 1.5.1 2020-06-18
1
+ ## 1.6.0
2
+
3
+
4
+ ### Added
5
+
6
+ - You can now pass a key name or path to `rule_error?` predicate (issue #658 closed via #673) (@moofkit)
7
+ - You can now pass initial context object to `Contract#call` (issue #674 via #675) (@pyromaniac)
8
+
9
+ ### Fixed
10
+
11
+ - Checking `key?` within a rule no longer crashes when value is `nil` or an empty string (issue #670 fixed via #672) (@alexxty7)
12
+
13
+
14
+ [Compare v1.5.6...master](https://github.com/dry-rb/dry-validation/compare/v1.5.6...master)
15
+
16
+ ## 1.5.6 2020-09-04
17
+
18
+
19
+ ### Fixed
20
+
21
+ - Dependency on dry-schema was bumped to >= 1.5.1. This time for real (@solnic)
22
+
23
+
24
+ [Compare v1.5.5...v1.5.6](https://github.com/dry-rb/dry-validation/compare/v1.5.5...v1.5.6)
25
+
26
+ ## 1.5.5 2020-09-03
27
+
28
+
29
+ ### Fixed
30
+
31
+ - Dependency on dry-schema was bumped to >= 1.5.2 (see #666 for more info) (@artofhuman)
32
+
33
+
34
+ [Compare v1.5.4...v1.5.5](https://github.com/dry-rb/dry-validation/compare/v1.5.4...v1.5.5)
35
+
36
+ ## 1.5.4 2020-08-21
37
+
38
+
39
+ ### Added
40
+
41
+ - You can now pass any key or a path to the rule's `key?` helper (see #664 for more info) (@alassek)
42
+
43
+ ### Fixed
44
+
45
+ - Full messages work correctly with rule failures now (issue #661 fixed via #662) (@stind)
46
+ - Providing a custom message template for array errors works correctly (issue #663 fixed via #665) (@tadeusz-niemiec)
47
+
48
+
49
+ [Compare v1.5.3...v1.5.4](https://github.com/dry-rb/dry-validation/compare/v1.5.3...v1.5.4)
50
+
51
+ ## 1.5.3 2020-07-27
52
+
53
+
54
+ ### Added
55
+
56
+ - You can now access current value's index via `rule(:foo).each do |index:|` (issue #606 done via #657) (@mrbongiolo)
57
+
58
+ ### Fixed
59
+
60
+ - Using `.each(:foo)` works as expected when there are errors related to other keys (issue #659 fixed via #660) (@solnic)
61
+
62
+ ### Changed
63
+
64
+ - `Result#error?` is now a public API and it takes into consideration both schema and rule errors (issue #655 fixed via #656) (@PragTob)
65
+
66
+ [Compare v1.5.2...v1.5.3](https://github.com/dry-rb/dry-validation/compare/v1.5.2...v1.5.3)
67
+
68
+ ## 1.5.2 2020-07-14
2
69
 
3
70
 
4
71
  ### Fixed
5
72
 
6
- - dry-monads no longer required for the `:hints` extension (@schokomarie)
7
- - Using `full: true` option works as expected with custom rule messages (issue #618 fixed via #651) (@sirfilip)
8
- - Using `locale: ...` option works as expected with hints (issue #589 fixed via #652) (@sirfilip)
9
73
  - `key?` predicate in rules no longer crashes when the rule path points to a non-existent array value (issue #653 fixed via #654) (@solnic)
10
74
 
11
75
 
12
- [Compare v1.5.1...v1.5.1](https://github.com/dry-rb/dry-validation/compare/v1.5.1...v1.5.1)
76
+ [Compare v1.5.1...v1.5.2](https://github.com/dry-rb/dry-validation/compare/v1.5.1...v1.5.2)
13
77
 
14
78
  ## 1.5.1 2020-06-18
15
79
 
@@ -18,8 +82,7 @@
18
82
 
19
83
  - dry-monads no longer required for the `:hints` extension (@schokomarie)
20
84
  - Using `full: true` option works as expected with custom rule messages (issue #618 fixed via #651) (@sirfilip)
21
- - Using `locale: ...` option works as expected with hints (issue #589 fixed via #652) (@sirfilip)
22
- - `key?` predicate in rules no longer crashes when the rule path points to a non-existent array value (issue #653 fixed via #654) (@solnic)
85
+ - Using `locale: ...` option works as expected with hints (issue #589 fixed via 652) (@sirfilip)
23
86
 
24
87
 
25
88
  [Compare v1.5.0...v1.5.1](https://github.com/dry-rb/dry-validation/compare/v1.5.0...v1.5.1)
data/README.md CHANGED
@@ -21,7 +21,7 @@
21
21
 
22
22
  This library officially supports the following Ruby versions:
23
23
 
24
- * MRI >= `2.4`
24
+ * MRI >= `2.5`
25
25
  * jruby >= `9.2`
26
26
 
27
27
  ## License
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-validation'
26
26
  spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-validation/issues'
27
27
 
28
- spec.required_ruby_version = ">= 2.4.0"
28
+ spec.required_ruby_version = ">= 2.5.0"
29
29
 
30
30
  # to update dependencies edit project.yml
31
31
  spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
@@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
33
33
  spec.add_runtime_dependency "dry-core", "~> 0.4"
34
34
  spec.add_runtime_dependency "dry-equalizer", "~> 0.2"
35
35
  spec.add_runtime_dependency "dry-initializer", "~> 3.0"
36
- spec.add_runtime_dependency "dry-schema", "~> 1.5"
36
+ spec.add_runtime_dependency "dry-schema", "~> 1.5", ">= 1.5.2"
37
37
 
38
38
  spec.add_development_dependency "bundler"
39
39
  spec.add_development_dependency "rake"
@@ -68,6 +68,11 @@ module Dry
68
68
  # @api public
69
69
  option :macros, default: -> { config.macros }
70
70
 
71
+ # @!attribute [r] default_context
72
+ # @return [Hash] Default context for rules
73
+ # @api public
74
+ option :default_context, default: -> { EMPTY_HASH }
75
+
71
76
  # @!attribute [r] schema
72
77
  # @return [Dry::Schema::Params, Dry::Schema::JSON, Dry::Schema::Processor]
73
78
  # @api private
@@ -86,12 +91,18 @@ module Dry
86
91
  # Apply the contract to an input
87
92
  #
88
93
  # @param [Hash] input The input to validate
94
+ # @param [Hash] context Initial context for rules
89
95
  #
90
96
  # @return [Result]
91
97
  #
92
98
  # @api public
93
- def call(input)
94
- Result.new(schema.(input), Concurrent::Map.new) do |result|
99
+ def call(input, context = EMPTY_HASH)
100
+ context_map = Concurrent::Map.new.tap do |map|
101
+ default_context.each { |key, value| map[key] = value }
102
+ context.each { |key, value| map[key] = value }
103
+ end
104
+
105
+ Result.new(schema.(input), context_map) do |result|
95
106
  rules.each do |rule|
96
107
  next if rule.keys.any? { |key| error?(result, key) }
97
108
 
@@ -123,14 +134,14 @@ module Dry
123
134
  return path.expand.any? { |nested_path| error?(result, nested_path) }
124
135
  end
125
136
 
126
- return true if result.error?(path)
137
+ return true if result.schema_error?(path)
127
138
 
128
139
  path
129
140
  .to_a[0..-2]
130
141
  .any? { |key|
131
142
  curr_path = Schema::Path[path.keys[0..path.keys.index(key)]]
132
143
 
133
- return false unless result.error?(curr_path)
144
+ return false unless result.schema_error?(curr_path)
134
145
 
135
146
  result.errors.any? { |err|
136
147
  (other = Schema::Path[err.path]).same_root?(curr_path) && other == curr_path
@@ -155,16 +155,23 @@ module Dry
155
155
  #
156
156
  # This is useful when dealing with rules for optional keys
157
157
  #
158
- # @example
158
+ # @example use the default key name
159
159
  # rule(:age) do
160
160
  # key.failure(:invalid) if key? && value < 18
161
161
  # end
162
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
+ #
163
170
  # @return [Boolean]
164
171
  #
165
172
  # @api public
166
- def key?
167
- values.key?(key_name)
173
+ def key?(name = key_name)
174
+ values.key?(name)
168
175
  end
169
176
 
170
177
  # Check if there are any errors on the schema under the provided path
@@ -175,16 +182,22 @@ module Dry
175
182
  #
176
183
  # @api public
177
184
  def schema_error?(path)
178
- result.error?(path)
185
+ result.schema_error?(path)
179
186
  end
180
187
 
181
188
  # Check if there are any errors on the current rule
182
189
  #
190
+ # @param path [Symbol, String, Array] A Path-compatible spec
191
+ #
183
192
  # @return [Boolean]
184
193
  #
185
194
  # @api public
186
- def rule_error?
187
- !key(path).empty?
195
+ def rule_error?(path = nil)
196
+ if path.nil?
197
+ !key(self.path).empty?
198
+ else
199
+ result.rule_error?(path)
200
+ end
188
201
  end
189
202
 
190
203
  # @api private
@@ -1,10 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
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[->(**opts) { [message_text(message, path, **opts), meta] }, 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|
@@ -51,18 +54,6 @@ module Dry
51
54
  end
52
55
  alias_method :[], :call
53
56
 
54
- # Resolve a message
55
- #
56
- # @return String
57
- #
58
- # @api public
59
- def message_text(message, path, locale: nil, full: false, **opts)
60
- keys = path.to_a.compact
61
- msg_opts = EMPTY_HASH.merge(path: keys, locale: locale || messages.default_locale)
62
-
63
- full ? "#{messages.rule(keys.last, msg_opts) || keys.last} #{message}" : message
64
- end
65
-
66
57
  # Resolve a message
67
58
  #
68
59
  # @return [String]
@@ -81,6 +72,11 @@ module Dry
81
72
  template, meta = messages[rule, msg_opts.merge(path: keys.last)] unless template
82
73
  end
83
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
+
84
80
  unless template
85
81
  raise MissingMessageError, <<~STR
86
82
  Message template for #{rule.inspect} under #{keys.join(DOT).inspect} was not found
@@ -90,12 +86,29 @@ module Dry
90
86
  parsed_tokens = parse_tokens(tokens)
91
87
  text = template.(template.data(parsed_tokens))
92
88
 
93
- [full ? "#{messages.rule(keys.last, msg_opts)} #{text}" : text, meta]
89
+ [message_text(text, path: path, locale: locale, full: full), meta]
94
90
  end
95
91
  # rubocop:enable Metrics/AbcSize
96
92
 
97
93
  private
98
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
+
99
112
  def parse_tokens(tokens)
100
113
  Hash[
101
114
  tokens.map do |key, token|
@@ -101,11 +101,25 @@ module Dry
101
101
 
102
102
  # Check if values include an error for the provided key
103
103
  #
104
- # @api private
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
+ # Check if the rules includes an error for the provided key
117
+ #
118
+ # @api private
119
+ def rule_error?(key)
120
+ !schema_error?(key) && error?(key)
121
+ end
122
+
109
123
  # Check if there's any error for the provided key
110
124
  #
111
125
  # This does not consider errors from the nested values
@@ -116,7 +130,7 @@ module Dry
116
130
  key_path = Schema::Path[key]
117
131
  err_path = Schema::Path[error.path]
118
132
 
119
- return false unless key_path.same_root?(err_path)
133
+ next unless key_path.same_root?(err_path)
120
134
 
121
135
  key_path == err_path
122
136
  }
@@ -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.error?(path)
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
@@ -70,6 +70,10 @@ module Dry
70
70
  return result
71
71
  elsif e.is_a?(Symbol) && a.is_a?(Array)
72
72
  return false
73
+ elsif a.nil?
74
+ return false
75
+ elsif a.is_a?(String)
76
+ return false
73
77
  else
74
78
  return false unless a.is_a?(Array) ? (e >= 0 && e < a.size) : a.key?(e)
75
79
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module Validation
5
- VERSION = "1.5.2"
5
+ VERSION = "1.6.0"
6
6
  end
7
7
  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.5.2
4
+ version: 1.6.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: 2020-07-14 00:00:00.000000000 Z
11
+ date: 2020-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -93,6 +93,9 @@ dependencies:
93
93
  - - "~>"
94
94
  - !ruby/object:Gem::Version
95
95
  version: '1.5'
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: 1.5.2
96
99
  type: :runtime
97
100
  prerelease: false
98
101
  version_requirements: !ruby/object:Gem::Requirement
@@ -100,6 +103,9 @@ dependencies:
100
103
  - - "~>"
101
104
  - !ruby/object:Gem::Version
102
105
  version: '1.5'
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: 1.5.2
103
109
  - !ruby/object:Gem::Dependency
104
110
  name: bundler
105
111
  requirement: !ruby/object:Gem::Requirement
@@ -192,14 +198,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
192
198
  requirements:
193
199
  - - ">="
194
200
  - !ruby/object:Gem::Version
195
- version: 2.4.0
201
+ version: 2.5.0
196
202
  required_rubygems_version: !ruby/object:Gem::Requirement
197
203
  requirements:
198
204
  - - ">="
199
205
  - !ruby/object:Gem::Version
200
206
  version: '0'
201
207
  requirements: []
202
- rubygems_version: 3.0.3
208
+ rubygems_version: 3.1.4
203
209
  signing_key:
204
210
  specification_version: 4
205
211
  summary: Validation library