dry-validation 1.0.0 → 1.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7acb8c840fe5a4c12564c86985078e25cff1bea877b9e2dc4f29b39bc892b6a5
4
- data.tar.gz: ae09dc37911b0e4031918f22efabd53035501119a71da60ce08b4e0a00a3e0b6
3
+ metadata.gz: 3821e92d2dced61bb892e20a5e5d69b596128fcdbd05596e41fff8716767b08c
4
+ data.tar.gz: f797d5e46604e777966cb3d9a7a4032265227684164224a8ff109fc8ba51d1c1
5
5
  SHA512:
6
- metadata.gz: 9430d9ca1660c3d280dd5c32f1787bce32c06c38ecd22987f53ccce8b581debce2679b95dc3b2eb9a96598d16c2dc0d99f5b65aa26de14fe0f2a03c5bb822a87
7
- data.tar.gz: a07ad85054ae898cd155db7874219332e58956f57904c1dde445d27d34aa81aa2b7d1a431e6218f6aa320bfdb0e0fffd20fd619a98991929b12c1f643326c77a
6
+ metadata.gz: 7504498b77c794b9fe37e0384fba50a8fb6c99e3fecd3423e66fe018006288b3ba1a5a7a2232fb53dede256ba0a13630313748a0214b4a0d9865fc22c0b9edae
7
+ data.tar.gz: 654233d365e7844985f465e16335a234a2d5c2c240b97a485d286a52e6229e3ee80d8719e76d3ec95fe393d75f480617452b7813cb36b4b033021f9b98958461
@@ -1,3 +1,25 @@
1
+ # v1.1.1 2019-06-24
2
+
3
+ ### Fixed
4
+
5
+ * `Rule#each` works with array values from nested hashes (@mustardnoise)
6
+
7
+ [Compare v1.1.0...v1.1.1](https://github.com/dry-rb/dry-validation/compare/v1.1.0...v1.1.1)
8
+
9
+ # v1.1.0 2019-06-14
10
+
11
+ ### Added
12
+
13
+ * `key?` method available within rules, that can be used to check if there's a value under the rule's default key (refs #540) (@solnic)
14
+ * `value` supports hash-based path specifications now (refs #547) (@solnic)
15
+ * `value` can read multiple values when the key points to them, ie in case of `rule(geo: [:lat, :lon])` it would return an array with `lat` and `lon` (@solnic)
16
+
17
+ ### Fixed
18
+
19
+ * Passing multiple macro names to `validate` or `each` works correctly (fixed #538 #541) (@jandudulski)
20
+
21
+ [Compare v1.0.0...v1.1.0](https://github.com/dry-rb/dry-validation/compare/v1.0.0...v1.1.0)
22
+
1
23
  # v1.0.0 2019-06-10
2
24
 
3
25
  This release is a complete rewrite on top of `dry-schema` that uses contract classes to define schema and validation rules. It's **not backward-compatible**. This release addressed over 150 known issues, including bugs and missing features.
@@ -12,7 +34,7 @@ See [the list of all addressed issues](https://github.com/dry-rb/dry-validation/
12
34
  - Support for macros that encapsulate common rule logic
13
35
  - Built-in `:acceptance` macro
14
36
 
15
- [Compare v0.13.3...v1.0.0](https://github.com/dry-rb/dry-validation/compare/v1.13.3...v1.0.0)
37
+ [Compare v0.13.3...v1.0.0](https://github.com/dry-rb/dry-validation/compare/v0.13.3...v1.0.0)
16
38
 
17
39
  # v1.0.0 2019-06-10 (compared to 1.0.0.rc3)
18
40
 
@@ -41,9 +41,12 @@ module Dry
41
41
  # @return [Contract]
42
42
  #
43
43
  # @api public
44
+ #
45
+ # rubocop:disable Naming/MethodName
44
46
  def self.Contract(options = EMPTY_HASH, &block)
45
47
  Contract.build(options, &block)
46
48
  end
49
+ # rubocop:enable Naming/MethodName
47
50
 
48
51
  # This is needed by Macros::Registrar
49
52
  #
@@ -11,6 +11,12 @@ module Dry
11
11
  # Root path is used for base errors in hash representation of error messages
12
12
  ROOT_PATH = [nil].freeze
13
13
 
14
+ # Path to the default errors locale file
15
+ DEFAULT_ERRORS_NAMESPACE = 'dry_validation'
16
+
17
+ # Path to the default errors locale file
18
+ DEFAULT_ERRORS_PATH = Pathname(__FILE__).join('../../../../config/errors.yml').realpath.freeze
19
+
14
20
  # Mapping for block kwarg options used by block_options
15
21
  #
16
22
  # @see Rule#block_options
@@ -54,8 +54,8 @@ module Dry
54
54
  extend Dry::Initializer
55
55
  extend ClassInterface
56
56
 
57
- config.messages.top_namespace = 'dry_validation'
58
- config.messages.load_paths << Pathname(__FILE__).join('../../../../config/errors.yml').realpath
57
+ config.messages.top_namespace = DEFAULT_ERRORS_NAMESPACE
58
+ config.messages.load_paths << DEFAULT_ERRORS_PATH
59
59
 
60
60
  # @!attribute [r] config
61
61
  # @return [Config] Contract's configuration object
@@ -118,7 +118,9 @@ module Dry
118
118
  # @api private
119
119
  def error?(result, key)
120
120
  path = Schema::Path[key]
121
- result.error?(path) || path.map.with_index { |_k, i| result.error?(path.keys[0..i - 2]) }.any?
121
+
122
+ result.error?(path) ||
123
+ path.map.with_index { |_k, i| result.error?(path.keys[0..i - 2]) }.any?
122
124
  end
123
125
 
124
126
  # Get a registered macro
@@ -147,6 +147,22 @@ module Dry
147
147
  values[key_name]
148
148
  end
149
149
 
150
+ # Return if the value under the default key is available
151
+ #
152
+ # This is useful when dealing with rules for optional keys
153
+ #
154
+ # @example
155
+ # rule(:age) do
156
+ # key.failure(:invalid) if key? && value < 18
157
+ # end
158
+ #
159
+ # @return [Boolean]
160
+ #
161
+ # @api public
162
+ def key?
163
+ values.key?(key_name)
164
+ end
165
+
150
166
  # Check if there are any errors under the provided path
151
167
  #
152
168
  # @param [Symbol, String, Array] A Path-compatible spec
@@ -49,6 +49,8 @@ module Dry
49
49
  # @return [String]
50
50
  #
51
51
  # @api public
52
+ #
53
+ # rubocop:disable Metrics/AbcSize
52
54
  def message(rule, tokens: EMPTY_HASH, locale: nil, full: false, path:)
53
55
  keys = path.to_a.compact
54
56
  msg_opts = tokens.merge(path: keys, locale: locale || messages.default_locale)
@@ -70,6 +72,7 @@ module Dry
70
72
 
71
73
  [full ? "#{messages.rule(keys.last, msg_opts)} #{text}" : text, meta]
72
74
  end
75
+ # rubocop:enable Metrics/AbcSize
73
76
  end
74
77
  end
75
78
  end
@@ -148,9 +148,9 @@ module Dry
148
148
  # @api public
149
149
  def inspect
150
150
  if context.empty?
151
- "#<#{self.class}#{to_h.inspect} errors=#{errors.to_h.inspect}>"
151
+ "#<#{self.class}#{to_h} errors=#{errors.to_h}>"
152
152
  else
153
- "#<#{self.class}#{to_h.inspect} errors=#{errors.to_h.inspect} context=#{context.each.to_h.inspect}>"
153
+ "#<#{self.class}#{to_h} errors=#{errors.to_h} context=#{context.each.to_h}>"
154
154
  end
155
155
  end
156
156
 
@@ -54,7 +54,7 @@ module Dry
54
54
  #
55
55
  # @api public
56
56
  def validate(*macros, &block)
57
- @macros = macros.map { |spec| Array(spec) }.map(&:flatten)
57
+ @macros = parse_macros(*macros)
58
58
  @block = block if block
59
59
  self
60
60
  end
@@ -68,17 +68,22 @@ module Dry
68
68
  # rule(:nums).each do
69
69
  # key.failure("must be greater than 0") if value < 0
70
70
  # end
71
+ # rule(:nums).each(min: 3)
72
+ # rule(address: :city) do
73
+ # key.failure("oops") if value != 'Munich'
74
+ # end
71
75
  #
72
76
  # @return [Rule]
73
77
  #
74
78
  # @api public
75
79
  def each(*macros, &block)
76
- root = keys
80
+ root = keys[0]
81
+ macros = parse_macros(*macros)
77
82
  @keys = []
78
83
 
79
84
  @block = proc do
80
- values[root].each_with_index do |_, idx|
81
- path = [*root, idx]
85
+ (values[root] || []).each_with_index do |_, idx|
86
+ path = [*Schema::Path[root].to_a, idx]
82
87
 
83
88
  next if result.error?(path)
84
89
 
@@ -99,6 +104,22 @@ module Dry
99
104
  def inspect
100
105
  %(#<#{self.class} keys=#{keys.inspect}>)
101
106
  end
107
+
108
+ # Parse function arguments into macros structure
109
+ #
110
+ # @return [Array]
111
+ #
112
+ # @api private
113
+ def parse_macros(*args)
114
+ args.each_with_object([]) do |spec, macros|
115
+ case spec
116
+ when Hash
117
+ spec.each { |k, v| macros << [k, Array(v)] }
118
+ else
119
+ macros << Array(spec)
120
+ end
121
+ end
122
+ end
102
123
  end
103
124
  end
104
125
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'dry/equalizer'
4
+ require 'dry/schema/path'
4
5
  require 'dry/validation/constants'
5
6
 
6
7
  module Dry
@@ -40,17 +41,39 @@ module Dry
40
41
  #
41
42
  # @api public
42
43
  def [](*args)
43
- if args.size.equal?(1)
44
- case (key = args[0])
45
- when Symbol then data[key]
46
- when String then self[*key.split(DOT).map(&:to_sym)]
47
- when Array then self[*key]
44
+ return data.dig(*args) if args.size > 1
45
+
46
+ case (key = args[0])
47
+ when Symbol, String, Array, Hash
48
+ path = Schema::Path[key]
49
+ keys = path.to_a
50
+
51
+ return data.dig(*keys) unless keys.last.is_a?(Array)
52
+
53
+ last = keys.pop
54
+ vals = self.class.new(data.dig(*keys))
55
+
56
+ last.map { |name| vals[name] }
57
+ else
58
+ raise ArgumentError, '+key+ must be a valid path specification'
59
+ end
60
+ end
61
+
62
+ # @api public
63
+ def key?(key, hash = data)
64
+ return hash.key?(key) if key.is_a?(Symbol)
65
+
66
+ Schema::Path[key].reduce(hash) do |a, e|
67
+ if e.is_a?(Array)
68
+ result = e.all? { |k| key?(k, a) }
69
+ return result
48
70
  else
49
- raise ArgumentError, '+key+ must be a symbol, string, array, or a list of keys for dig'
71
+ return false unless a.is_a?(Array) ? (e >= 0 && e < a.size) : a.key?(e)
50
72
  end
51
- else
52
- data.dig(*args)
73
+ a[e]
53
74
  end
75
+
76
+ true
54
77
  end
55
78
 
56
79
  # @api private
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module Validation
5
- VERSION = '1.0.0'
5
+ VERSION = '1.1.1'
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.0.0
4
+ version: 1.1.1
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-06-10 00:00:00.000000000 Z
11
+ date: 2019-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby