dry-types 0.14.1 → 1.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +631 -134
- data/LICENSE +17 -17
- data/README.md +15 -13
- data/dry-types.gemspec +27 -30
- data/lib/dry/types/any.rb +32 -12
- data/lib/dry/types/array/constructor.rb +32 -0
- data/lib/dry/types/array/member.rb +75 -16
- data/lib/dry/types/array.rb +19 -6
- data/lib/dry/types/builder.rb +131 -15
- data/lib/dry/types/builder_methods.rb +49 -20
- data/lib/dry/types/coercions/json.rb +43 -7
- data/lib/dry/types/coercions/params.rb +118 -31
- data/lib/dry/types/coercions.rb +76 -22
- data/lib/dry/types/compat.rb +0 -2
- data/lib/dry/types/compiler.rb +56 -41
- data/lib/dry/types/constrained/coercible.rb +36 -6
- data/lib/dry/types/constrained.rb +81 -32
- data/lib/dry/types/constraints.rb +18 -4
- data/lib/dry/types/constructor/function.rb +216 -0
- data/lib/dry/types/constructor/wrapper.rb +94 -0
- data/lib/dry/types/constructor.rb +126 -56
- data/lib/dry/types/container.rb +7 -0
- data/lib/dry/types/core.rb +54 -21
- data/lib/dry/types/decorator.rb +38 -17
- data/lib/dry/types/default.rb +61 -16
- data/lib/dry/types/enum.rb +43 -20
- data/lib/dry/types/errors.rb +75 -9
- data/lib/dry/types/extensions/maybe.rb +74 -16
- data/lib/dry/types/extensions/monads.rb +29 -0
- data/lib/dry/types/extensions.rb +7 -1
- data/lib/dry/types/fn_container.rb +6 -1
- data/lib/dry/types/hash/constructor.rb +33 -0
- data/lib/dry/types/hash.rb +86 -67
- data/lib/dry/types/inflector.rb +3 -1
- data/lib/dry/types/json.rb +18 -16
- data/lib/dry/types/lax.rb +75 -0
- data/lib/dry/types/map.rb +76 -33
- data/lib/dry/types/meta.rb +51 -0
- data/lib/dry/types/module.rb +120 -0
- data/lib/dry/types/nominal.rb +210 -0
- data/lib/dry/types/options.rb +13 -26
- data/lib/dry/types/params.rb +39 -25
- data/lib/dry/types/predicate_inferrer.rb +238 -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 +16 -0
- data/lib/dry/types/printer.rb +315 -0
- data/lib/dry/types/result.rb +29 -3
- data/lib/dry/types/schema/key.rb +156 -0
- data/lib/dry/types/schema.rb +408 -0
- data/lib/dry/types/spec/types.rb +103 -33
- data/lib/dry/types/sum.rb +84 -35
- data/lib/dry/types/type.rb +49 -0
- data/lib/dry/types/version.rb +3 -1
- data/lib/dry/types.rb +156 -76
- data/lib/dry-types.rb +3 -1
- metadata +65 -78
- data/.gitignore +0 -10
- data/.rspec +0 -2
- data/.travis.yml +0 -27
- data/.yardopts +0 -5
- data/CONTRIBUTING.md +0 -29
- data/Gemfile +0 -24
- data/Rakefile +0 -20
- data/benchmarks/hash_schemas.rb +0 -51
- data/lib/dry/types/compat/form_types.rb +0 -27
- data/lib/dry/types/compat/int.rb +0 -14
- data/lib/dry/types/definition.rb +0 -113
- data/lib/dry/types/hash/schema.rb +0 -199
- data/lib/dry/types/hash/schema_builder.rb +0 -75
- data/lib/dry/types/safe.rb +0 -59
- data/log/.gitkeep +0 -0
@@ -1,9 +1,18 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/equalizer"
|
4
|
+
require "dry/types/fn_container"
|
5
|
+
require "dry/types/constructor/function"
|
6
|
+
require "dry/types/constructor/wrapper"
|
2
7
|
|
3
8
|
module Dry
|
4
9
|
module Types
|
5
|
-
|
6
|
-
|
10
|
+
# Constructor types apply a function to the input that is supposed to return
|
11
|
+
# a new value. Coercion is a common use case for constructor types.
|
12
|
+
#
|
13
|
+
# @api public
|
14
|
+
class Constructor < Nominal
|
15
|
+
include Dry::Equalizer(:type, :options, inspect: false, immutable: true)
|
7
16
|
|
8
17
|
# @return [#call]
|
9
18
|
attr_reader :fn
|
@@ -11,118 +20,179 @@ module Dry
|
|
11
20
|
# @return [Type]
|
12
21
|
attr_reader :type
|
13
22
|
|
14
|
-
undef :constrained
|
23
|
+
undef :constrained?, :meta, :optional?, :primitive, :default?, :name
|
15
24
|
|
16
25
|
# @param [Builder, Object] input
|
17
26
|
# @param [Hash] options
|
18
27
|
# @param [#call, nil] block
|
28
|
+
#
|
29
|
+
# @api public
|
19
30
|
def self.new(input, **options, &block)
|
20
|
-
type = input.is_a?(Builder) ? input :
|
21
|
-
super(type, **options,
|
31
|
+
type = input.is_a?(Builder) ? input : Nominal.new(input)
|
32
|
+
super(type, **options, fn: Function[options.fetch(:fn, block)])
|
22
33
|
end
|
23
34
|
|
24
|
-
# @param [
|
35
|
+
# @param [Builder, Object] input
|
25
36
|
# @param [Hash] options
|
26
37
|
# @param [#call, nil] block
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
raise ArgumentError, 'Missing constructor block' if fn.nil?
|
38
|
+
#
|
39
|
+
# @api public
|
40
|
+
def self.[](type, fn:, **options)
|
41
|
+
function = Function[fn]
|
32
42
|
|
33
|
-
|
43
|
+
if function.wrapper?
|
44
|
+
wrapper_type.new(type, fn: function, **options)
|
45
|
+
else
|
46
|
+
new(type, fn: function, **options)
|
47
|
+
end
|
34
48
|
end
|
35
49
|
|
36
|
-
# @
|
37
|
-
def
|
38
|
-
|
50
|
+
# @api private
|
51
|
+
def self.wrapper_type
|
52
|
+
@wrapper_type ||= begin
|
53
|
+
if self < Wrapper
|
54
|
+
self
|
55
|
+
else
|
56
|
+
const_set(:Wrapping, ::Class.new(self).include(Wrapper))
|
57
|
+
end
|
58
|
+
end
|
39
59
|
end
|
40
60
|
|
41
|
-
#
|
42
|
-
|
43
|
-
|
61
|
+
# Instantiate a new constructor type instance
|
62
|
+
#
|
63
|
+
# @param [Type] type
|
64
|
+
# @param [Function] fn
|
65
|
+
# @param [Hash] options
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
def initialize(type, fn: nil, **options)
|
69
|
+
@type = type
|
70
|
+
@fn = fn
|
71
|
+
|
72
|
+
super(type, **options, fn: fn)
|
44
73
|
end
|
45
74
|
|
46
|
-
|
47
|
-
|
75
|
+
# @return [Object]
|
76
|
+
#
|
77
|
+
# @api private
|
78
|
+
def call_safe(input)
|
79
|
+
coerced = fn.(input) { |output = input| return yield(output) }
|
80
|
+
type.call_safe(coerced) { |output = coerced| yield(output) }
|
48
81
|
end
|
49
82
|
|
50
|
-
# @param [Object] input
|
51
83
|
# @return [Object]
|
52
|
-
|
53
|
-
|
84
|
+
#
|
85
|
+
# @api private
|
86
|
+
def call_unsafe(input)
|
87
|
+
type.call_unsafe(fn.(input))
|
54
88
|
end
|
55
|
-
alias_method :[], :call
|
56
89
|
|
57
90
|
# @param [Object] input
|
58
91
|
# @param [#call,nil] block
|
92
|
+
#
|
59
93
|
# @return [Logic::Result, Types::Result]
|
60
94
|
# @return [Object] if block given and try fails
|
95
|
+
#
|
96
|
+
# @api public
|
61
97
|
def try(input, &block)
|
62
|
-
|
63
|
-
rescue
|
64
|
-
failure(input, e
|
98
|
+
value = fn.(input)
|
99
|
+
rescue CoercionError => e
|
100
|
+
failure = failure(input, e)
|
101
|
+
block_given? ? yield(failure) : failure
|
102
|
+
else
|
103
|
+
type.try(value, &block)
|
65
104
|
end
|
66
105
|
|
106
|
+
# Build a new constructor by appending a block to the coercion function
|
107
|
+
#
|
67
108
|
# @param [#call, nil] new_fn
|
68
109
|
# @param [Hash] options
|
69
110
|
# @param [#call, nil] block
|
111
|
+
#
|
70
112
|
# @return [Constructor]
|
113
|
+
#
|
114
|
+
# @api public
|
71
115
|
def constructor(new_fn = nil, **options, &block)
|
72
|
-
|
73
|
-
right = fn
|
74
|
-
|
75
|
-
with(options.merge(fn: -> input { left[right[input]] }))
|
76
|
-
end
|
116
|
+
next_fn = Function[new_fn || block]
|
77
117
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
false
|
84
|
-
else
|
85
|
-
type.valid?(constructed_value)
|
118
|
+
if next_fn.wrapper?
|
119
|
+
self.class.wrapper_type.new(with(**options), fn: next_fn)
|
120
|
+
else
|
121
|
+
with(**options, fn: fn >> next_fn)
|
122
|
+
end
|
86
123
|
end
|
87
|
-
alias_method
|
124
|
+
alias_method :append, :constructor
|
125
|
+
alias_method :>>, :constructor
|
88
126
|
|
89
127
|
# @return [Class]
|
128
|
+
#
|
129
|
+
# @api private
|
90
130
|
def constrained_type
|
91
131
|
Constrained::Coercible
|
92
132
|
end
|
93
133
|
|
94
|
-
# @
|
134
|
+
# @see Nominal#to_ast
|
95
135
|
#
|
96
|
-
# @
|
136
|
+
# @api public
|
97
137
|
def to_ast(meta: true)
|
98
|
-
[:constructor, [type.to_ast(meta: meta),
|
99
|
-
register_fn(fn),
|
100
|
-
meta ? self.meta : EMPTY_HASH]]
|
138
|
+
[:constructor, [type.to_ast(meta: meta), fn.to_ast]]
|
101
139
|
end
|
102
140
|
|
103
|
-
|
141
|
+
# Build a new constructor by prepending a block to the coercion function
|
142
|
+
#
|
143
|
+
# @param [#call, nil] new_fn
|
144
|
+
# @param [Hash] options
|
145
|
+
# @param [#call, nil] block
|
146
|
+
#
|
147
|
+
# @return [Constructor]
|
148
|
+
#
|
149
|
+
# @api public
|
150
|
+
def prepend(new_fn = nil, **options, &block)
|
151
|
+
with(**options, fn: fn << (new_fn || block))
|
152
|
+
end
|
153
|
+
alias_method :<<, :prepend
|
154
|
+
|
155
|
+
# Build a lax type
|
156
|
+
#
|
157
|
+
# @return [Lax]
|
158
|
+
# @api public
|
159
|
+
def lax
|
160
|
+
Lax.new(constructor_type[type.lax, **options])
|
161
|
+
end
|
104
162
|
|
105
|
-
|
106
|
-
|
163
|
+
# Wrap the type with a proc
|
164
|
+
#
|
165
|
+
# @return [Proc]
|
166
|
+
#
|
167
|
+
# @api public
|
168
|
+
def to_proc
|
169
|
+
proc { |value| self.(value) }
|
107
170
|
end
|
108
171
|
|
172
|
+
private
|
173
|
+
|
109
174
|
# @param [Symbol] meth
|
110
175
|
# @param [Boolean] include_private
|
111
176
|
# @return [Boolean]
|
177
|
+
#
|
178
|
+
# @api private
|
112
179
|
def respond_to_missing?(meth, include_private = false)
|
113
180
|
super || type.respond_to?(meth)
|
114
181
|
end
|
115
182
|
|
116
183
|
# Delegates missing methods to {#type}
|
117
|
-
#
|
184
|
+
#
|
185
|
+
# @param [Symbol] method
|
118
186
|
# @param [Array] args
|
119
187
|
# @param [#call, nil] block
|
120
|
-
|
121
|
-
|
122
|
-
|
188
|
+
#
|
189
|
+
# @api private
|
190
|
+
def method_missing(method, *args, &block)
|
191
|
+
if type.respond_to?(method)
|
192
|
+
response = type.public_send(method, *args, &block)
|
123
193
|
|
124
|
-
if response.
|
125
|
-
|
194
|
+
if response.is_a?(Type) && type.class.equal?(response.class)
|
195
|
+
response.constructor_type[response, **options]
|
126
196
|
else
|
127
197
|
response
|
128
198
|
end
|
data/lib/dry/types/container.rb
CHANGED
data/lib/dry/types/core.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/types/any"
|
2
4
|
|
3
5
|
module Dry
|
4
6
|
module Types
|
5
|
-
|
7
|
+
# Primitives with {Kernel} coercion methods
|
8
|
+
KERNEL_COERCIBLE = {
|
6
9
|
string: String,
|
7
10
|
integer: Integer,
|
8
11
|
float: Float,
|
@@ -11,9 +14,19 @@ module Dry
|
|
11
14
|
hash: ::Hash
|
12
15
|
}.freeze
|
13
16
|
|
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
|
14
28
|
NON_COERCIBLE = {
|
15
29
|
nil: NilClass,
|
16
|
-
symbol: Symbol,
|
17
30
|
class: Class,
|
18
31
|
true: TrueClass,
|
19
32
|
false: FalseClass,
|
@@ -23,44 +36,64 @@ module Dry
|
|
23
36
|
range: Range
|
24
37
|
}.freeze
|
25
38
|
|
26
|
-
|
39
|
+
# All built-in 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
|
27
44
|
|
45
|
+
# All built-in primitives except {NilClass}
|
28
46
|
NON_NIL = ALL_PRIMITIVES.reject { |name, _| name == :nil }.freeze
|
29
47
|
|
30
|
-
# Register
|
48
|
+
# Register generic types for {ALL_PRIMITIVES}
|
31
49
|
ALL_PRIMITIVES.each do |name, primitive|
|
32
|
-
|
50
|
+
type = Nominal[primitive].new(primitive)
|
51
|
+
register("nominal.#{name}", type)
|
33
52
|
end
|
34
53
|
|
35
|
-
# Register strict
|
54
|
+
# Register strict types for {ALL_PRIMITIVES}
|
36
55
|
ALL_PRIMITIVES.each do |name, primitive|
|
37
|
-
|
56
|
+
type = self["nominal.#{name}"].constrained(type: primitive)
|
57
|
+
register(name.to_s, type)
|
58
|
+
register("strict.#{name}", type)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Register {KERNEL_COERCIBLE} types
|
62
|
+
KERNEL_COERCIBLE.each do |name, primitive|
|
63
|
+
register("coercible.#{name}", self["nominal.#{name}"].constructor(Kernel.method(primitive.name)))
|
38
64
|
end
|
39
65
|
|
40
|
-
# Register
|
41
|
-
|
42
|
-
register(
|
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
|
+
)
|
43
71
|
end
|
44
72
|
|
45
|
-
# Register
|
73
|
+
# Register optional strict {NON_NIL} types
|
46
74
|
NON_NIL.each_key do |name|
|
47
|
-
|
75
|
+
type = self[name.to_s].optional
|
76
|
+
register("optional.strict.#{name}", type)
|
77
|
+
register("optional.#{name}", type)
|
48
78
|
end
|
49
79
|
|
50
|
-
# Register
|
80
|
+
# Register optional {COERCIBLE} types
|
51
81
|
COERCIBLE.each_key do |name|
|
52
82
|
register("optional.coercible.#{name}", self["coercible.#{name}"].optional)
|
53
83
|
end
|
54
84
|
|
55
|
-
# Register
|
56
|
-
register("bool", self["true"] | self["false"])
|
57
|
-
|
85
|
+
# Register `:bool` since it's common and not a built-in Ruby type :(
|
86
|
+
register("nominal.bool", self["nominal.true"] | self["nominal.false"])
|
87
|
+
bool = self["strict.true"] | self["strict.false"]
|
88
|
+
register("strict.bool", bool)
|
89
|
+
register("bool", bool)
|
58
90
|
|
59
91
|
register("any", Any)
|
60
|
-
register("
|
92
|
+
register("nominal.any", Any)
|
93
|
+
register("strict.any", Any)
|
61
94
|
end
|
62
95
|
end
|
63
96
|
|
64
|
-
require
|
65
|
-
require
|
66
|
-
require
|
97
|
+
require "dry/types/coercions"
|
98
|
+
require "dry/types/params"
|
99
|
+
require "dry/types/json"
|
data/lib/dry/types/decorator.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
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
|
|
@@ -9,63 +14,76 @@ module Dry
|
|
9
14
|
attr_reader :type
|
10
15
|
|
11
16
|
# @param [Type] type
|
12
|
-
def initialize(type,
|
17
|
+
def initialize(type, *, **)
|
13
18
|
super
|
14
19
|
@type = type
|
15
20
|
end
|
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
|
-
# @return [Sum]
|
43
|
-
def optional
|
44
|
-
Types['strict.nil'] | self
|
45
|
-
end
|
46
|
-
|
47
47
|
# @param [Symbol] meth
|
48
48
|
# @param [Boolean] include_private
|
49
|
+
#
|
49
50
|
# @return [Boolean]
|
51
|
+
#
|
52
|
+
# @api public
|
50
53
|
def respond_to_missing?(meth, include_private = false)
|
51
54
|
super || type.respond_to?(meth)
|
52
55
|
end
|
53
56
|
|
57
|
+
# Wrap the type with a proc
|
58
|
+
#
|
59
|
+
# @return [Proc]
|
60
|
+
#
|
61
|
+
# @api public
|
62
|
+
def to_proc
|
63
|
+
proc { |value| self.(value) }
|
64
|
+
end
|
65
|
+
|
54
66
|
private
|
55
67
|
|
56
68
|
# @param [Object] response
|
69
|
+
#
|
57
70
|
# @return [Boolean]
|
71
|
+
#
|
72
|
+
# @api private
|
58
73
|
def decorate?(response)
|
59
|
-
response.
|
74
|
+
response.is_a?(type.class)
|
60
75
|
end
|
61
76
|
|
62
77
|
# Delegates missing methods to {#type}
|
78
|
+
#
|
63
79
|
# @param [Symbol] meth
|
64
80
|
# @param [Array] args
|
65
81
|
# @param [#call, nil] block
|
82
|
+
#
|
83
|
+
# @api private
|
66
84
|
def method_missing(meth, *args, &block)
|
67
85
|
if type.respond_to?(meth)
|
68
|
-
response = type.
|
86
|
+
response = type.public_send(meth, *args, &block)
|
69
87
|
|
70
88
|
if decorate?(response)
|
71
89
|
__new__(response)
|
@@ -76,10 +94,13 @@ module Dry
|
|
76
94
|
super
|
77
95
|
end
|
78
96
|
end
|
97
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
79
98
|
|
80
99
|
# Replace underlying type
|
100
|
+
#
|
101
|
+
# @api private
|
81
102
|
def __new__(type)
|
82
|
-
self.class.new(type, options)
|
103
|
+
self.class.new(type, *@__args__.drop(1), **@options)
|
83
104
|
end
|
84
105
|
end
|
85
106
|
end
|
data/lib/dry/types/default.rb
CHANGED
@@ -1,30 +1,46 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/equalizer"
|
4
|
+
require "dry/types/decorator"
|
2
5
|
|
3
6
|
module Dry
|
4
7
|
module Types
|
8
|
+
# Default types are useful when a missing value should be replaced by a default one
|
9
|
+
#
|
10
|
+
# @api public
|
5
11
|
class Default
|
6
|
-
|
7
|
-
include Dry::Equalizer(:type, :options, :value)
|
8
|
-
include Decorator
|
9
|
-
include Builder
|
10
|
-
|
12
|
+
# @api private
|
11
13
|
class Callable < Default
|
12
|
-
include Dry::Equalizer(:type, :
|
14
|
+
include Dry::Equalizer(:type, inspect: false, immutable: true)
|
13
15
|
|
14
16
|
# Evaluates given callable
|
15
17
|
# @return [Object]
|
16
18
|
def evaluate
|
17
19
|
value.call(type)
|
18
20
|
end
|
21
|
+
|
22
|
+
# @return [true]
|
23
|
+
def callable?
|
24
|
+
true
|
25
|
+
end
|
19
26
|
end
|
20
27
|
|
28
|
+
include Type
|
29
|
+
include Decorator
|
30
|
+
include Builder
|
31
|
+
include Printable
|
32
|
+
include Dry::Equalizer(:type, :value, inspect: false, immutable: true)
|
33
|
+
|
21
34
|
# @return [Object]
|
22
35
|
attr_reader :value
|
23
36
|
|
24
37
|
alias_method :evaluate, :value
|
25
38
|
|
26
39
|
# @param [Object, #call] value
|
40
|
+
#
|
27
41
|
# @return [Class] {Default} or {Default::Callable}
|
42
|
+
#
|
43
|
+
# @api private
|
28
44
|
def self.[](value)
|
29
45
|
if value.respond_to?(:call)
|
30
46
|
Callable
|
@@ -35,49 +51,78 @@ module Dry
|
|
35
51
|
|
36
52
|
# @param [Type] type
|
37
53
|
# @param [Object] value
|
54
|
+
#
|
55
|
+
# @api private
|
38
56
|
def initialize(type, value, **options)
|
39
57
|
super
|
40
58
|
@value = value
|
41
59
|
end
|
42
60
|
|
61
|
+
# Build a constrained type
|
62
|
+
#
|
43
63
|
# @param [Array] args see {Dry::Types::Builder#constrained}
|
64
|
+
#
|
44
65
|
# @return [Default]
|
66
|
+
#
|
67
|
+
# @api public
|
45
68
|
def constrained(*args)
|
46
69
|
type.constrained(*args).default(value)
|
47
70
|
end
|
48
71
|
|
49
72
|
# @return [true]
|
73
|
+
#
|
74
|
+
# @api public
|
50
75
|
def default?
|
51
76
|
true
|
52
77
|
end
|
53
78
|
|
54
79
|
# @param [Object] input
|
80
|
+
#
|
55
81
|
# @return [Result::Success]
|
82
|
+
#
|
83
|
+
# @api public
|
56
84
|
def try(input)
|
57
85
|
success(call(input))
|
58
86
|
end
|
59
87
|
|
88
|
+
# @return [Boolean]
|
89
|
+
#
|
90
|
+
# @api public
|
60
91
|
def valid?(value = Undefined)
|
61
|
-
|
92
|
+
Undefined.equal?(value) || super
|
62
93
|
end
|
63
94
|
|
64
95
|
# @param [Object] input
|
96
|
+
#
|
65
97
|
# @return [Object] value passed through {#type} or {#default} value
|
66
|
-
|
98
|
+
#
|
99
|
+
# @api private
|
100
|
+
def call_unsafe(input = Undefined)
|
67
101
|
if input.equal?(Undefined)
|
68
102
|
evaluate
|
69
103
|
else
|
70
|
-
|
71
|
-
output.nil? ? evaluate : output
|
104
|
+
Undefined.default(type.call_unsafe(input)) { evaluate }
|
72
105
|
end
|
73
106
|
end
|
74
|
-
alias_method :[], :call
|
75
107
|
|
76
|
-
|
108
|
+
# @param [Object] input
|
109
|
+
#
|
110
|
+
# @return [Object] value passed through {#type} or {#default} value
|
111
|
+
#
|
112
|
+
# @api private
|
113
|
+
def call_safe(input = Undefined, &block)
|
114
|
+
if input.equal?(Undefined)
|
115
|
+
evaluate
|
116
|
+
else
|
117
|
+
Undefined.default(type.call_safe(input, &block)) { evaluate }
|
118
|
+
end
|
119
|
+
end
|
77
120
|
|
78
|
-
#
|
79
|
-
|
80
|
-
|
121
|
+
# @return [false]
|
122
|
+
#
|
123
|
+
# @api private
|
124
|
+
def callable?
|
125
|
+
false
|
81
126
|
end
|
82
127
|
end
|
83
128
|
end
|