dry-schema 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b804e7069cd7d8764f82ce208e38768fa9975e6d1460e1e44917d5c0eaeee911
4
- data.tar.gz: 6814f96c49db2634895c20faf7b331feccbdcdcbc83ff89292f655acd6c0adfc
3
+ metadata.gz: ebc7203aa64419493d5557a5228e8ae17da67a89b7dab86556897aad7856138e
4
+ data.tar.gz: '083cad2ab1b35ecfac75a5d37a868f36145cce8ea31bf03dc10b3ad84233b498'
5
5
  SHA512:
6
- metadata.gz: 80d4cc2626025ef517e48bba83026c1bba7ef5797fa25e2543589ed503ec9d7142e799ed9713d4452b7a1f1b2d2988b4c6aeb3172230ec6fd4987d58c8621775
7
- data.tar.gz: f35d2b94570ec416b6fcb0457a4e685f37ff3a265a011a4016af611307e2d8d1b8b03dc9e4b59a63b5f2cf55aacf8ceabac0a5d689e73f14e4aaa5cef96e1fa4
6
+ metadata.gz: 0db3366b58c3fd06ad10958de4215ae5b2ff67f244873ff8b48b96da9bfcf08678a06ef3302099862891630b825596c6a4adfecac9140e8e5045ca7acc200b34
7
+ data.tar.gz: 04e3fa2ee8d50aaac7c6bcdaacb1611252ce06af397499cf0fbc0ed21fb33e62c55b9ab0179b4df9160bbd0efe1c6bed1c60ac628c06f23f992879df8c6326ed
@@ -1,3 +1,20 @@
1
+ # 0.1.1 2019-02-17
2
+
3
+ ### Added
4
+
5
+ - `Result#error?` supports checking nested errors too ie`result.error?('user.address')` (solnic)
6
+
7
+ ### Fixed
8
+
9
+ - Fix issues with templates and invalid tokens (issue #27) (solnic)
10
+ - Fix Ruby warnings (flash-gordon)
11
+
12
+ ### Internal
13
+
14
+ - Key and value coercers are now equalizable (flash-gordon)
15
+
16
+ [Compare v0.1.0...v0.1.1](https://github.com/dry-rb/dry-schema/compare/v0.1.0...v0.1.1)
17
+
1
18
  # 0.1.0 2019-01-30
2
19
 
3
20
  Initial release.
@@ -14,7 +14,7 @@ module Dry
14
14
  # @return [Processor]
15
15
  #
16
16
  # @api public
17
- def self.define(options = EMPTY_HASH, &block)
17
+ def self.define(**options, &block)
18
18
  DSL.new(options, &block).call
19
19
  end
20
20
 
@@ -90,7 +90,7 @@ module Dry
90
90
  # @return [DSL]
91
91
  #
92
92
  # @api public
93
- def self.new(options = EMPTY_HASH, &block)
93
+ def self.new(**options, &block)
94
94
  dsl = super
95
95
  dsl.instance_eval(&block) if block
96
96
  dsl
@@ -1,4 +1,5 @@
1
1
  require 'dry/core/cache'
2
+ require 'dry/equalizer'
2
3
 
3
4
  module Dry
4
5
  module Schema
@@ -7,6 +8,7 @@ module Dry
7
8
  # @api private
8
9
  class KeyCoercer
9
10
  extend Dry::Core::Cache
11
+ include ::Dry::Equalizer(:key_map, :coercer)
10
12
 
11
13
  TO_SYM = :to_sym.to_proc.freeze
12
14
 
@@ -26,7 +28,7 @@ module Dry
26
28
  def initialize(key_map, &coercer)
27
29
  @key_map = key_map.coercible(&coercer)
28
30
  end
29
-
31
+
30
32
  # @api private
31
33
  def call(source)
32
34
  key_map.write(Hash(source))
@@ -43,7 +43,7 @@ module Dry
43
43
  #
44
44
  # @api public
45
45
  def to_s
46
- [left, right].uniq.join(" #{messages[:or]} ")
46
+ [left, right].uniq.join(" #{messages[:or].()} ")
47
47
  end
48
48
  end
49
49
 
@@ -164,7 +164,7 @@ module Dry
164
164
 
165
165
  # @api private
166
166
  def message_text(rule, template, tokens, opts)
167
- text = template % tokens
167
+ text = template[template.data(tokens)]
168
168
 
169
169
  if full?
170
170
  rule_name = rule ? (messages.rule(rule, opts) || rule) : (opts[:name] || opts[:path].last)
@@ -4,6 +4,7 @@ require 'dry/equalizer'
4
4
  require 'dry/configurable'
5
5
 
6
6
  require 'dry/schema/constants'
7
+ require 'dry/schema/messages/template'
7
8
 
8
9
  module Dry
9
10
  module Schema
@@ -69,15 +70,15 @@ module Dry
69
70
  get(path, options) if key?(path, options)
70
71
  end
71
72
 
72
- # Retrieve a message
73
+ # Retrieve a message template
73
74
  #
74
- # @return [String]
75
+ # @return [Template]
75
76
  #
76
77
  # @api public
77
78
  def call(*args)
78
79
  cache.fetch_or_store(args.hash) do
79
80
  path, opts = lookup(*args)
80
- get(path, opts) if path
81
+ Template[get(path, opts)] if path
81
82
  end
82
83
  end
83
84
  alias_method :[], :call
@@ -96,7 +97,7 @@ module Dry
96
97
 
97
98
  tokens[:path] = options[:rule] || Array(options[:path]).join(DOT)
98
99
 
99
- opts = options.reject { |k, _| config.lookup_options.include?(k) }
100
+ opts = options.select { |k, _| !config.lookup_options.include?(k) }
100
101
 
101
102
  path = lookup_paths(tokens).detect do |key|
102
103
  key?(key, opts) && get(key, opts).is_a?(String)
@@ -0,0 +1,66 @@
1
+ require 'dry/equalizer'
2
+
3
+ require 'dry/schema/constants'
4
+
5
+ module Dry
6
+ module Schema
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\d]*)}/
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
@@ -0,0 +1,55 @@
1
+ require 'dry/schema/constants'
2
+
3
+ module Dry
4
+ module Schema
5
+ # Path represents a list of keys in a hash
6
+ #
7
+ # @api private
8
+ class Path
9
+ # !@attribute [r] keys
10
+ # @return [Array<Symbol>]
11
+ attr_reader :keys
12
+
13
+ # Coerce a spec into a path object
14
+ #
15
+ # @param [Symbol, String, Hash, Array<Symbol>] spec
16
+ #
17
+ # @return [Path]
18
+ #
19
+ # @api private
20
+ def self.[](spec)
21
+ case spec
22
+ when Symbol, Array
23
+ new(Array[*spec])
24
+ when String
25
+ new(spec.split(DOT).map(&:to_sym))
26
+ when Hash
27
+ new(keys_from_hash(spec))
28
+ when self
29
+ spec
30
+ else
31
+ raise ArgumentError, '+spec+ must be either a Symbol, Array or Hash'
32
+ end
33
+ end
34
+
35
+ # Extract a list of keys from a hash
36
+ #
37
+ # @api private
38
+ def self.keys_from_hash(hash)
39
+ hash.inject([]) { |a, (k, v)|
40
+ v.is_a?(Hash) ? a.concat([k, *keys_from_hash(v)]) : a.concat([k, v])
41
+ }
42
+ end
43
+
44
+ # @api private
45
+ def initialize(keys)
46
+ @keys = keys
47
+ end
48
+
49
+ # @api private
50
+ def ==(other)
51
+ keys == Path[other].keys
52
+ end
53
+ end
54
+ end
55
+ end
@@ -15,7 +15,7 @@ module Dry
15
15
  # 1. Prepare input hash using a key map
