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.
@@ -8,14 +8,7 @@ module Dry
8
8
  class MessageSet
9
9
  include Enumerable
10
10
 
11
- HINT_EXCLUSION = %i(
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
- failures? ? messages_map : hints_map
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
- failures.group_by(&:path).reduce(placeholders) do |hash, (path, msgs)|
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 hint_groups
97
- @hint_groups ||= hints.group_by(&:path)
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 = paths.reduce({}) do |hash, path|
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
@@ -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.new
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.load
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
- path = "%{locale}.rules.#{name}"
70
- get(path, options) if key?(path, options)
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]).join(DOT)
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
- ::I18n.load_path.concat(config.paths)
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}.rules.#{namespace}")) + super
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.load(paths = config.paths)
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
- data[key % { locale: options.fetch(:locale, default_locale) }]
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
- data.key?(key % { locale: options.fetch(:locale, default_locale) })
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
@@ -105,29 +105,7 @@ module Dry
105
105
  #
106
106
  # @api public
107
107
  def errors(options = EMPTY_HASH)
108
- message_set(options.merge(hints: false)).dump
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
- [:set, rules.values.map(&:to_ast)]
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
@@ -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
- opts.each do |predicate, *args|
44
+ pred_opts.each do |predicate, *args|
42
45
  append(__send__(predicate, *args))
43
46
  end
44
47
 
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module Schema
3
- VERSION = '0.1.1'.freeze
3
+ VERSION = '0.2.0'.freeze
4
4
  end
5
5
  end
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.1.1
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-17 00:00:00.000000000 Z
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: '0'
252
+ version: '2.4'
247
253
  required_rubygems_version: !ruby/object:Gem::Requirement
248
254
  requirements:
249
255
  - - ">="