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
@@ -8,14 +8,7 @@ module Dry
|
|
8
8
|
class MessageSet
|
9
9
|
include Enumerable
|
10
10
|
|
11
|
-
|
12
|
-
key? filled? nil? bool?
|
13
|
-
str? int? float? decimal?
|
14
|
-
date? date_time? time? hash?
|
15
|
-
array? format?
|
16
|
-
).freeze
|
17
|
-
|
18
|
-
attr_reader :messages, :failures, :hints, :paths, :placeholders, :options
|
11
|
+
attr_reader :messages, :placeholders, :options
|
19
12
|
|
20
13
|
# @api private
|
21
14
|
def self.[](messages, options = EMPTY_HASH)
|
@@ -25,12 +18,7 @@ module Dry
|
|
25
18
|
# @api private
|
26
19
|
def initialize(messages, options = EMPTY_HASH)
|
27
20
|
@messages = messages
|
28
|
-
@hints = messages.select(&:hint?)
|
29
|
-
@failures = messages - hints
|
30
|
-
@paths = failures.map(&:path).uniq
|
31
21
|
@options = options
|
32
|
-
|
33
|
-
initialize_hints!
|
34
22
|
initialize_placeholders!
|
35
23
|
end
|
36
24
|
|
@@ -42,16 +30,11 @@ module Dry
|
|
42
30
|
|
43
31
|
# @api public
|
44
32
|
def to_h
|
45
|
-
|
33
|
+
messages_map
|
46
34
|
end
|
47
35
|
alias_method :to_hash, :to_h
|
48
36
|
alias_method :dump, :to_h
|
49
37
|
|
50
|
-
# @api private
|
51
|
-
def failures?
|
52
|
-
options[:failures].equal?(true)
|
53
|
-
end
|
54
|
-
|
55
38
|
# @api private
|
56
39
|
def empty?
|
57
40
|
messages.empty?
|
@@ -60,26 +43,8 @@ module Dry
|
|
60
43
|
private
|
61
44
|
|
62
45
|
# @api private
|
63
|
-
def messages_map
|
64
|
-
|
65
|
-
node = path.reduce(hash) { |a, e| a[e] }
|
66
|
-
|
67
|
-
msgs.each do |msg|
|
68
|
-
node << msg
|
69
|
-
end
|
70
|
-
|
71
|
-
msg_hints = hint_groups[path]
|
72
|
-
node.concat(msg_hints) if msg_hints
|
73
|
-
|
74
|
-
node.map!(&:to_s)
|
75
|
-
|
76
|
-
hash
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
# @api private
|
81
|
-
def hints_map
|
82
|
-
hints.group_by(&:path).reduce(placeholders) do |hash, (path, msgs)|
|
46
|
+
def messages_map(messages = self.messages)
|
47
|
+
messages.group_by(&:path).reduce(placeholders) do |hash, (path, msgs)|
|
83
48
|
node = path.reduce(hash) { |a, e| a[e] }
|
84
49
|
|
85
50
|
msgs.each do |msg|
|
@@ -93,18 +58,13 @@ module Dry
|
|
93
58
|
end
|
94
59
|
|
95
60
|
# @api private
|
96
|
-
def
|
97
|
-
@
|
98
|
-
end
|
99
|
-
|
100
|
-
# @api private
|
101
|
-
def initialize_hints!
|
102
|
-
hints.reject! { |hint| HINT_EXCLUSION.include?(hint.predicate) }
|
61
|
+
def paths
|
62
|
+
@paths ||= messages.map(&:path).uniq
|
103
63
|
end
|
104
64
|
|
105
65
|
# @api private
|
106
66
|
def initialize_placeholders!
|
107
|
-
@placeholders =
|
67
|
+
@placeholders = messages.map(&:path).uniq.reduce({}) do |hash, path|
|
108
68
|
curr_idx = 0
|
109
69
|
last_idx = path.size - 1
|
110
70
|
node = hash
|
data/lib/dry/schema/messages.rb
CHANGED
@@ -20,17 +20,19 @@ module Dry
|
|
20
20
|
|
21
21
|
# @api private
|
22
22
|
def self.build(config)
|
23
|
-
case config.messages
|
23
|
+
klass = case config.messages
|
24
24
|
when :yaml then default
|
25
|
-
when :i18n then Messages::I18n
|
25
|
+
when :i18n then Messages::I18n
|
26
26
|
else
|
27
27
|
raise "+#{config.messages}+ is not a valid messages identifier"
|
28
28
|
end
|
29
|
+
|
30
|
+
klass.build
|
29
31
|
end
|
30
32
|
|
31
33
|
# @api private
|
32
34
|
def self.default
|
33
|
-
Messages::YAML
|
35
|
+
Messages::YAML
|
34
36
|
end
|
35
37
|
end
|
36
38
|
end
|
@@ -34,6 +34,10 @@ module Dry
|
|
34
34
|
%{root}.%{predicate}
|
35
35
|
).freeze
|
36
36
|
|
37
|
+
setting :rule_lookup_paths, %w(
|
38
|
+
rules.%{name}
|
39
|
+
).freeze
|
40
|
+
|
37
41
|
setting :arg_type_default, 'default'.freeze
|
38
42
|
setting :val_type_default, 'default'.freeze
|
39
43
|
|
@@ -66,8 +70,10 @@ module Dry
|
|
66
70
|
|
67
71
|
# @api private
|
68
72
|
def rule(name, options = {})
|
69
|
-
|
70
|
-
|
73
|
+
tokens = { name: name, locale: options.fetch(:locale, default_locale) }
|
74
|
+
path = rule_lookup_paths(tokens).detect { |key| key?(key, options) }
|
75
|
+
|
76
|
+
get(path, options) if path
|
71
77
|
end
|
72
78
|
|
73
79
|
# Retrieve a message template
|
@@ -95,7 +101,7 @@ module Dry
|
|
95
101
|
message_type: options[:message_type] || :failure
|
96
102
|
)
|
97
103
|
|
98
|
-
tokens[:path] = options[:rule] || Array(options[:path]).
|
104
|
+
tokens[:path] = options[:rule] || Array(options[:path]).last
|
99
105
|
|
100
106
|
opts = options.select { |k, _| !config.lookup_options.include?(k) }
|
101
107
|
|
@@ -111,6 +117,11 @@ module Dry
|
|
111
117
|
config.lookup_paths.map { |path| path % tokens }
|
112
118
|
end
|
113
119
|
|
120
|
+
# @api private
|
121
|
+
def rule_lookup_paths(tokens)
|
122
|
+
config.rule_lookup_paths.map { |key| key % tokens }
|
123
|
+
end
|
124
|
+
|
114
125
|
# Return a new message backend that will look for messages under provided namespace
|
115
126
|
#
|
116
127
|
# @param [Symbol,String] namespace
|
@@ -9,7 +9,21 @@ module Dry
|
|
9
9
|
class Messages::I18n < Messages::Abstract
|
10
10
|
attr_reader :t
|
11
11
|
|
12
|
-
|
12
|
+
configure do |config|
|
13
|
+
config.root = 'dry_schema.errors'.freeze
|
14
|
+
config.rule_lookup_paths = config.rule_lookup_paths.map { |path| "dry_schema.#{path}" }
|
15
|
+
end
|
16
|
+
|
17
|
+
# @api private
|
18
|
+
def self.build(paths = config.paths)
|
19
|
+
set_load_paths(paths)
|
20
|
+
new
|
21
|
+
end
|
22
|
+
|
23
|
+
# @api private
|
24
|
+
def self.set_load_paths(paths)
|
25
|
+
::I18n.load_path.concat(paths)
|
26
|
+
end
|
13
27
|
|
14
28
|
# @api private
|
15
29
|
def initialize
|
@@ -14,12 +14,16 @@ module Dry
|
|
14
14
|
# @api private
|
15
15
|
attr_reader :root
|
16
16
|
|
17
|
+
# @api private
|
18
|
+
attr_reader :call_opts
|
19
|
+
|
17
20
|
# @api private
|
18
21
|
def initialize(namespace, messages)
|
19
22
|
super()
|
20
23
|
@namespace = namespace
|
21
24
|
@messages = messages
|
22
25
|
@root = messages.root
|
26
|
+
@call_opts = { namespace: namespace }.freeze
|
23
27
|
end
|
24
28
|
|
25
29
|
# Get a message for the given key and its options
|
@@ -34,6 +38,12 @@ module Dry
|
|
34
38
|
messages.get(key, options)
|
35
39
|
end
|
36
40
|
|
41
|
+
# @api public
|
42
|
+
def call(key, options = {})
|
43
|
+
super(key, options.empty? ? call_opts : options.merge(call_opts))
|
44
|
+
end
|
45
|
+
alias_method :[], :call
|
46
|
+
|
37
47
|
# Check if given key is defined
|
38
48
|
#
|
39
49
|
# @return [Boolean]
|
@@ -45,7 +55,12 @@ module Dry
|
|
45
55
|
|
46
56
|
# @api private
|
47
57
|
def lookup_paths(tokens)
|
48
|
-
super(tokens.merge(root: "#{root}
|
58
|
+
super(tokens.merge(root: "#{tokens[:root]}.#{namespace}")) + super
|
59
|
+
end
|
60
|
+
|
61
|
+
def rule_lookup_paths(tokens)
|
62
|
+
base_paths = messages.rule_lookup_paths(tokens)
|
63
|
+
base_paths.map { |key| key.gsub("dry_schema", "dry_schema.#{namespace}") } + base_paths
|
49
64
|
end
|
50
65
|
end
|
51
66
|
end
|
@@ -16,11 +16,12 @@ module Dry
|
|
16
16
|
|
17
17
|
# @api private
|
18
18
|
configure do |config|
|
19
|
-
config.root = '%{locale}.errors'.freeze
|
19
|
+
config.root = '%{locale}.dry_schema.errors'.freeze
|
20
|
+
config.rule_lookup_paths = config.rule_lookup_paths.map { |path| "%{locale}.dry_schema.#{path}" }
|
20
21
|
end
|
21
22
|
|
22
23
|
# @api private
|
23
|
-
def self.
|
24
|
+
def self.build(paths = config.paths)
|
24
25
|
new(paths.map { |path| load_file(path) }.reduce(:merge))
|
25
26
|
end
|
26
27
|
|
@@ -51,7 +52,11 @@ module Dry
|
|
51
52
|
#
|
52
53
|
# @api public
|
53
54
|
def get(key, options = {})
|
54
|
-
|
55
|
+
evaluated_key = key.include?('%{locale}') ?
|
56
|
+
key % { locale: options.fetch(:locale, default_locale) } :
|
57
|
+
key
|
58
|
+
|
59
|
+
data[evaluated_key]
|
55
60
|
end
|
56
61
|
|
57
62
|
# Check if given key is defined
|
@@ -60,7 +65,11 @@ module Dry
|
|
60
65
|
#
|
61
66
|
# @api public
|
62
67
|
def key?(key, options = {})
|
63
|
-
|
68
|
+
evaluated_key = key.include?('%{locale}') ?
|
69
|
+
key % { locale: options.fetch(:locale, default_locale) } :
|
70
|
+
key
|
71
|
+
|
72
|
+
data.key?(evaluated_key)
|
64
73
|
end
|
65
74
|
|
66
75
|
# Merge messages from an additional path
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Dry
|
2
|
+
module Schema
|
3
|
+
class NamespacedRule
|
4
|
+
attr_reader :rule
|
5
|
+
|
6
|
+
attr_reader :namespace
|
7
|
+
|
8
|
+
def initialize(namespace, rule)
|
9
|
+
@namespace = namespace
|
10
|
+
@rule = rule
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(input)
|
14
|
+
result = rule.call(input)
|
15
|
+
Logic::Result.new(result.success?) { [:namespace, [namespace, result.to_ast]] }
|
16
|
+
end
|
17
|
+
|
18
|
+
def ast(input=Undefined)
|
19
|
+
[:namespace, [namespace, rule.ast(input)]]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/dry/schema/result.rb
CHANGED
@@ -105,29 +105,7 @@ module Dry
|
|
105
105
|
#
|
106
106
|
# @api public
|
107
107
|
def errors(options = EMPTY_HASH)
|
108
|
-
message_set(options
|
109
|
-
end
|
110
|
-
|
111
|
-
# Get all messages including hints
|
112
|
-
#
|
113
|
-
# @see #message_set
|
114
|
-
#
|
115
|
-
# @return [Hash<Symbol=>Array>]
|
116
|
-
#
|
117
|
-
# @api public
|
118
|
-
def messages(options = EMPTY_HASH)
|
119
|
-
message_set(options.merge(hints: true)).dump
|
120
|
-
end
|
121
|
-
|
122
|
-
# Get hints exclusively without errors
|
123
|
-
#
|
124
|
-
# @see #message_set
|
125
|
-
#
|
126
|
-
# @return [Hash<Symbol=>Array>]
|
127
|
-
#
|
128
|
-
# @api public
|
129
|
-
def hints(options = EMPTY_HASH)
|
130
|
-
message_set(options.merge(failures: false)).dump
|
108
|
+
message_set(options).dump
|
131
109
|
end
|
132
110
|
|
133
111
|
# Return the message set
|
@@ -38,7 +38,11 @@ module Dry
|
|
38
38
|
|
39
39
|
# @api private
|
40
40
|
def to_ast
|
41
|
-
|
41
|
+
if config.namespace
|
42
|
+
[:namespace, [config.namespace, [:set, rules.values.map(&:to_ast)]]]
|
43
|
+
else
|
44
|
+
[:set, rules.values.map(&:to_ast)]
|
45
|
+
end
|
42
46
|
end
|
43
47
|
end
|
44
48
|
end
|
data/lib/dry/schema/trace.rb
CHANGED
@@ -28,6 +28,9 @@ module Dry
|
|
28
28
|
|
29
29
|
# @api private
|
30
30
|
def evaluate(*predicates, **opts, &block)
|
31
|
+
pred_opts = opts.dup
|
32
|
+
pred_opts.delete(:type_spec)
|
33
|
+
|
31
34
|
predicates.each do |predicate|
|
32
35
|
if predicate.respond_to?(:call)
|
33
36
|
append(predicate)
|
@@ -38,7 +41,7 @@ module Dry
|
|
38
41
|
end
|
39
42
|
end
|
40
43
|
|
41
|
-
|
44
|
+
pred_opts.each do |predicate, *args|
|
42
45
|
append(__send__(predicate, *args))
|
43
46
|
end
|
44
47
|
|
data/lib/dry/schema/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-schema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.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-02-
|
11
|
+
date: 2019-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -192,6 +192,10 @@ files:
|
|
192
192
|
- lib/dry/schema/constants.rb
|
193
193
|
- lib/dry/schema/dsl.rb
|
194
194
|
- lib/dry/schema/extensions.rb
|
195
|
+
- lib/dry/schema/extensions/hints.rb
|
196
|
+
- lib/dry/schema/extensions/hints/message_compiler_methods.rb
|
197
|
+
- lib/dry/schema/extensions/hints/message_set_methods.rb
|
198
|
+
- lib/dry/schema/extensions/hints/result_methods.rb
|
195
199
|
- lib/dry/schema/extensions/monads.rb
|
196
200
|
- lib/dry/schema/json.rb
|
197
201
|
- lib/dry/schema/key.rb
|
@@ -207,6 +211,7 @@ files:
|
|
207
211
|
- lib/dry/schema/macros/maybe.rb
|
208
212
|
- lib/dry/schema/macros/optional.rb
|
209
213
|
- lib/dry/schema/macros/required.rb
|
214
|
+
- lib/dry/schema/macros/schema.rb
|
210
215
|
- lib/dry/schema/macros/value.rb
|
211
216
|
- lib/dry/schema/message.rb
|
212
217
|
- lib/dry/schema/message_compiler.rb
|
@@ -218,6 +223,7 @@ files:
|
|
218
223
|
- lib/dry/schema/messages/namespaced.rb
|
219
224
|
- lib/dry/schema/messages/template.rb
|
220
225
|
- lib/dry/schema/messages/yaml.rb
|
226
|
+
- lib/dry/schema/namespaced_rule.rb
|
221
227
|
- lib/dry/schema/params.rb
|
222
228
|
- lib/dry/schema/path.rb
|
223
229
|
- lib/dry/schema/predicate.rb
|
@@ -243,7 +249,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
243
249
|
requirements:
|
244
250
|
- - ">="
|
245
251
|
- !ruby/object:Gem::Version
|
246
|
-
version: '
|
252
|
+
version: '2.4'
|
247
253
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
248
254
|
requirements:
|
249
255
|
- - ">="
|