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 +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +2 -2
- data/lib/dry/validation.rb +4 -0
- data/lib/dry/validation/contract.rb +13 -4
- data/lib/dry/validation/contract/class_interface.rb +22 -29
- data/lib/dry/validation/extensions/predicates_as_macros.rb +75 -0
- data/lib/dry/validation/function.rb +11 -8
- data/lib/dry/validation/rule.rb +2 -0
- data/lib/dry/validation/schema_ext.rb +34 -0
- data/lib/dry/validation/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aadb0a6e283c3de0438b2ddf7335262e276c206021e95f4aaa7eb70be040f268
|
4
|
+
data.tar.gz: e2c9949f4f69ded243970367602b997c8eba80c5d18b223f7f14d30d914b4886
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7cd158435b3998c6864a594d61315760b974a4b8d8a8728bdff42cc3684209416a23a154e0efe9537ab54839f96819b4b11f434104b2ba5b2be6dd4fce4c39b5
|
7
|
+
data.tar.gz: d796476595c68a33dca5cf26cb11f3aff0c3fc2be73165f5693bb9b62c94c02a917ff8f559cc62055909805d95928dc96189e8a1391657177a21674ab15b58f5
|
data/CHANGELOG.md
CHANGED
@@ -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.
|
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.
|
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]
|
data/lib/dry/validation.rb
CHANGED
@@ -116,11 +116,20 @@ module Dry
|
|
116
116
|
private
|
117
117
|
|
118
118
|
# @api private
|
119
|
-
def error?(result,
|
120
|
-
path = Schema::Path[
|
119
|
+
def error?(result, spec)
|
120
|
+
path = Schema::Path[spec]
|
121
121
|
|
122
|
-
result.error?(path)
|
123
|
-
|
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 =
|
186
|
-
.map
|
187
|
-
|
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
|
-
# @
|
31
|
+
# @param [Proc] block Callable
|
32
|
+
# @return Hash
|
27
33
|
#
|
28
34
|
# @api private
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
@block_options ||= block
|
35
|
+
def map_keywords(block)
|
36
|
+
block
|
33
37
|
.parameters
|
34
|
-
.select { |arg
|
35
|
-
.map
|
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
|
data/lib/dry/validation/rule.rb
CHANGED
@@ -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
|
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
|
+
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-
|
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
|
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
|
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
|