dry-types 0.14.1 → 1.5.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 +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
|