dry-types 0.15.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +10 -0
- data/.github/ISSUE_TEMPLATE/---bug-report.md +34 -0
- data/.github/ISSUE_TEMPLATE/---feature-request.md +18 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +18 -2
- data/.travis.yml +10 -5
- data/.yardopts +6 -2
- data/CHANGELOG.md +186 -3
- data/Gemfile +11 -5
- data/README.md +4 -3
- data/Rakefile +4 -2
- data/benchmarks/hash_schemas.rb +10 -6
- data/benchmarks/lax_schema.rb +15 -0
- data/benchmarks/profile_invalid_input.rb +15 -0
- data/benchmarks/profile_lax_schema_valid.rb +16 -0
- data/benchmarks/profile_valid_input.rb +15 -0
- data/benchmarks/schema_valid_vs_invalid.rb +21 -0
- data/benchmarks/setup.rb +17 -0
- data/docsite/source/array-with-member.html.md +13 -0
- data/docsite/source/built-in-types.html.md +116 -0
- data/docsite/source/constraints.html.md +31 -0
- data/docsite/source/custom-types.html.md +93 -0
- data/docsite/source/default-values.html.md +91 -0
- data/docsite/source/enum.html.md +69 -0
- data/docsite/source/getting-started.html.md +57 -0
- data/docsite/source/hash-schemas.html.md +169 -0
- data/docsite/source/index.html.md +155 -0
- data/docsite/source/map.html.md +17 -0
- data/docsite/source/optional-values.html.md +96 -0
- data/docsite/source/sum.html.md +21 -0
- data/dry-types.gemspec +21 -19
- data/lib/dry-types.rb +2 -0
- data/lib/dry/types.rb +60 -17
- data/lib/dry/types/any.rb +21 -10
- data/lib/dry/types/array.rb +17 -1
- data/lib/dry/types/array/constructor.rb +32 -0
- data/lib/dry/types/array/member.rb +72 -13
- data/lib/dry/types/builder.rb +49 -5
- data/lib/dry/types/builder_methods.rb +43 -16
- data/lib/dry/types/coercions.rb +84 -19
- data/lib/dry/types/coercions/json.rb +22 -3
- data/lib/dry/types/coercions/params.rb +98 -30
- data/lib/dry/types/compiler.rb +35 -12
- data/lib/dry/types/constrained.rb +78 -27
- data/lib/dry/types/constrained/coercible.rb +36 -6
- data/lib/dry/types/constraints.rb +15 -1
- data/lib/dry/types/constructor.rb +77 -62
- data/lib/dry/types/constructor/function.rb +200 -0
- data/lib/dry/types/container.rb +5 -0
- data/lib/dry/types/core.rb +35 -14
- data/lib/dry/types/decorator.rb +37 -10
- data/lib/dry/types/default.rb +48 -16
- data/lib/dry/types/enum.rb +31 -16
- data/lib/dry/types/errors.rb +73 -7
- data/lib/dry/types/extensions.rb +6 -0
- data/lib/dry/types/extensions/maybe.rb +52 -5
- data/lib/dry/types/extensions/monads.rb +29 -0
- data/lib/dry/types/fn_container.rb +5 -0
- data/lib/dry/types/hash.rb +32 -14
- data/lib/dry/types/hash/constructor.rb +16 -3
- data/lib/dry/types/inflector.rb +2 -0
- data/lib/dry/types/json.rb +7 -5
- data/lib/dry/types/{safe.rb → lax.rb} +33 -16
- data/lib/dry/types/map.rb +70 -32
- data/lib/dry/types/meta.rb +51 -0
- data/lib/dry/types/module.rb +10 -5
- data/lib/dry/types/nominal.rb +105 -14
- data/lib/dry/types/options.rb +12 -25
- data/lib/dry/types/params.rb +14 -3
- data/lib/dry/types/predicate_inferrer.rb +197 -0
- data/lib/dry/types/predicate_registry.rb +34 -0
- data/lib/dry/types/primitive_inferrer.rb +97 -0
- data/lib/dry/types/printable.rb +5 -1
- data/lib/dry/types/printer.rb +70 -64
- data/lib/dry/types/result.rb +26 -0
- data/lib/dry/types/schema.rb +177 -80
- data/lib/dry/types/schema/key.rb +48 -35
- data/lib/dry/types/spec/types.rb +43 -6
- data/lib/dry/types/sum.rb +70 -21
- data/lib/dry/types/type.rb +49 -0
- data/lib/dry/types/version.rb +3 -1
- metadata +91 -62
data/lib/dry/types/container.rb
CHANGED
data/lib/dry/types/core.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'dry/types/any'
|
2
4
|
|
3
5
|
module Dry
|
4
6
|
module Types
|
5
7
|
# Primitives with {Kernel} coercion methods
|
6
|
-
|
8
|
+
KERNEL_COERCIBLE = {
|
7
9
|
string: String,
|
8
10
|
integer: Integer,
|
9
11
|
float: Float,
|
@@ -12,10 +14,19 @@ module Dry
|
|
12
14
|
hash: ::Hash
|
13
15
|
}.freeze
|
14
16
|
|
15
|
-
# Primitives
|
17
|
+
# Primitives with coercions through by convention `to_*` methods
|
18
|
+
METHOD_COERCIBLE = {
|
19
|
+
symbol: Symbol
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
# By convention methods to coerce {METHOD_COERCIBLE} primitives
|
23
|
+
METHOD_COERCIBLE_METHODS = {
|
24
|
+
symbol: :to_sym
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
# Primitives that are non-coercible
|
16
28
|
NON_COERCIBLE = {
|
17
29
|
nil: NilClass,
|
18
|
-
symbol: Symbol,
|
19
30
|
class: Class,
|
20
31
|
true: TrueClass,
|
21
32
|
false: FalseClass,
|
@@ -26,7 +37,10 @@ module Dry
|
|
26
37
|
}.freeze
|
27
38
|
|
28
39
|
# All built-in primitives
|
29
|
-
ALL_PRIMITIVES =
|
40
|
+
ALL_PRIMITIVES = [KERNEL_COERCIBLE, METHOD_COERCIBLE, NON_COERCIBLE].reduce(&:merge).freeze
|
41
|
+
|
42
|
+
# All coercible types
|
43
|
+
COERCIBLE = KERNEL_COERCIBLE.merge(METHOD_COERCIBLE).freeze
|
30
44
|
|
31
45
|
# All built-in primitives except {NilClass}
|
32
46
|
NON_NIL = ALL_PRIMITIVES.reject { |name, _| name == :nil }.freeze
|
@@ -44,11 +58,18 @@ module Dry
|
|
44
58
|
register("strict.#{name}", type)
|
45
59
|
end
|
46
60
|
|
47
|
-
# Register {
|
48
|
-
|
61
|
+
# Register {KERNEL_COERCIBLE} types
|
62
|
+
KERNEL_COERCIBLE.each do |name, primitive|
|
49
63
|
register("coercible.#{name}", self["nominal.#{name}"].constructor(Kernel.method(primitive.name)))
|
50
64
|
end
|
51
65
|
|
66
|
+
# Register {METHOD_COERCIBLE} types
|
67
|
+
METHOD_COERCIBLE.each_key do |name|
|
68
|
+
register(
|
69
|
+
"coercible.#{name}", self["nominal.#{name}"].constructor(&METHOD_COERCIBLE_METHODS[name])
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
52
73
|
# Register optional strict {NON_NIL} types
|
53
74
|
NON_NIL.each_key do |name|
|
54
75
|
register("optional.strict.#{name}", self["strict.#{name}"].optional)
|
@@ -60,14 +81,14 @@ module Dry
|
|
60
81
|
end
|
61
82
|
|
62
83
|
# Register `:bool` since it's common and not a built-in Ruby type :(
|
63
|
-
register(
|
64
|
-
bool = self[
|
65
|
-
register(
|
66
|
-
register(
|
67
|
-
|
68
|
-
register(
|
69
|
-
register(
|
70
|
-
register(
|
84
|
+
register('nominal.bool', self['nominal.true'] | self['nominal.false'])
|
85
|
+
bool = self['strict.true'] | self['strict.false']
|
86
|
+
register('strict.bool', bool)
|
87
|
+
register('bool', bool)
|
88
|
+
|
89
|
+
register('any', Any)
|
90
|
+
register('nominal.any', Any)
|
91
|
+
register('strict.any', Any)
|
71
92
|
end
|
72
93
|
end
|
73
94
|
|
data/lib/dry/types/decorator.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'dry/types/options'
|
2
4
|
|
3
5
|
module Dry
|
4
6
|
module Types
|
7
|
+
# Common API for types
|
8
|
+
#
|
9
|
+
# @api public
|
5
10
|
module Decorator
|
6
11
|
include Options
|
7
12
|
|
@@ -16,56 +21,76 @@ module Dry
|
|
16
21
|
|
17
22
|
# @param [Object] input
|
18
23
|
# @param [#call, nil] block
|
24
|
+
#
|
19
25
|
# @return [Result,Logic::Result]
|
20
26
|
# @return [Object] if block given and try fails
|
27
|
+
#
|
28
|
+
# @api public
|
21
29
|
def try(input, &block)
|
22
30
|
type.try(input, &block)
|
23
31
|
end
|
24
32
|
|
25
|
-
# @param [Object] value
|
26
|
-
# @return [Boolean]
|
27
|
-
def valid?(value)
|
28
|
-
type.valid?(value)
|
29
|
-
end
|
30
|
-
alias_method :===, :valid?
|
31
|
-
|
32
33
|
# @return [Boolean]
|
34
|
+
#
|
35
|
+
# @api public
|
33
36
|
def default?
|
34
37
|
type.default?
|
35
38
|
end
|
36
39
|
|
37
40
|
# @return [Boolean]
|
41
|
+
#
|
42
|
+
# @api public
|
38
43
|
def constrained?
|
39
44
|
type.constrained?
|
40
45
|
end
|
41
46
|
|
42
47
|
# @return [Sum]
|
48
|
+
#
|
49
|
+
# @api public
|
43
50
|
def optional
|
44
51
|
Types['strict.nil'] | self
|
45
52
|
end
|
46
53
|
|
47
54
|
# @param [Symbol] meth
|
48
55
|
# @param [Boolean] include_private
|
56
|
+
#
|
49
57
|
# @return [Boolean]
|
58
|
+
#
|
59
|
+
# @api public
|
50
60
|
def respond_to_missing?(meth, include_private = false)
|
51
61
|
super || type.respond_to?(meth)
|
52
62
|
end
|
53
63
|
|
64
|
+
# Wrap the type with a proc
|
65
|
+
#
|
66
|
+
# @return [Proc]
|
67
|
+
#
|
68
|
+
# @api public
|
69
|
+
def to_proc
|
70
|
+
proc { |value| self.(value) }
|
71
|
+
end
|
72
|
+
|
54
73
|
private
|
55
74
|
|
56
75
|
# @param [Object] response
|
76
|
+
#
|
57
77
|
# @return [Boolean]
|
78
|
+
#
|
79
|
+
# @api private
|
58
80
|
def decorate?(response)
|
59
|
-
response.
|
81
|
+
response.is_a?(type.class)
|
60
82
|
end
|
61
83
|
|
62
84
|
# Delegates missing methods to {#type}
|
85
|
+
#
|
63
86
|
# @param [Symbol] meth
|
64
87
|
# @param [Array] args
|
65
88
|
# @param [#call, nil] block
|
89
|
+
#
|
90
|
+
# @api private
|
66
91
|
def method_missing(meth, *args, &block)
|
67
92
|
if type.respond_to?(meth)
|
68
|
-
response = type.
|
93
|
+
response = type.public_send(meth, *args, &block)
|
69
94
|
|
70
95
|
if decorate?(response)
|
71
96
|
__new__(response)
|
@@ -78,8 +103,10 @@ module Dry
|
|
78
103
|
end
|
79
104
|
|
80
105
|
# Replace underlying type
|
106
|
+
#
|
107
|
+
# @api private
|
81
108
|
def __new__(type)
|
82
|
-
self.class.new(type, options)
|
109
|
+
self.class.new(type, *@__args__[1..-1], **@options)
|
83
110
|
end
|
84
111
|
end
|
85
112
|
end
|
data/lib/dry/types/default.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'dry/types/decorator'
|
2
4
|
|
3
5
|
module Dry
|
4
6
|
module Types
|
7
|
+
# Default types are useful when a missing value should be replaced by a default one
|
8
|
+
#
|
9
|
+
# @api public
|
5
10
|
class Default
|
6
|
-
|
7
|
-
include Decorator
|
8
|
-
include Builder
|
9
|
-
include Printable
|
10
|
-
include Dry::Equalizer(:type, :options, :value, inspect: false)
|
11
|
-
|
11
|
+
# @api private
|
12
12
|
class Callable < Default
|
13
|
-
include Dry::Equalizer(:type,
|
13
|
+
include Dry::Equalizer(:type, inspect: false)
|
14
14
|
|
15
15
|
# Evaluates given callable
|
16
16
|
# @return [Object]
|
@@ -19,13 +19,22 @@ module Dry
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
include Type
|
23
|
+
include Decorator
|
24
|
+
include Builder
|
25
|
+
include Printable
|
26
|
+
include Dry::Equalizer(:type, :value, inspect: false)
|
27
|
+
|
22
28
|
# @return [Object]
|
23
29
|
attr_reader :value
|
24
30
|
|
25
31
|
alias_method :evaluate, :value
|
26
32
|
|
27
33
|
# @param [Object, #call] value
|
34
|
+
#
|
28
35
|
# @return [Class] {Default} or {Default::Callable}
|
36
|
+
#
|
37
|
+
# @api private
|
29
38
|
def self.[](value)
|
30
39
|
if value.respond_to?(:call)
|
31
40
|
Callable
|
@@ -36,48 +45,71 @@ module Dry
|
|
36
45
|
|
37
46
|
# @param [Type] type
|
38
47
|
# @param [Object] value
|
48
|
+
#
|
49
|
+
# @api private
|
39
50
|
def initialize(type, value, **options)
|
40
51
|
super
|
41
52
|
@value = value
|
42
53
|
end
|
43
54
|
|
55
|
+
# Build a constrained type
|
56
|
+
#
|
44
57
|
# @param [Array] args see {Dry::Types::Builder#constrained}
|
58
|
+
#
|
45
59
|
# @return [Default]
|
60
|
+
#
|
61
|
+
# @api public
|
46
62
|
def constrained(*args)
|
47
63
|
type.constrained(*args).default(value)
|
48
64
|
end
|
49
65
|
|
50
66
|
# @return [true]
|
67
|
+
#
|
68
|
+
# @api public
|
51
69
|
def default?
|
52
70
|
true
|
53
71
|
end
|
54
72
|
|
55
73
|
# @param [Object] input
|
74
|
+
#
|
56
75
|
# @return [Result::Success]
|
76
|
+
#
|
77
|
+
# @api public
|
57
78
|
def try(input)
|
58
79
|
success(call(input))
|
59
80
|
end
|
60
81
|
|
82
|
+
# @return [Boolean]
|
83
|
+
#
|
84
|
+
# @api public
|
61
85
|
def valid?(value = Undefined)
|
62
|
-
|
86
|
+
Undefined.equal?(value) || super
|
63
87
|
end
|
64
88
|
|
65
89
|
# @param [Object] input
|
90
|
+
#
|
66
91
|
# @return [Object] value passed through {#type} or {#default} value
|
67
|
-
|
92
|
+
#
|
93
|
+
# @api private
|
94
|
+
def call_unsafe(input = Undefined)
|
68
95
|
if input.equal?(Undefined)
|
69
96
|
evaluate
|
70
97
|
else
|
71
|
-
Undefined.default(type
|
98
|
+
Undefined.default(type.call_unsafe(input)) { evaluate }
|
72
99
|
end
|
73
100
|
end
|
74
|
-
alias_method :[], :call
|
75
|
-
|
76
|
-
private
|
77
101
|
|
78
|
-
#
|
79
|
-
|
80
|
-
|
102
|
+
# @param [Object] input
|
103
|
+
#
|
104
|
+
# @return [Object] value passed through {#type} or {#default} value
|
105
|
+
#
|
106
|
+
# @api private
|
107
|
+
def call_safe(input = Undefined, &block)
|
108
|
+
if input.equal?(Undefined)
|
109
|
+
evaluate
|
110
|
+
else
|
111
|
+
Undefined.default(type.call_safe(input, &block)) { evaluate }
|
112
|
+
end
|
81
113
|
end
|
82
114
|
end
|
83
115
|
end
|
data/lib/dry/types/enum.rb
CHANGED
@@ -1,11 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'dry/types/decorator'
|
2
4
|
|
3
5
|
module Dry
|
4
6
|
module Types
|
7
|
+
# Enum types can be used to define an enum on top of an existing type
|
8
|
+
#
|
9
|
+
# @api public
|
5
10
|
class Enum
|
6
11
|
include Type
|
7
|
-
include Dry::Equalizer(:type, :
|
12
|
+
include Dry::Equalizer(:type, :mapping, inspect: false)
|
8
13
|
include Decorator
|
14
|
+
include Builder
|
9
15
|
|
10
16
|
# @return [Array]
|
11
17
|
attr_reader :values
|
@@ -19,6 +25,8 @@ module Dry
|
|
19
25
|
# @param [Type] type
|
20
26
|
# @param [Hash] options
|
21
27
|
# @option options [Array] :values
|
28
|
+
#
|
29
|
+
# @api private
|
22
30
|
def initialize(type, options)
|
23
31
|
super
|
24
32
|
@mapping = options.fetch(:mapping).freeze
|
@@ -27,22 +35,28 @@ module Dry
|
|
27
35
|
freeze
|
28
36
|
end
|
29
37
|
|
30
|
-
# @param [Object] input
|
31
38
|
# @return [Object]
|
32
|
-
|
33
|
-
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
def call_unsafe(input)
|
42
|
+
type.call_unsafe(map_value(input))
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [Object]
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
def call_safe(input, &block)
|
49
|
+
type.call_safe(map_value(input), &block)
|
34
50
|
end
|
35
|
-
alias_method :[], :call
|
36
51
|
|
37
|
-
# @
|
38
|
-
#
|
39
|
-
# @
|
40
|
-
# @return [Logic::Result]
|
41
|
-
# @return [Object] if coercion fails and a block is given
|
52
|
+
# @see Dry::Types::Constrained#try
|
53
|
+
#
|
54
|
+
# @api public
|
42
55
|
def try(input)
|
43
56
|
super(map_value(input))
|
44
57
|
end
|
45
58
|
|
59
|
+
# @api private
|
46
60
|
def default(*)
|
47
61
|
raise '.enum(*values).default(value) is not supported. Call '\
|
48
62
|
'.default(value).enum(*values) instead'
|
@@ -51,16 +65,15 @@ module Dry
|
|
51
65
|
# Check whether a value is in the enum
|
52
66
|
alias_method :include?, :valid?
|
53
67
|
|
54
|
-
# @api public
|
55
|
-
#
|
56
68
|
# @see Nominal#to_ast
|
69
|
+
#
|
70
|
+
# @api public
|
57
71
|
def to_ast(meta: true)
|
58
|
-
[:enum, [type.to_ast(meta: meta),
|
59
|
-
mapping,
|
60
|
-
meta ? self.meta : EMPTY_HASH]]
|
72
|
+
[:enum, [type.to_ast(meta: meta), mapping]]
|
61
73
|
end
|
62
74
|
|
63
75
|
# @return [String]
|
76
|
+
#
|
64
77
|
# @api public
|
65
78
|
def to_s
|
66
79
|
PRINTER.(self)
|
@@ -71,8 +84,10 @@ module Dry
|
|
71
84
|
|
72
85
|
# Maps a value
|
73
86
|
#
|
74
|
-
# @param [Object]
|
87
|
+
# @param [Object] input
|
88
|
+
#
|
75
89
|
# @return [Object]
|
90
|
+
#
|
76
91
|
# @api private
|
77
92
|
def map_value(input)
|
78
93
|
if input.equal?(Undefined)
|
data/lib/dry/types/errors.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dry
|
2
4
|
module Types
|
3
5
|
extend Dry::Core::ClassAttributes
|
@@ -8,7 +10,62 @@ module Dry
|
|
8
10
|
|
9
11
|
namespace self
|
10
12
|
|
11
|
-
class
|
13
|
+
# Base class for coercion errors raise by dry-types
|
14
|
+
#
|
15
|
+
class CoercionError < StandardError
|
16
|
+
# @api private
|
17
|
+
def self.handle(exception, meta: Undefined)
|
18
|
+
if block_given?
|
19
|
+
yield
|
20
|
+
else
|
21
|
+
raise new(
|
22
|
+
exception.message,
|
23
|
+
meta: meta,
|
24
|
+
backtrace: exception.backtrace
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Metadata associated with the error
|
30
|
+
#
|
31
|
+
# @return [Object]
|
32
|
+
attr_reader :meta
|
33
|
+
|
34
|
+
# @api private
|
35
|
+
def initialize(message, meta: Undefined, backtrace: Undefined)
|
36
|
+
unless message.is_a?(::String)
|
37
|
+
raise ArgumentError, "message must be a string, #{message.class} given"
|
38
|
+
end
|
39
|
+
|
40
|
+
super(message)
|
41
|
+
@meta = Undefined.default(meta, nil)
|
42
|
+
set_backtrace(backtrace) unless Undefined.equal?(backtrace)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Collection of multiple errors
|
47
|
+
#
|
48
|
+
class MultipleError < CoercionError
|
49
|
+
# @return [Array<CoercionError>]
|
50
|
+
attr_reader :errors
|
51
|
+
|
52
|
+
# @param [Array<CoercionError>] errors
|
53
|
+
def initialize(errors)
|
54
|
+
@errors = errors
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return string
|
58
|
+
def message
|
59
|
+
errors.map(&:message).join(', ')
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [Array]
|
63
|
+
def meta
|
64
|
+
errors.map(&:meta)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class SchemaError < CoercionError
|
12
69
|
# @param [String,Symbol] key
|
13
70
|
# @param [Object] value
|
14
71
|
# @param [String, #to_s] result
|
@@ -17,26 +74,34 @@ module Dry
|
|
17
74
|
end
|
18
75
|
end
|
19
76
|
|
20
|
-
MapError = Class.new(
|
77
|
+
MapError = Class.new(CoercionError)
|
21
78
|
|
22
|
-
SchemaKeyError = Class.new(
|
79
|
+
SchemaKeyError = Class.new(CoercionError)
|
23
80
|
private_constant(:SchemaKeyError)
|
24
81
|
|
25
82
|
class MissingKeyError < SchemaKeyError
|
83
|
+
# @return [Symbol]
|
84
|
+
attr_reader :key
|
85
|
+
|
26
86
|
# @param [String,Symbol] key
|
27
87
|
def initialize(key)
|
28
|
-
|
88
|
+
@key = key
|
89
|
+
super("#{key.inspect} is missing in Hash input")
|
29
90
|
end
|
30
91
|
end
|
31
92
|
|
32
93
|
class UnknownKeysError < SchemaKeyError
|
94
|
+
# @return [Array<Symbol>]
|
95
|
+
attr_reader :keys
|
96
|
+
|
33
97
|
# @param [<String, Symbol>] keys
|
34
|
-
def initialize(
|
98
|
+
def initialize(keys)
|
99
|
+
@keys = keys
|
35
100
|
super("unexpected keys #{keys.inspect} in Hash input")
|
36
101
|
end
|
37
102
|
end
|
38
103
|
|
39
|
-
class ConstraintError <
|
104
|
+
class ConstraintError < CoercionError
|
40
105
|
# @return [String, #to_s]
|
41
106
|
attr_reader :result
|
42
107
|
# @return [Object]
|
@@ -56,9 +121,10 @@ module Dry
|
|
56
121
|
end
|
57
122
|
|
58
123
|
# @return [String]
|
59
|
-
def
|
124
|
+
def message
|
60
125
|
"#{input.inspect} violates constraints (#{result} failed)"
|
61
126
|
end
|
127
|
+
alias_method :to_s, :message
|
62
128
|
end
|
63
129
|
end
|
64
130
|
end
|