16
16
  # 2. Apply pre-coercion filtering rules (optional step, used only when `filter` was used)
17
17
  # 3. Apply value coercions based on type specifications
18
- # 4. Apply rules
18
+ # 4. Apply rules
19
19
  #
20
20
  # @see Params
21
21
  # @see JSON
@@ -51,7 +51,7 @@ module Dry
51
51
  #
52
52
  # @api private
53
53
  def self.definition
54
- @__definition__
54
+ @__definition__ ||= nil
55
55
  end
56
56
 
57
57
  # Build a new processor object
@@ -1,6 +1,8 @@
1
1
  require 'dry/initializer'
2
2
  require 'dry/equalizer'
3
3
 
4
+ require 'dry/schema/path'
5
+
4
6
  module Dry
5
7
  module Schema
6
8
  # Processing result
@@ -66,15 +68,15 @@ module Dry
66
68
  output.key?(name)
67
69
  end
68
70
 
69
- # Check if a given key resulted in an error
71
+ # Check if there's an error for the provided spec
70
72
  #
71
- # @param [Symbol] name
73
+ # @param [Symbol, Hash<Symbol=>Symbol>] name
72
74
  #
73
75
  # @return [Boolean]
74
76
  #
75
77
  # @api public
76
- def error?(name)
77
- errors.key?(name)
78
+ def error?(spec)
79
+ message_set.any? { |msg| Path[spec] == msg.path }
78
80
  end
79
81
 
80
82
  # Check if the result is successful
@@ -1,3 +1,4 @@
1
+ require 'dry/equalizer'
1
2
  require 'dry/initializer'
2
3
 
3
4
  module Dry
@@ -7,6 +8,7 @@ module Dry
7
8
  # @api private
8
9
  class ValueCoercer
9
10
  extend Dry::Initializer
11
+ include ::Dry::Equalizer(:type_schema)
10
12
 
11
13
  # @api private
12
14
  param :type_schema
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module Schema
3
- VERSION = '0.1.0'.freeze
3
+ VERSION = '0.1.1'.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.0
4
+ version: 0.1.1
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-01-30 00:00:00.000000000 Z
11
+ date: 2019-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -216,8 +216,10 @@ files:
216
216
  - lib/dry/schema/messages/abstract.rb
217
217
  - lib/dry/schema/messages/i18n.rb
218
218
  - lib/dry/schema/messages/namespaced.rb
219
+ - lib/dry/schema/messages/template.rb
219
220
  - lib/dry/schema/messages/yaml.rb
220
221
  - lib/dry/schema/params.rb
222
+ - lib/dry/schema/path.rb
221
223
  - lib/dry/schema/predicate.rb
222
224
  - lib/dry/schema/predicate_inferrer.rb
223
225
  - lib/dry/schema/predicate_registry.rb
@@ -248,7 +250,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
248
250
  - !ruby/object:Gem::Version
249
251
  version: '0'
250
252
  requirements: []
251
- rubygems_version: 3.0.2
253
+ rubygems_version: 3.0.1
252
254
  signing_key:
253
255
  specification_version: 4
254
256
  summary: Schema coercion and validation