dry-types 0.9.2 → 0.9.3
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 +4 -4
- data/.travis.yml +10 -6
- data/.yardopts +5 -0
- data/CHANGELOG.md +9 -1
- data/Gemfile +4 -1
- data/Rakefile +4 -0
- data/dry-types.gemspec +2 -1
- data/lib/dry/types.rb +25 -0
- data/lib/dry/types/array.rb +2 -0
- data/lib/dry/types/array/member.rb +16 -2
- data/lib/dry/types/builder.rb +17 -2
- data/lib/dry/types/coercions.rb +14 -2
- data/lib/dry/types/coercions/form.rb +18 -0
- data/lib/dry/types/coercions/json.rb +2 -0
- data/lib/dry/types/constrained.rb +21 -0
- data/lib/dry/types/constrained/coercible.rb +5 -0
- data/lib/dry/types/constraints.rb +3 -0
- data/lib/dry/types/constructor.rb +28 -0
- data/lib/dry/types/decorator.rb +19 -0
- data/lib/dry/types/default.rb +14 -0
- data/lib/dry/types/definition.rb +31 -4
- data/lib/dry/types/enum.rb +10 -1
- data/lib/dry/types/errors.rb +14 -2
- data/lib/dry/types/extensions/maybe.rb +19 -2
- data/lib/dry/types/hash.rb +18 -0
- data/lib/dry/types/hash/schema.rb +69 -0
- data/lib/dry/types/options.rb +6 -0
- data/lib/dry/types/result.rb +10 -0
- data/lib/dry/types/safe.rb +9 -0
- data/lib/dry/types/sum.rb +20 -0
- data/lib/dry/types/version.rb +1 -1
- metadata +23 -2
@@ -2,6 +2,11 @@ module Dry
|
|
2
2
|
module Types
|
3
3
|
class Constrained
|
4
4
|
class Coercible < Constrained
|
5
|
+
# @param [Object] input
|
6
|
+
# @param [#call] block
|
7
|
+
# @yieldparam [Failure] failure
|
8
|
+
# @yieldreturn [Result]
|
9
|
+
# @return [Result]
|
5
10
|
def try(input, &block)
|
6
11
|
result = type.try(input)
|
7
12
|
|
@@ -4,12 +4,15 @@ require 'dry/logic/rule/predicate'
|
|
4
4
|
|
5
5
|
module Dry
|
6
6
|
module Types
|
7
|
+
# @param [Hash] options
|
8
|
+
# @return [Dry::Logic::Rule]
|
7
9
|
def self.Rule(options)
|
8
10
|
rule_compiler.(
|
9
11
|
options.map { |key, val| Logic::Rule::Predicate.new(Logic::Predicates[:"#{key}?"]).curry(val).to_ast }
|
10
12
|
).reduce(:and)
|
11
13
|
end
|
12
14
|
|
15
|
+
# @return [Dry::Logic::RuleCompiler]
|
13
16
|
def self.rule_compiler
|
14
17
|
@rule_compiler ||= Logic::RuleCompiler.new(Logic::Predicates)
|
15
18
|
end
|
@@ -5,36 +5,54 @@ module Dry
|
|
5
5
|
class Constructor < Definition
|
6
6
|
include Dry::Equalizer(:type)
|
7
7
|
|
8
|
+
# @return [#call]
|
8
9
|
attr_reader :fn
|
9
10
|
|
11
|
+
# @return [Definition]
|
10
12
|
attr_reader :type
|
11
13
|
|
14
|
+
# @param [Builder, Object] input
|
15
|
+
# @param [Hash] options
|
16
|
+
# @param [#call] block
|
12
17
|
def self.new(input, options = {}, &block)
|
13
18
|
type = input.is_a?(Builder) ? input : Definition.new(input)
|
14
19
|
super(type, options, &block)
|
15
20
|
end
|
16
21
|
|
22
|
+
# @param [Definition] type
|
23
|
+
# @param [Hash] options
|
24
|
+
# @param [#proc] block
|
17
25
|
def initialize(type, options = {}, &block)
|
18
26
|
@type = type
|
19
27
|
@fn = options.fetch(:fn, block)
|
20
28
|
super
|
21
29
|
end
|
22
30
|
|
31
|
+
# @return [Class]
|
23
32
|
def primitive
|
24
33
|
type.primitive
|
25
34
|
end
|
26
35
|
|
36
|
+
# @param [Object] input
|
37
|
+
# @return [Object]
|
27
38
|
def call(input)
|
28
39
|
type[fn[input]]
|
29
40
|
end
|
30
41
|
alias_method :[], :call
|
31
42
|
|
43
|
+
# @param [Object] input
|
44
|
+
# @param [#call] block
|
45
|
+
# @return [Result]
|
32
46
|
def try(input, &block)
|
33
47
|
type.try(fn[input], &block)
|
34
48
|
rescue TypeError => e
|
35
49
|
failure(input, e.message)
|
36
50
|
end
|
37
51
|
|
52
|
+
# @param [#call, nil] new_fn
|
53
|
+
# @param [Hash] options
|
54
|
+
# @param [#call] block
|
55
|
+
# @return [Constructor]
|
38
56
|
def constructor(new_fn = nil, **options, &block)
|
39
57
|
left = new_fn || block
|
40
58
|
right = fn
|
@@ -42,20 +60,30 @@ module Dry
|
|
42
60
|
with(options.merge(fn: -> input { left[right[input]] }))
|
43
61
|
end
|
44
62
|
|
63
|
+
# @param [Object] value
|
64
|
+
# @return [Boolean]
|
45
65
|
def valid?(value)
|
46
66
|
super && type.valid?(value)
|
47
67
|
end
|
48
68
|
|
69
|
+
# @return [Class]
|
49
70
|
def constrained_type
|
50
71
|
Constrained::Coercible
|
51
72
|
end
|
52
73
|
|
53
74
|
private
|
54
75
|
|
76
|
+
# @param [Symbol] meth
|
77
|
+
# @param [Boolean] include_private
|
78
|
+
# @return [Boolean]
|
55
79
|
def respond_to_missing?(meth, include_private = false)
|
56
80
|
super || type.respond_to?(meth)
|
57
81
|
end
|
58
82
|
|
83
|
+
# Delegates missing methods to {#type}
|
84
|
+
# @param [Symbol] meth
|
85
|
+
# @param [Array] args
|
86
|
+
# @param [#call] block
|
59
87
|
def method_missing(meth, *args, &block)
|
60
88
|
if type.respond_to?(meth)
|
61
89
|
response = type.__send__(meth, *args, &block)
|
data/lib/dry/types/decorator.rb
CHANGED
@@ -5,43 +5,62 @@ module Dry
|
|
5
5
|
module Decorator
|
6
6
|
include Options
|
7
7
|
|
8
|
+
# @return [Definition]
|
8
9
|
attr_reader :type
|
9
10
|
|
11
|
+
# @param [Definition] type
|
10
12
|
def initialize(type, *)
|
11
13
|
super
|
12
14
|
@type = type
|
13
15
|
end
|
14
16
|
|
17
|
+
# @return [Constructor]
|
15
18
|
def constructor
|
16
19
|
type.constructor
|
17
20
|
end
|
18
21
|
|
22
|
+
# @param [Object] input
|
23
|
+
# @param [#call] block
|
24
|
+
# @return [Result]
|
19
25
|
def try(input, &block)
|
20
26
|
type.try(input, &block)
|
21
27
|
end
|
22
28
|
|
29
|
+
# @param [Object] value
|
30
|
+
# @return [Boolean]
|
23
31
|
def valid?(value)
|
24
32
|
type.valid?(value)
|
25
33
|
end
|
26
34
|
|
35
|
+
# @return [Boolean]
|
27
36
|
def default?
|
28
37
|
type.default?
|
29
38
|
end
|
30
39
|
|
40
|
+
# @return [Boolean]
|
31
41
|
def constrained?
|
32
42
|
type.constrained?
|
33
43
|
end
|
34
44
|
|
45
|
+
# @param [Symbol] meth
|
46
|
+
# @param [Boolean] include_private
|
47
|
+
# @return [Boolean]
|
35
48
|
def respond_to_missing?(meth, include_private = false)
|
36
49
|
super || type.respond_to?(meth)
|
37
50
|
end
|
38
51
|
|
39
52
|
private
|
40
53
|
|
54
|
+
# @param [Object] response
|
55
|
+
# @return [Boolean]
|
41
56
|
def decorate?(response)
|
42
57
|
response.kind_of?(type.class)
|
43
58
|
end
|
44
59
|
|
60
|
+
# Delegates missing methods to {#type}
|
61
|
+
# @param [Symbol] meth
|
62
|
+
# @param [Array] args
|
63
|
+
# @param [#call] block
|
45
64
|
def method_missing(meth, *args, &block)
|
46
65
|
if type.respond_to?(meth)
|
47
66
|
response = type.__send__(meth, *args, &block)
|
data/lib/dry/types/default.rb
CHANGED
@@ -10,15 +10,20 @@ module Dry
|
|
10
10
|
class Callable < Default
|
11
11
|
include Dry::Equalizer(:type, :options)
|
12
12
|
|
13
|
+
# Evaluates given callable
|
14
|
+
# @return [Object]
|
13
15
|
def evaluate
|
14
16
|
value.call
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
20
|
+
# @return [Object]
|
18
21
|
attr_reader :value
|
19
22
|
|
20
23
|
alias_method :evaluate, :value
|
21
24
|
|
25
|
+
# @param [Object, #call] value
|
26
|
+
# @return [Default, Dry::Types::Default::Callable]
|
22
27
|
def self.[](value)
|
23
28
|
if value.respond_to?(:call)
|
24
29
|
Callable
|
@@ -27,23 +32,32 @@ module Dry
|
|
27
32
|
end
|
28
33
|
end
|
29
34
|
|
35
|
+
# @param [Definition] type
|
36
|
+
# @param [Object] value
|
30
37
|
def initialize(type, value, *)
|
31
38
|
super
|
32
39
|
@value = value
|
33
40
|
end
|
34
41
|
|
42
|
+
# @param [Array] args see {Dry::Types::Builder#constrained}
|
43
|
+
# @return [Default]
|
35
44
|
def constrained(*args)
|
36
45
|
type.constrained(*args).default(value)
|
37
46
|
end
|
38
47
|
|
48
|
+
# @return [true]
|
39
49
|
def default?
|
40
50
|
true
|
41
51
|
end
|
42
52
|
|
53
|
+
# @param [Object] input
|
54
|
+
# @return [Success]
|
43
55
|
def try(input)
|
44
56
|
success(call(input))
|
45
57
|
end
|
46
58
|
|
59
|
+
# @param [Object] input
|
60
|
+
# @return [Object] value passed through {#type} or {#default} value
|
47
61
|
def call(input)
|
48
62
|
if input.nil?
|
49
63
|
evaluate
|
data/lib/dry/types/definition.rb
CHANGED
@@ -9,10 +9,14 @@ module Dry
|
|
9
9
|
include Options
|
10
10
|
include Builder
|
11
11
|
|
12
|
+
# @return [Hash]
|
12
13
|
attr_reader :options
|
13
14
|
|
15
|
+
# @return [Class]
|
14
16
|
attr_reader :primitive
|
15
17
|
|
18
|
+
# @param [Class] primitive
|
19
|
+
# @return [Definition]
|
16
20
|
def self.[](primitive)
|
17
21
|
if primitive == ::Array
|
18
22
|
Types::Array
|
@@ -23,29 +27,41 @@ module Dry
|
|
23
27
|
end
|
24
28
|
end
|
25
29
|
|
30
|
+
# @param [Class] primitive
|
31
|
+
# @param [Hash] options
|
26
32
|
def initialize(primitive, options = {})
|
27
33
|
super
|
28
34
|
@primitive = primitive
|
29
35
|
freeze
|
30
36
|
end
|
31
37
|
|
38
|
+
# @return [String]
|
32
39
|
def name
|
33
40
|
primitive.name
|
34
41
|
end
|
35
42
|
|
43
|
+
# @return [false]
|
36
44
|
def default?
|
37
45
|
false
|
38
46
|
end
|
39
47
|
|
48
|
+
# @return [false]
|
40
49
|
def constrained?
|
41
50
|
false
|
42
51
|
end
|
43
52
|
|
53
|
+
# @param [Object] input
|
54
|
+
# @return [Object]
|
44
55
|
def call(input)
|
45
56
|
input
|
46
57
|
end
|
47
58
|
alias_method :[], :call
|
48
59
|
|
60
|
+
# @param [Object] input
|
61
|
+
# @param [#call] block
|
62
|
+
# @yieldparam [Failure] failure
|
63
|
+
# @yieldreturn [Result]
|
64
|
+
# @return [Result]
|
49
65
|
def try(input, &block)
|
50
66
|
if valid?(input)
|
51
67
|
success(input)
|
@@ -55,18 +71,29 @@ module Dry
|
|
55
71
|
end
|
56
72
|
end
|
57
73
|
|
58
|
-
|
59
|
-
|
74
|
+
# @param (see Dry::Types::Success#initialize)
|
75
|
+
# @return [Success]
|
76
|
+
def success(input)
|
77
|
+
Result::Success.new(input)
|
60
78
|
end
|
61
79
|
|
62
|
-
|
63
|
-
|
80
|
+
|
81
|
+
# @param (see Failure#initialize)
|
82
|
+
# @return [Failure]
|
83
|
+
def failure(input, error)
|
84
|
+
Result::Failure.new(input, error)
|
64
85
|
end
|
65
86
|
|
87
|
+
# @param [Object] klass class of the result instance
|
88
|
+
# @param [Array] args arguments for the +klass#initialize+ method
|
89
|
+
# @return [Object] new instance of the given +klass+
|
66
90
|
def result(klass, *args)
|
67
91
|
klass.new(*args)
|
68
92
|
end
|
69
93
|
|
94
|
+
# Checks whether value is of a #primitive class
|
95
|
+
# @param [Object] value
|
96
|
+
# @return [Boolean]
|
70
97
|
def primitive?(value)
|
71
98
|
value.is_a?(primitive)
|
72
99
|
end
|
data/lib/dry/types/enum.rb
CHANGED
@@ -6,8 +6,15 @@ module Dry
|
|
6
6
|
include Dry::Equalizer(:type, :options, :values)
|
7
7
|
include Decorator
|
8
8
|
|
9
|
-
|
9
|
+
# @return [Array]
|
10
|
+
attr_reader :values
|
10
11
|
|
12
|
+
# @return [Hash]
|
13
|
+
attr_reader :mapping
|
14
|
+
|
15
|
+
# @param [Definition] type
|
16
|
+
# @param [Hash] options
|
17
|
+
# @option options [Array] :values
|
11
18
|
def initialize(type, options)
|
12
19
|
super
|
13
20
|
@values = options.fetch(:values).freeze
|
@@ -15,6 +22,8 @@ module Dry
|
|
15
22
|
@mapping = values.each_with_object({}) { |v, h| h[values.index(v)] = v }.freeze
|
16
23
|
end
|
17
24
|
|
25
|
+
# @param [Object] input
|
26
|
+
# @return [Object]
|
18
27
|
def call(input)
|
19
28
|
value =
|
20
29
|
if values.include?(input)
|
data/lib/dry/types/errors.rb
CHANGED
@@ -2,9 +2,13 @@ module Dry
|
|
2
2
|
module Types
|
3
3
|
extend Dry::Configurable
|
4
4
|
|
5
|
+
# @!attribute [r] namespace
|
6
|
+
# @return [Container{String => Definition}]
|
5
7
|
setting :namespace, self
|
6
8
|
|
7
9
|
class SchemaError < TypeError
|
10
|
+
# @param [String] key
|
11
|
+
# @param [Object] value
|
8
12
|
def initialize(key, value)
|
9
13
|
super("#{value.inspect} (#{value.class}) has invalid type for :#{key}")
|
10
14
|
end
|
@@ -14,20 +18,27 @@ module Dry
|
|
14
18
|
private_constant(:SchemaKeyError)
|
15
19
|
|
16
20
|
class MissingKeyError < SchemaKeyError
|
21
|
+
# @param [String] key
|
17
22
|
def initialize(key)
|
18
23
|
super(":#{key} is missing in Hash input")
|
19
24
|
end
|
20
25
|
end
|
21
26
|
|
22
27
|
class UnknownKeysError < SchemaKeyError
|
28
|
+
# @param [<String, Symbol>] keys
|
23
29
|
def initialize(*keys)
|
24
30
|
super("unexpected keys #{keys.inspect} in Hash input")
|
25
31
|
end
|
26
32
|
end
|
27
33
|
|
28
|
-
ConstraintError
|
29
|
-
|
34
|
+
class ConstraintError < TypeError
|
35
|
+
# @return [String, #to_s]
|
36
|
+
attr_reader :result
|
37
|
+
# @return [Object]
|
38
|
+
attr_reader :input
|
30
39
|
|
40
|
+
# @param [String, #to_s] result
|
41
|
+
# @param [Object] input
|
31
42
|
def initialize(result, input)
|
32
43
|
@result = result
|
33
44
|
@input = input
|
@@ -39,6 +50,7 @@ module Dry
|
|
39
50
|
end
|
40
51
|
end
|
41
52
|
|
53
|
+
# @return [String]
|
42
54
|
def to_s
|
43
55
|
"#{input.inspect} violates constraints (#{result} failed)"
|
44
56
|
end
|
@@ -9,19 +9,27 @@ module Dry
|
|
9
9
|
include Builder
|
10
10
|
include Dry::Monads::Maybe::Mixin
|
11
11
|
|
12
|
+
# @param [Dry::Monads::Maybe, Object] input
|
13
|
+
# @return [Dry::Monads::Maybe]
|
12
14
|
def call(input)
|
13
15
|
input.is_a?(Dry::Monads::Maybe) ? input : Maybe(type[input])
|
14
16
|
end
|
15
17
|
alias_method :[], :call
|
16
18
|
|
19
|
+
# @param [Object] input
|
20
|
+
# @return [Result::Success]
|
17
21
|
def try(input)
|
18
22
|
Result::Success.new(Maybe(type[input]))
|
19
23
|
end
|
20
24
|
|
25
|
+
# @return [true]
|
21
26
|
def maybe?
|
22
27
|
true
|
23
28
|
end
|
24
29
|
|
30
|
+
# @param [Object] value
|
31
|
+
# @see Dry::Types::Builder#default
|
32
|
+
# @raise [ArgumentError] if nil provided as default value
|
25
33
|
def default(value)
|
26
34
|
if value.nil?
|
27
35
|
raise ArgumentError, "nil cannot be used as a default of a maybe type"
|
@@ -32,6 +40,7 @@ module Dry
|
|
32
40
|
end
|
33
41
|
|
34
42
|
module Builder
|
43
|
+
# @return [Maybe]
|
35
44
|
def maybe
|
36
45
|
Maybe.new(Types['strict.nil'] | self)
|
37
46
|
end
|
@@ -39,6 +48,9 @@ module Dry
|
|
39
48
|
|
40
49
|
class Hash
|
41
50
|
module MaybeTypes
|
51
|
+
# @param [Hash] result
|
52
|
+
# @param [Symbol] key
|
53
|
+
# @param [Definition] type
|
42
54
|
def resolve_missing_value(result, key, type)
|
43
55
|
if type.respond_to?(:maybe?) && type.maybe?
|
44
56
|
result[key] = type[nil]
|
@@ -48,8 +60,13 @@ module Dry
|
|
48
60
|
end
|
49
61
|
end
|
50
62
|
|
51
|
-
StrictWithDefaults
|
52
|
-
|
63
|
+
class StrictWithDefaults < Strict
|
64
|
+
include MaybeTypes
|
65
|
+
end
|
66
|
+
|
67
|
+
class Schema < Hash
|
68
|
+
include MaybeTypes
|
69
|
+
end
|
53
70
|
end
|
54
71
|
|
55
72
|
# Register non-coercible maybe types
|