dry-schema 0.1.0 → 0.1.1

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: 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