dry-validation 0.13.2 → 0.13.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a31ac4653e7f148d6ee09543b38c81f9670bc40c51c8644414aacc000e66357
4
- data.tar.gz: 2c84a8c6b29bb290f3e24505a9f52c1abcc31c777b54ed4140bc38225e5410d2
3
+ metadata.gz: d569600e476b1c0830184bea7e9393f333693e11c1a9d8b074e2b2329deeba7a
4
+ data.tar.gz: 4811db9bc4e1cc3f398df8717333683355779116a72314532b10bc2d49a87333
5
5
  SHA512:
6
- metadata.gz: afb6b1de3fea9028ec2d4ffd481b9a49a79f2a9192c0101122a00c4b567d99e5d53083c130cc1789d643b9c80a5b7c98384e776d36c746a3ca1ff83ea80b1caf
7
- data.tar.gz: d287f0d13f12c65a476de805e6fd95175eea35da74b679dd0fcb98e8ac616e000cf465db769b2e53e5db2e082173c30a3c8c16cffe0537517e96dbd499e8d004
6
+ metadata.gz: c497db70c2bf78e3355c685176361b06357ee9d9f17a2c867127d4d575865f0e6cb1f5bafae4b595e1db3af8748fc6122e6522177a152e17e8e6119006591b3c
7
+ data.tar.gz: 2b93c44b453e47f6a68ec05bedaec9d2f48d001a6dc9d0f62f2f2d7b70de5f8c1a7130bfc33c558fff1129fceb69d37f33f341d38c96549570a684d7279d24b0
@@ -1,3 +1,16 @@
1
+ # v0.13.3 2019-05-21
2
+
3
+ ### Fixed
4
+
5
+ * Fixed regression with caching templates that rely on predicate arguments (solnic)
6
+ * Removed ugly workaround for template evaluation with extra tokens (solnic)
7
+
8
+ ### Changed
9
+
10
+ * [internal] `Messages::Abstract#call` returns a `Template` object now, this was backported from dry-schema (solnic)
11
+
12
+ [Compare v0.13.2...v0.13.3](https://github.com/dry-rb/dry-validation/compare/v0.13.2...v0.13.3)
13
+
1
14
  # v0.13.2 2019-05-12
2
15
 
3
16
  ### Fixed
@@ -32,7 +32,7 @@ module Dry
32
32
  end
33
33
 
34
34
  def to_s
35
- [left, right].uniq.join(" #{messages[:or]} ")
35
+ [left, right].uniq.join(" #{messages[:or].()} ")
36
36
  end
37
37
  end
38
38
 
@@ -160,9 +160,7 @@ module Dry
160
160
  end
161
161
 
162
162
  def message_text(rule, template, tokens, opts)
163
- original_verbosity = $VERBOSE
164
- $VERBOSE = nil
165
- text = template % tokens
163
+ text = template[template.data(tokens)]
166
164
 
167
165
  if full?
168
166
  rule_name = messages.rule(rule, opts) || rule
@@ -170,8 +168,6 @@ module Dry
170
168
  else
171
169
  text
172
170
  end
173
- ensure
174
- $VERBOSE = original_verbosity
175
171
  end
176
172
 
177
173
  def message_tokens(args)
@@ -1,8 +1,11 @@
1
1
  require 'pathname'
2
2
  require 'concurrent/map'
3
+
3
4
  require 'dry/equalizer'
4
5
  require 'dry/configurable'
5
6
 
7
+ require 'dry/validation/template'
8
+
6
9
  module Dry
7
10
  module Validation
8
11
  module Messages
@@ -62,23 +65,15 @@ module Dry
62
65
  end
63
66
 
64
67
  def call(predicate, options = EMPTY_HASH)
65
- cache.fetch_or_store(cache_key(predicate, options)) do
68
+ cache.fetch_or_store([predicate, options.reject { |k,| k.equal?(:input) }]) do
66
69
  path, opts = lookup(predicate, options)
67
- get(path, opts) if path
70
+ return unless path
71
+ text = yield(path, opts)
72
+ Template[text]
68
73
  end
69
74
  end
70
75
  alias_method :[], :call
71
76
 
72
- if ::Hash.instance_methods.include?(:slice)
73
- def cache_key(predicate, options)
74
- [predicate, options.slice(*CACHE_KEYS)]
75
- end
76
- else
77
- def cache_key(predicate, options)
78
- [predicate, options.select { |key,| CACHE_KEYS.include?(key) }]
79
- end
80
- end
81
-
82
77
  def lookup(predicate, options = {})
83
78
  tokens = options.merge(
84
79
  root: root,
@@ -112,7 +107,7 @@ module Dry
112
107
  end
113
108
 
114
109
  def cache
115
- @cache ||= self.class.cache[hash]
110
+ @cache ||= self.class.cache[self]
116
111
  end
117
112
 
118
113
  def default_locale
@@ -13,8 +13,15 @@ module Dry
13
13
  @t = I18n.method(:t)
14
14
  end
15
15
 
16
+ def call(predicate, options = EMPTY_HASH)
17
+ super do |path, opts|
18
+ get(path, opts)
19
+ end
20
+ end
21
+ alias_method :[], :call
22
+
16
23
  def get(key, options = {})
17
- t.(key, options) if key
24
+ t.(key, locale: options.fetch(:locale, default_locale)) if key
18
25
  end
19
26
 
20
27
  def rule(name, options = {})
@@ -11,6 +11,13 @@ module Dry
11
11
  @root = messages.root
12
12
  end
13
13
 
14
+ def call(predicate, options = EMPTY_HASH)
15
+ super do |path, opts|
16
+ messages.get(path, opts)
17
+ end
18
+ end
19
+ alias_method :[], :call
20
+
14
21
  def key?(key, *args)
15
22
  messages.key?(key, *args)
16
23
  end
@@ -34,6 +34,13 @@ module Dry
34
34
  @data = data
35
35
  end
36
36
 
37
+ def call(predicate, options = EMPTY_HASH)
38
+ super do |path, opts|
39
+ get(path, opts)
40
+ end
41
+ end
42
+ alias_method :[], :call
43
+
37
44
  def get(key, options = {})
38
45
  data[key % { locale: options.fetch(:locale, default_locale) }]
39
46
  end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/equalizer'
4
+
5
+ module Dry
6
+ module Validation
7
+ module Messages
8
+ # Template wraps a string with interpolation tokens and defines evaluator function
9
+ # dynamically
10
+ #
11
+ # @api private
12
+ class Template
13
+ include Dry::Equalizer(:text)
14
+
15
+ TOKEN_REGEXP = /%{(\w*)}/
16
+
17
+ # !@attribute [r] text
18
+ # @return [String]
19
+ attr_reader :text
20
+
21
+ # !@attribute [r] tokens
22
+ # @return [Hash]
23
+ attr_reader :tokens
24
+
25
+ # !@attribute [r] evaluator
26
+ # @return [Proc]
27
+ attr_reader :evaluator
28
+
29
+ # @api private
30
+ def self.[](input)
31
+ new(*parse(input))
32
+ end
33
+
34
+ # @api private
35
+ def self.parse(input)
36
+ tokens = input.scan(TOKEN_REGEXP).flatten(1).map(&:to_sym)
37
+ text = input.gsub('%', '#')
38
+
39
+ evaluator = <<-RUBY.strip
40
+ -> (#{tokens.map { |token| "#{token}:" }.join(", ")}) { "#{text}" }
41
+ RUBY
42
+
43
+ [text, tokens, eval(evaluator, binding, __FILE__, __LINE__ - 3)]
44
+ end
45
+
46
+ # @api private
47
+ def initialize(text, tokens, evaluator)
48
+ @text = text
49
+ @tokens = tokens
50
+ @evaluator = evaluator
51
+ end
52
+
53
+ # @api private
54
+ def data(input)
55
+ tokens.each_with_object({}) { |k, h| h[k] = input[k] }
56
+ end
57
+
58
+ # @api private
59
+ def call(data = EMPTY_HASH)
60
+ data.empty? ? evaluator.() : evaluator.(data)
61
+ end
62
+ alias_method :[], :call
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module Validation
3
- VERSION = '0.13.2'.freeze
3
+ VERSION = '0.13.3'.freeze
4
4
  end
5
5
  end
@@ -3,4 +3,6 @@ en:
3
3
  rules:
4
4
  email:
5
5
  filled?: "Please provide your email"
6
+ age:
7
+ gt?: "%{input} must be greater than %{num}"
6
8
  email?: "must be an email"
@@ -4,8 +4,12 @@ RSpec.describe Dry::Validation do
4
4
  shared_context 'schema with customized messages' do
5
5
  describe '#messages' do
6
6
  it 'returns compiled error messages' do
7
- expect(schema.(email: '').messages).to eql(
8
- email: ['Please provide your email']
7
+ expect(schema.(email: '', age: 12).messages).to eql(
8
+ email: ['Please provide your email'], age: ['12 must be greater than 18']
9
+ )
10
+
11
+ expect(schema.(email: '', age: 14).messages).to eql(
12
+ email: ['Please provide your email'], age: ['14 must be greater than 18']
9
13
  )
10
14
  end
11
15
  end
@@ -18,7 +22,8 @@ RSpec.describe Dry::Validation do
18
22
  config.messages_file = SPEC_ROOT.join('fixtures/locales/en.yml')
19
23
  end
20
24
 
21
- required(:email, &:filled?)
25
+ required(:email).filled
26
+ required(:age).value(gt?: 18)
22
27
  end
23
28
  end
24
29
 
@@ -38,7 +43,8 @@ RSpec.describe Dry::Validation do
38
43
  config.messages = :i18n
39
44
  end
40
45
 
41
- required(:email, &:filled?)
46
+ required(:email).filled
47
+ required(:age).value(gt?: 18)
42
48
  end
43
49
  end
44
50
 
@@ -17,33 +17,33 @@ RSpec.describe Messages::I18n do
17
17
  end
18
18
 
19
19
  it 'returns a message for a predicate' do
20
- message = messages[:filled?, rule: :name]
20
+ message = messages[:filled?, rule: :name].text
21
21
 
22
22
  expect(message).to eql("nie może być pusty")
23
23
  end
24
24
 
25
25
  it 'returns a message for a specific rule' do
26
- message = messages[:filled?, rule: :email]
26
+ message = messages[:filled?, rule: :email].text
27
27
 
28
28
  expect(message).to eql("Proszę podać adres email")
29
29
  end
30
30
 
31
31
  it 'returns a message for a specific val type' do
32
- message = messages[:size?, rule: :pages, val_type: String]
32
+ message = messages[:size?, rule: :pages, val_type: String].text
33
33
 
34
- expect(message).to eql("wielkość musi być równa %{size}")
34
+ expect(message).to eql("wielkość musi być równa \#{size}")
35
35
  end
36
36
 
37
37
  it 'returns a message for a specific rule and its default arg type' do
38
- message = messages[:size?, rule: :pages]
38
+ message = messages[:size?, rule: :pages].text
39
39
 
40
- expect(message).to eql("wielkość musi być równa %{size}")
40
+ expect(message).to eql("wielkość musi być równa \#{size}")
41
41
  end
42
42
 
43
43
  it 'returns a message for a specific rule and its arg type' do
44
- message = messages[:size?, rule: :pages, arg_type: Range]
44
+ message = messages[:size?, rule: :pages, arg_type: Range].text
45
45
 
46
- expect(message).to eql("wielkość musi być między %{size_left} a %{size_right}")
46
+ expect(message).to eql("wielkość musi być między \#{size_left} a \#{size_right}")
47
47
  end
48
48
  end
49
49
 
@@ -57,27 +57,27 @@ RSpec.describe Messages::I18n do
57
57
 
58
58
  context 'with a different locale' do
59
59
  it 'returns a message for a predicate' do
60
- message = messages[:filled?, rule: :name, locale: :en]
60
+ message = messages[:filled?, rule: :name, locale: :en].text
61
61
 
62
62
  expect(message).to eql("must be filled")
63
63
  end
64
64
 
65
65
  it 'returns a message for a specific rule' do
66
- message = messages[:filled?, rule: :email, locale: :en]
66
+ message = messages[:filled?, rule: :email, locale: :en].text
67
67
 
68
68
  expect(message).to eql("Please provide your email")
69
69
  end
70
70
 
71
71
  it 'returns a message for a specific rule and its default arg type' do
72
- message = messages[:size?, rule: :pages, locale: :en]
72
+ message = messages[:size?, rule: :pages, locale: :en].text
73
73
 
74
- expect(message).to eql("size must be %{size}")
74
+ expect(message).to eql("size must be \#{size}")
75
75
  end
76
76
 
77
77
  it 'returns a message for a specific rule and its arg type' do
78
- message = messages[:size?, rule: :pages, arg_type: Range, locale: :en]
78
+ message = messages[:size?, rule: :pages, arg_type: Range, locale: :en].text
79
79
 
80
- expect(message).to eql("size must be within %{size_left} - %{size_right}")
80
+ expect(message).to eql("size must be within \#{size_left} - \#{size_right}")
81
81
  end
82
82
  end
83
83
 
@@ -90,7 +90,7 @@ RSpec.describe Messages::I18n do
90
90
  it 'returns a message for a predicate in the default_locale' do
91
91
  pending 'FIXME: this got broken for some reason, probably an I18n issue'
92
92
 
93
- message = messages[:even?, rule: :some_number]
93
+ message = messages[:even?, rule: :some_number].text
94
94
 
95
95
  expect(I18n.locale).to eql(:pl)
96
96
  expect(message).to eql("must be even")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-validation
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.2
4
+ version: 0.13.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Holland
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-05-12 00:00:00.000000000 Z
12
+ date: 2019-05-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: concurrent-ruby
@@ -226,6 +226,7 @@ files:
226
226
  - lib/dry/validation/schema/rule.rb
227
227
  - lib/dry/validation/schema/value.rb
228
228
  - lib/dry/validation/schema_compiler.rb
229
+ - lib/dry/validation/template.rb
229
230
  - lib/dry/validation/type_specs.rb
230
231
  - lib/dry/validation/version.rb
231
232
  - log/.gitkeep