dry-schema 0.1.1 → 0.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 +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
|
- - ">="
|