dry-validation 1.1.1 → 1.2.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: 3821e92d2dced61bb892e20a5e5d69b596128fcdbd05596e41fff8716767b08c
4
- data.tar.gz: f797d5e46604e777966cb3d9a7a4032265227684164224a8ff109fc8ba51d1c1
3
+ metadata.gz: aadb0a6e283c3de0438b2ddf7335262e276c206021e95f4aaa7eb70be040f268
4
+ data.tar.gz: e2c9949f4f69ded243970367602b997c8eba80c5d18b223f7f14d30d914b4886
5
5
  SHA512:
6
- metadata.gz: 7504498b77c794b9fe37e0384fba50a8fb6c99e3fecd3423e66fe018006288b3ba1a5a7a2232fb53dede256ba0a13630313748a0214b4a0d9865fc22c0b9edae
7
- data.tar.gz: 654233d365e7844985f465e16335a234a2d5c2c240b97a485d286a52e6229e3ee80d8719e76d3ec95fe393d75f480617452b7813cb36b4b033021f9b98958461
6
+ metadata.gz: 7cd158435b3998c6864a594d61315760b974a4b8d8a8728bdff42cc3684209416a23a154e0efe9537ab54839f96819b4b11f434104b2ba5b2be6dd4fce4c39b5
7
+ data.tar.gz: d796476595c68a33dca5cf26cb11f3aff0c3fc2be73165f5693bb9b62c94c02a917ff8f559cc62055909805d95928dc96189e8a1391657177a21674ab15b58f5
@@ -1,3 +1,19 @@
1
+ # v1.2.0 2019-07-08
2
+
3
+ ### Added
4
+
5
+ * New extension `:predicates_as_macros` (@waiting-for-dev)
6
+
7
+ ### Fixed
8
+
9
+ * Guarding rules for nested keys works correctly (issue #560) (@solnic)
10
+
11
+ ### Changed
12
+
13
+ * `dry-schema` dependency was bumped to `>= 1.3.1` (@solnic)
14
+
15
+ [Compare v1.1.1...v1.2.0](https://github.com/dry-rb/dry-validation/compare/v1.1.1...v1.2.0)
16
+
1
17
  # v1.1.1 2019-06-24
2
18
 
3
19
  ### Fixed
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  [gem]: https://rubygems.org/gems/dry-validation
2
- [travis]: https://travis-ci.org/dry-rb/dry-validation
2
+ [travis]: https://travis-ci.com/dry-rb/dry-validation
3
3
  [codeclimate]: https://codeclimate.com/github/dry-rb/dry-validation
4
4
  [chat]: https://dry-rb.zulipchat.com
5
5
  [inchpages]: http://inch-ci.org/github/dry-rb/dry-validation
@@ -7,7 +7,7 @@
7
7
  # dry-validation [![Join the chat at https://dry-rb.zulipchat.com](https://img.shields.io/badge/dry--rb-join%20chat-%23346b7a.svg)][chat]
8
8
 
9
9
  [![Gem Version](https://badge.fury.io/rb/dry-validation.svg)][gem]
10
- [![Build Status](https://travis-ci.org/dry-rb/dry-validation.svg?branch=master)][travis]
10
+ [![Build Status](https://travis-ci.com/dry-rb/dry-validation.svg?branch=master)][travis]
11
11
  [![Code Climate](https://codeclimate.com/github/dry-rb/dry-validation/badges/gpa.svg)][codeclimate]
12
12
  [![Test Coverage](https://codeclimate.com/github/dry-rb/dry-validation/badges/coverage.svg)][codeclimate]
13
13
  [![Inline docs](http://inch-ci.org/github/dry-rb/dry-validation.svg?branch=master)][inchpages]
@@ -23,6 +23,10 @@ module Dry
23
23
  require 'dry/validation/extensions/hints'
24
24
  end
25
25
 
26
+ register_extension(:predicates_as_macros) do
27
+ require 'dry/validation/extensions/predicates_as_macros'
28
+ end
29
+
26
30
  # Define a contract and build its instance
27
31
  #
28
32
  # @example
@@ -116,11 +116,20 @@ module Dry
116
116
  private
117
117
 
118
118
  # @api private
119
- def error?(result, key)
120
- path = Schema::Path[key]
119
+ def error?(result, spec)
120
+ path = Schema::Path[spec]
121
121
 
122
- result.error?(path) ||
123
- path.map.with_index { |_k, i| result.error?(path.keys[0..i - 2]) }.any?
122
+ return true if result.error?(path)
123
+
124
+ path
125
+ .to_a[0..-2]
126
+ .any? { |key|
127
+ curr_path = Schema::Path[path.keys[0..path.keys.index(key)]]
128
+
129
+ return false unless result.error?(curr_path)
130
+
131
+ result.errors.any? { |err| Schema::Path[err.path] == curr_path }
132
+ }
124
133
  end
125
134
 
126
135
  # Get a registered macro
@@ -7,34 +7,9 @@ require 'dry/schema/key_map'
7
7
 
8
8
  require 'dry/validation/constants'
9
9
  require 'dry/validation/macros'
10
+ require 'dry/validation/schema_ext'
10
11
 
11
12
  module Dry
12
- module Schema
13
- # @api private
14
- class Key
15
- # @api private
16
- def to_dot_notation
17
- [name.to_s]
18
- end
19
-
20
- # @api private
21
- class Hash < Key
22
- # @api private
23
- def to_dot_notation
24
- [name].product(members.map(&:to_dot_notation).flatten(1)).map { |e| e.join(DOT) }
25
- end
26
- end
27
- end
28
-
29
- # @api private
30
- class KeyMap
31
- # @api private
32
- def to_dot_notation
33
- @to_dot_notation ||= map(&:to_dot_notation).flatten
34
- end
35
- end
36
- end
37
-
38
13
  module Validation
39
14
  class Contract
40
15
  # Contract's class interface
@@ -179,12 +154,29 @@ module Dry
179
154
  private
180
155
 
181
156
  # @api private
157
+ # rubocop:disable Metrics/AbcSize
182
158
  def ensure_valid_keys(*keys)
183
159
  valid_paths = key_map.to_dot_notation.map { |value| Schema::Path[value] }
184
160
 
185
- invalid_keys = Schema::KeyMap[*keys]
186
- .map(&:dump)
187
- .reject { |spec| valid_paths.any? { |path| path.include?(Schema::Path[spec]) } }
161
+ invalid_keys = keys
162
+ .map { |key|
163
+ [key, Schema::Path[key]]
164
+ }
165
+ .map { |(key, path)|
166
+ if (last = path.last).is_a?(Array)
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
+ .flatten(1)
176
+ .reject { |(_, path)|
177
+ valid_paths.any? { |valid_path| valid_path.include?(path) }
178
+ }
179
+ .map(&:first)
188
180
 
189
181
  return if invalid_keys.empty?
190
182
 
@@ -192,6 +184,7 @@ module Dry
192
184
  #{name}.rule specifies keys that are not defined by the schema: #{invalid_keys.inspect}
193
185
  STR
194
186
  end
187
+ # rubocop:enable Metrics/AbcSize
195
188
 
196
189
  # @api private
197
190
  def key_map
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/schema/predicate_registry'
4
+ require 'dry/validation/contract'
5
+
6
+ module Dry
7
+ module Validation
8
+ # Predicate registry with additional needed methods.
9
+ class PredicateRegistry < Schema::PredicateRegistry
10
+ # List of predicates to be imported by `:predicates_as_macros`
11
+ # extension.
12
+ #
13
+ # @see Dry::Validation::Contract
14
+ WHITELIST = %i[
15
+ filled? gt? gteq? included_in? includes? inclusion? is? lt?
16
+ lteq? max_size? min_size? not_eql? odd? respond_to? size? true?
17
+ uuid_v4?
18
+ ].freeze
19
+
20
+ # @api private
21
+ def arg_names(name)
22
+ arg_list(name).map(&:first)
23
+ end
24
+
25
+ # @api private
26
+ def call(name, args)
27
+ self[name].(*args)
28
+ end
29
+
30
+ # @api private
31
+ def message_opts(name, arg_values)
32
+ arg_names(name).zip(arg_values).to_h
33
+ end
34
+ end
35
+
36
+ # Extension to use dry-logic predicates as macros.
37
+ #
38
+ # @see Dry::Validation::PredicateRegistry::WHITELIST Available predicates
39
+ #
40
+ # @example
41
+ # Dry::Validation.load_extensions(:predicates_as_macros)
42
+ #
43
+ # class ApplicationContract < Dry::Validation::Contract
44
+ # import_predicates_as_macros
45
+ # end
46
+ #
47
+ # class AgeContract < ApplicationContract
48
+ # schema do
49
+ # required(:age).filled(:integer)
50
+ # end
51
+ #
52
+ # rule(:age).validate(gteq?: 18)
53
+ # end
54
+ #
55
+ # AgeContract.new.(age: 17).errors.first.text
56
+ # # => 'must be greater than or equal to 18'
57
+ #
58
+ # @api public
59
+ class Contract
60
+ # Make macros available for self and its descendants.
61
+ def self.import_predicates_as_macros
62
+ registry = PredicateRegistry.new
63
+
64
+ PredicateRegistry::WHITELIST.each do |name|
65
+ register_macro(name) do |macro:|
66
+ predicate_args = [*macro.args, value]
67
+ message_opts = registry.message_opts(name, predicate_args)
68
+
69
+ key.failure(name, message_opts) unless registry.(name, predicate_args)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -19,21 +19,24 @@ module Dry
19
19
  # @api private
20
20
  option :block
21
21
 
22
+ # @!attribute [r] block_options
23
+ # @return [Hash]
24
+ # @api private
25
+ option :block_options, default: -> { block ? map_keywords(block) : EMPTY_HASH }
26
+
22
27
  private
23
28
 
24
29
  # Extract options for the block kwargs
25
30
  #
26
- # @return [Hash]
31
+ # @param [Proc] block Callable
32
+ # @return Hash
27
33
  #
28
34
  # @api private
29
- def block_options
30
- return EMPTY_HASH unless block
31
-
32
- @block_options ||= block
35
+ def map_keywords(block)
36
+ block
33
37
  .parameters
34
- .select { |arg| arg[0].equal?(:keyreq) }
35
- .map(&:last)
36
- .map { |name| [name, BLOCK_OPTIONS_MAPPINGS[name]] }
38
+ .select { |arg,| arg.equal?(:keyreq) }
39
+ .map { |_, name| [name, BLOCK_OPTIONS_MAPPINGS[name]] }
37
40
  .to_h
38
41
  end
39
42
  end
@@ -93,6 +93,8 @@ module Dry
93
93
  end
94
94
  end
95
95
 
96
+ @block_options = map_keywords(block) if block
97
+
96
98
  self
97
99
  end
98
100
 
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/schema/key'
4
+ require 'dry/schema/key_map'
5
+
6
+ module Dry
7
+ module Schema
8
+ # @api private
9
+ #
10
+ # TODO: this should be moved to dry-schema at some point
11
+ class Key
12
+ # @api private
13
+ def to_dot_notation
14
+ [name.to_s]
15
+ end
16
+
17
+ # @api private
18
+ class Hash < Key
19
+ # @api private
20
+ def to_dot_notation
21
+ [name].product(members.map(&:to_dot_notation).flatten(1)).map { |e| e.join(DOT) }
22
+ end
23
+ end
24
+ end
25
+
26
+ # @api private
27
+ class KeyMap
28
+ # @api private
29
+ def to_dot_notation
30
+ @to_dot_notation ||= map(&:to_dot_notation).flatten
31
+ end
32
+ end
33
+ end
34
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module Validation
5
- VERSION = '1.1.1'
5
+ VERSION = '1.2.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.1.1
4
+ version: 1.2.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: 2019-06-24 00:00:00.000000000 Z
11
+ date: 2019-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -95,7 +95,7 @@ dependencies:
95
95
  version: '1.0'
96
96
  - - ">="
97
97
  - !ruby/object:Gem::Version
98
- version: 1.1.0
98
+ version: 1.3.1
99
99
  type: :runtime
100
100
  prerelease: false
101
101
  version_requirements: !ruby/object:Gem::Requirement
@@ -105,7 +105,7 @@ dependencies:
105
105
  version: '1.0'
106
106
  - - ">="
107
107
  - !ruby/object:Gem::Version
108
- version: 1.1.0
108
+ version: 1.3.1
109
109
  - !ruby/object:Gem::Dependency
110
110
  name: bundler
111
111
  requirement: !ruby/object:Gem::Requirement
@@ -168,6 +168,7 @@ files:
168
168
  - lib/dry/validation/evaluator.rb
169
169
  - lib/dry/validation/extensions/hints.rb
170
170
  - lib/dry/validation/extensions/monads.rb
171
+ - lib/dry/validation/extensions/predicates_as_macros.rb
171
172
  - lib/dry/validation/failures.rb
172
173
  - lib/dry/validation/function.rb
173
174
  - lib/dry/validation/macro.rb
@@ -177,6 +178,7 @@ files:
177
178
  - lib/dry/validation/messages/resolver.rb
178
179
  - lib/dry/validation/result.rb
179
180
  - lib/dry/validation/rule.rb
181
+ - lib/dry/validation/schema_ext.rb
180
182
  - lib/dry/validation/values.rb
181
183
  - lib/dry/validation/version.rb
182
184
  homepage: https://dry-rb.org/gems/dry-validation