dry-schema 0.1.1 → 0.2.0
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 +29 -0
- data/config/errors.yml +56 -55
- data/lib/dry/schema/compiler.rb +17 -0
- data/lib/dry/schema/dsl.rb +1 -1
- data/lib/dry/schema/extensions.rb +4 -0
- data/lib/dry/schema/extensions/hints.rb +52 -0
- data/lib/dry/schema/extensions/hints/message_compiler_methods.rb +72 -0
- data/lib/dry/schema/extensions/hints/message_set_methods.rb +29 -0
- data/lib/dry/schema/extensions/hints/result_methods.rb +38 -0
- data/lib/dry/schema/macros.rb +1 -0
- data/lib/dry/schema/macros/dsl.rb +22 -1
- data/lib/dry/schema/macros/filled.rb +8 -4
- data/lib/dry/schema/macros/hash.rb +3 -30
- data/lib/dry/schema/macros/key.rb +6 -6
- data/lib/dry/schema/macros/schema.rb +44 -0
- data/lib/dry/schema/macros/value.rb +9 -0
- data/lib/dry/schema/message.rb +13 -25
- data/lib/dry/schema/message_compiler.rb +31 -32
- data/lib/dry/schema/message_compiler/visitor_opts.rb +26 -0
- data/lib/dry/schema/message_set.rb +7 -47
- data/lib/dry/schema/messages.rb +5 -3
- data/lib/dry/schema/messages/abstract.rb +14 -3
- data/lib/dry/schema/messages/i18n.rb +15 -1
- data/lib/dry/schema/messages/namespaced.rb +16 -1
- data/lib/dry/schema/messages/yaml.rb +13 -4
- data/lib/dry/schema/namespaced_rule.rb +23 -0
- data/lib/dry/schema/result.rb +1 -23
- data/lib/dry/schema/rule_applier.rb +5 -1
- data/lib/dry/schema/trace.rb +4 -1
- data/lib/dry/schema/version.rb +1 -1
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bfbb04d5a9d9537294ec0e1d6fce172c2a6feb8a26ec13157ccc3f15120eee6f
|
4
|
+
data.tar.gz: 1c85541e6b71d1d44fc6abeb99350ef51abf7f8e2279556055f8f66cbb9e2373
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8b8b1023ed9256358d8ed96998be33070fe82c983e7d511e38f01d18da1fc1702ac2ea82f3fa02a83d9494d3822a3ce304662cc806ec6f4a16198d1db040444
|
7
|
+
data.tar.gz: fe668ebfb35ecee7ddc41c34d77fbde0abb9d3c8e98c192657036e8503bbde708c72b783a9f5ae1e6b9a366bee26b2217c78b4652e17d88219b3c4edaa74d6b9
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,32 @@
|
|
1
|
+
# 0.2.0 2019-02-26
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* New `hash` macro which prepends `hash?` type-check and allows nested schema definition (solnic)
|
6
|
+
* New `array` macro which works like `each` but prepends `array?` type-check (solnic)
|
7
|
+
|
8
|
+
### Fixed
|
9
|
+
|
10
|
+
* Rule name translation works correctly with I18n (issue #52) (solnic)
|
11
|
+
* Rule name translation works correctly with namespaced messages (both I18n and plain YAML) (issue #57) (solnic)
|
12
|
+
* Error messages under namespaces are correctly resolved for overridden names (issue #53) (solnic)
|
13
|
+
* Namespaced error messages work correctly when schemas are reused within other schemas (issue #49) (solnic)
|
14
|
+
* Child schema can override inherited rules now (issue #66) (skryukov)
|
15
|
+
* Hints are correctly generated for disjunction that use type-check predicates (issue #24) (solnic)
|
16
|
+
* Hints are correctly generated for nested schemas (issue #26) (solnic)
|
17
|
+
* `filled` macro respects inferred type-check predicates and puts them in front (solnic)
|
18
|
+
* Value coercion works correctly with re-usable nested schemas (issue #25) (solnic)
|
19
|
+
|
20
|
+
### Changed
|
21
|
+
|
22
|
+
* [BREAKING] **Messages are now configured under `dry_schema` namespace by default** (issue #38) (solnic)
|
23
|
+
* [BREAKING] Hints are now an optional feature provided by `:hints` extension, to load it do `Dry::Schema.load_extensions(:hints)` (solnic)
|
24
|
+
* [BREAKING] Hints generation was improved in general, output of `Result#messages` and `Result#hints` changed in some cases (solnic)
|
25
|
+
* [BREAKING] `schema` macro no longer prepends `hash?` check, for this behavior use the new `hash` macro (see #31) (solnic)
|
26
|
+
* [BREAKING] Support for MRI < 2.4 was dropped (solnic)
|
27
|
+
|
28
|
+
[Compare v0.1.1...v0.2.0](https://github.com/dry-rb/dry-schema/compare/v0.1.1...v0.2.0)
|
29
|
+
|
1
30
|
# 0.1.1 2019-02-17
|
2
31
|
|
3
32
|
### Added
|
data/config/errors.yml
CHANGED
@@ -1,91 +1,92 @@
|
|
1
1
|
en:
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
dry_schema:
|
3
|
+
errors:
|
4
|
+
or: "or"
|
5
|
+
array?: "must be an array"
|
5
6
|
|
6
|
-
|
7
|
+
empty?: "must be empty"
|
7
8
|
|
8
|
-
|
9
|
+
excludes?: "must not include %{value}"
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
excluded_from?:
|
12
|
+
arg:
|
13
|
+
default: "must not be one of: %{list}"
|
14
|
+
range: "must not be one of: %{list_left} - %{list_right}"
|
15
|
+
exclusion?: "must not be one of: %{list}"
|
15
16
|
|
16
|
-
|
17
|
+
eql?: "must be equal to %{left}"
|
17
18
|
|
18
|
-
|
19
|
+
not_eql?: "must not be equal to %{left}"
|
19
20
|
|
20
|
-
|
21
|
+
filled?: "must be filled"
|
21
22
|
|
22
|
-
|
23
|
+
format?: "is in invalid format"
|
23
24
|
|
24
|
-
|
25
|
+
number?: "must be a number"
|
25
26
|
|
26
|
-
|
27
|
+
odd?: "must be odd"
|
27
28
|
|
28
|
-
|
29
|
+
even?: "must be even"
|
29
30
|
|
30
|
-
|
31
|
+
gt?: "must be greater than %{num}"
|
31
32
|
|
32
|
-
|
33
|
+
gteq?: "must be greater than or equal to %{num}"
|
33
34
|
|
34
|
-
|
35
|
+
hash?: "must be a hash"
|
35
36
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
included_in?:
|
38
|
+
arg:
|
39
|
+
default: "must be one of: %{list}"
|
40
|
+
range: "must be one of: %{list_left} - %{list_right}"
|
41
|
+
inclusion?: "must be one of: %{list}"
|
41
42
|
|
42
|
-
|
43
|
+
includes?: "must include %{value}"
|
43
44
|
|
44
|
-
|
45
|
+
bool?: "must be boolean"
|
45
46
|
|
46
|
-
|
47
|
+
true?: "must be true"
|
47
48
|
|
48
|
-
|
49
|
+
false?: "must be false"
|
49
50
|
|
50
|
-
|
51
|
+
int?: "must be an integer"
|
51
52
|
|
52
|
-
|
53
|
+
float?: "must be a float"
|
53
54
|
|
54
|
-
|
55
|
+
decimal?: "must be a decimal"
|
55
56
|
|
56
|
-
|
57
|
+
date?: "must be a date"
|
57
58
|
|
58
|
-
|
59
|
+
date_time?: "must be a date time"
|
59
60
|
|
60
|
-
|
61
|
+
time?: "must be a time"
|
61
62
|
|
62
|
-
|
63
|
+
key?: "is missing"
|
63
64
|
|
64
|
-
|
65
|
+
attr?: "is missing"
|
65
66
|
|
66
|
-
|
67
|
+
lt?: "must be less than %{num}"
|
67
68
|
|
68
|
-
|
69
|
+
lteq?: "must be less than or equal to %{num}"
|
69
70
|
|
70
|
-
|
71
|
+
max_size?: "size cannot be greater than %{num}"
|
71
72
|
|
72
|
-
|
73
|
+
min_size?: "size cannot be less than %{num}"
|
73
74
|
|
74
|
-
|
75
|
+
nil?: "cannot be defined"
|
75
76
|
|
76
|
-
|
77
|
+
str?: "must be a string"
|
77
78
|
|
78
|
-
|
79
|
+
type?: "must be %{type}"
|
79
80
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
81
|
+
size?:
|
82
|
+
arg:
|
83
|
+
default: "size must be %{size}"
|
84
|
+
range: "size must be within %{size_left} - %{size_right}"
|
84
85
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
86
|
+
value:
|
87
|
+
string:
|
88
|
+
arg:
|
89
|
+
default: "length must be %{size}"
|
90
|
+
range: "length must be within %{size_left} - %{size_right}"
|
91
|
+
not:
|
92
|
+
empty?: "cannot be empty"
|
data/lib/dry/schema/compiler.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'dry/logic/rule_compiler'
|
2
|
+
require 'dry/schema/namespaced_rule'
|
2
3
|
require 'dry/schema/predicate_registry'
|
3
4
|
|
4
5
|
module Dry
|
@@ -16,6 +17,22 @@ module Dry
|
|
16
17
|
super
|
17
18
|
end
|
18
19
|
|
20
|
+
# Build a special rule that will produce namespaced failures
|
21
|
+
#
|
22
|
+
# This is needed for schemas that are namespaced and they are
|
23
|
+
# used as nested schemas
|
24
|
+
#
|
25
|
+
# @param [Array] node
|
26
|
+
# @param [Hash] opts
|
27
|
+
#
|
28
|
+
# @return [NamespacedRule]
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
def visit_namespace(node, opts = EMPTY_HASH)
|
32
|
+
namespace, rest = node
|
33
|
+
NamespacedRule.new(namespace, visit(rest))
|
34
|
+
end
|
35
|
+
|
19
36
|
# Return true if a given predicate is supported by this compiler
|
20
37
|
#
|
21
38
|
# @param [Symbol] predicate
|
data/lib/dry/schema/dsl.rb
CHANGED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'dry/schema/message'
|
2
|
+
require 'dry/schema/message_compiler'
|
3
|
+
|
4
|
+
require 'dry/schema/extensions/hints/message_compiler_methods'
|
5
|
+
require 'dry/schema/extensions/hints/message_set_methods'
|
6
|
+
require 'dry/schema/extensions/hints/result_methods'
|
7
|
+
|
8
|
+
module Dry
|
9
|
+
module Schema
|
10
|
+
# Hint-specific Message extensions
|
11
|
+
#
|
12
|
+
# @see Message
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
class Message
|
16
|
+
# @see Message::Or
|
17
|
+
#
|
18
|
+
# @api public
|
19
|
+
class Or
|
20
|
+
# @api private
|
21
|
+
def hint?
|
22
|
+
false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
def hint?
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# A hint message sub-type
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
class Hint < Message
|
36
|
+
def self.[](predicate, path, text, options)
|
37
|
+
Hint.new(predicate, path, text, options)
|
38
|
+
end
|
39
|
+
|
40
|
+
# @api private
|
41
|
+
def hint?
|
42
|
+
true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
module Extensions
|
47
|
+
MessageCompiler.prepend(Hints::MessageCompilerMethods)
|
48
|
+
MessageSet.prepend(Hints::MessageSetMethods)
|
49
|
+
Result.prepend(Hints::ResultMethods)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Dry
|
2
|
+
module Schema
|
3
|
+
module Extensions
|
4
|
+
module Hints
|
5
|
+
module MessageCompilerMethods
|
6
|
+
HINT_TYPE_EXCLUSION = %i[
|
7
|
+
key? nil? bool? str? int? float? decimal?
|
8
|
+
date? date_time? time? hash? array?
|
9
|
+
].freeze
|
10
|
+
|
11
|
+
HINT_OTHER_EXCLUSION = %i[format? filled?].freeze
|
12
|
+
|
13
|
+
attr_reader :hints
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
super
|
17
|
+
@hints = @options.fetch(:hints, true)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @api private
|
21
|
+
def hints?
|
22
|
+
hints.equal?(true)
|
23
|
+
end
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
def filter(messages, opts)
|
27
|
+
Array(messages).flatten.map { |msg| msg unless exclude?(msg, opts) }.compact.uniq
|
28
|
+
end
|
29
|
+
|
30
|
+
# @api private
|
31
|
+
def exclude?(messages, opts)
|
32
|
+
Array(messages).all? do |msg|
|
33
|
+
hints = opts.hints.reject { |hint| msg == hint }.reject { |hint| hint.predicate == :filled? }
|
34
|
+
key_failure = opts.key_failure?(msg.path)
|
35
|
+
predicate = msg.predicate
|
36
|
+
|
37
|
+
(HINT_TYPE_EXCLUSION.include?(predicate) && !key_failure) ||
|
38
|
+
(msg.predicate == :filled? && key_failure) ||
|
39
|
+
(!key_failure && HINT_TYPE_EXCLUSION.include?(predicate) && !hints.empty? && hints.any? { |hint| hint.path == msg.path }) ||
|
40
|
+
HINT_OTHER_EXCLUSION.include?(predicate)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# @api private
|
45
|
+
def message_type(options)
|
46
|
+
options[:message_type].equal?(:hint) ? Hint : Message
|
47
|
+
end
|
48
|
+
|
49
|
+
# @api private
|
50
|
+
def visit_hint(node, opts)
|
51
|
+
if hints?
|
52
|
+
filter(visit(node, opts.(message_type: :hint)), opts)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# @api private
|
57
|
+
def visit_predicate(node, opts)
|
58
|
+
message = super
|
59
|
+
opts.current_messages << message
|
60
|
+
message
|
61
|
+
end
|
62
|
+
|
63
|
+
# @api private
|
64
|
+
def visit_each(node, opts)
|
65
|
+
# TODO: we can still generate a hint for elements here!
|
66
|
+
[]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Dry
|
2
|
+
module Schema
|
3
|
+
module Extensions
|
4
|
+
module Hints
|
5
|
+
module MessageSetMethods
|
6
|
+
attr_reader :hints, :failures
|
7
|
+
|
8
|
+
# @api private
|
9
|
+
def initialize(messages, options = EMPTY_HASH)
|
10
|
+
super
|
11
|
+
@hints = messages.select(&:hint?)
|
12
|
+
end
|
13
|
+
|
14
|
+
# @api public
|
15
|
+
def to_h
|
16
|
+
failures? ? messages_map : messages_map(hints)
|
17
|
+
end
|
18
|
+
alias_method :to_hash, :to_h
|
19
|
+
alias_method :dump, :to_h
|
20
|
+
|
21
|
+
# @api private
|
22
|
+
def failures?
|
23
|
+
options[:failures].equal?(true)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Dry
|
2
|
+
module Schema
|
3
|
+
module Extensions
|
4
|
+
module Hints
|
5
|
+
module ResultMethods
|
6
|
+
# @see Result#errors
|
7
|
+
#
|
8
|
+
# @api public
|
9
|
+
def errors(options = EMPTY_HASH)
|
10
|
+
message_set(options.merge(hints: false)).dump
|
11
|
+
end
|
12
|
+
|
13
|
+
# Get all messages including hints
|
14
|
+
#
|
15
|
+
# @see #message_set
|
16
|
+
#
|
17
|
+
# @return [Hash<Symbol=>Array>]
|
18
|
+
#
|
19
|
+
# @api public
|
20
|
+
def messages(options = EMPTY_HASH)
|
21
|
+
message_set(options).dump
|
22
|
+
end
|
23
|
+
|
24
|
+
# Get hints exclusively without errors
|
25
|
+
#
|
26
|
+
# @see #message_set
|
27
|
+
#
|
28
|
+
# @return [Hash<Symbol=>Array>]
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
def hints(options = EMPTY_HASH)
|
32
|
+
message_set(options.merge(failures: false)).dump
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|