dry-types 0.13.2 → 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 +763 -233
- data/LICENSE +17 -17
- data/README.md +15 -13
- data/dry-types.gemspec +28 -28
- data/lib/dry-types.rb +3 -1
- data/lib/dry/types.rb +156 -76
- data/lib/dry/types/any.rb +32 -12
- data/lib/dry/types/array.rb +19 -6
- data/lib/dry/types/array/constructor.rb +32 -0
- data/lib/dry/types/array/member.rb +75 -16
- data/lib/dry/types/builder.rb +131 -15
- data/lib/dry/types/builder_methods.rb +49 -20
- data/lib/dry/types/coercions.rb +76 -22
- data/lib/dry/types/coercions/json.rb +43 -7
- data/lib/dry/types/coercions/params.rb +118 -31
- data/lib/dry/types/compat.rb +0 -2
- data/lib/dry/types/compiler.rb +56 -41
- data/lib/dry/types/constrained.rb +81 -32
- data/lib/dry/types/constrained/coercible.rb +36 -6
- data/lib/dry/types/constraints.rb +18 -4
- data/lib/dry/types/constructor.rb +127 -54
- data/lib/dry/types/constructor/function.rb +216 -0
- data/lib/dry/types/constructor/wrapper.rb +94 -0
- 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.rb +7 -1
- data/lib/dry/types/extensions/maybe.rb +74 -16
- data/lib/dry/types/extensions/monads.rb +29 -0
- data/lib/dry/types/fn_container.rb +6 -1
- data/lib/dry/types/hash.rb +86 -67
- data/lib/dry/types/hash/constructor.rb +33 -0
- 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.rb +408 -0
- data/lib/dry/types/schema/key.rb +156 -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
- metadata +68 -79
- data/.gitignore +0 -10
- data/.rspec +0 -2
- data/.travis.yml +0 -29
- 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
@@ -0,0 +1,156 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/equalizer"
|
4
|
+
require "dry/core/deprecations"
|
5
|
+
|
6
|
+
module Dry
|
7
|
+
module Types
|
8
|
+
# Schema is a hash with explicit member types defined
|
9
|
+
#
|
10
|
+
# @api public
|
11
|
+
class Schema < Hash
|
12
|
+
# Proxy type for schema keys. Contains only key name and
|
13
|
+
# whether it's required or not. All other calls deletaged
|
14
|
+
# to the wrapped type.
|
15
|
+
#
|
16
|
+
# @see Dry::Types::Schema
|
17
|
+
class Key
|
18
|
+
extend ::Dry::Core::Deprecations[:'dry-types']
|
19
|
+
include Type
|
20
|
+
include Dry::Equalizer(:name, :type, :options, inspect: false, immutable: true)
|
21
|
+
include Decorator
|
22
|
+
include Builder
|
23
|
+
include Printable
|
24
|
+
|
25
|
+
# @return [Symbol]
|
26
|
+
attr_reader :name
|
27
|
+
|
28
|
+
# @api private
|
29
|
+
def initialize(type, name, required: Undefined, **options)
|
30
|
+
required = Undefined.default(required) do
|
31
|
+
type.meta.fetch(:required) { !type.meta.fetch(:omittable, false) }
|
32
|
+
end
|
33
|
+
|
34
|
+
unless name.is_a?(::Symbol)
|
35
|
+
raise ArgumentError, "Schemas can only contain symbol keys, #{name.inspect} given"
|
36
|
+
end
|
37
|
+
|
38
|
+
super(type, name, required: required, **options)
|
39
|
+
@name = name
|
40
|
+
end
|
41
|
+
|
42
|
+
# @api private
|
43
|
+
def call_safe(input, &block)
|
44
|
+
type.call_safe(input, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
# @api private
|
48
|
+
def call_unsafe(input)
|
49
|
+
type.call_unsafe(input)
|
50
|
+
end
|
51
|
+
|
52
|
+
# @see Dry::Types::Nominal#try
|
53
|
+
#
|
54
|
+
# @api public
|
55
|
+
def try(input, &block)
|
56
|
+
type.try(input, &block)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Whether the key is required in schema input
|
60
|
+
#
|
61
|
+
# @return [Boolean]
|
62
|
+
#
|
63
|
+
# @api public
|
64
|
+
def required?
|
65
|
+
options.fetch(:required)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Control whether the key is required
|
69
|
+
#
|
70
|
+
# @overload required
|
71
|
+
# @return [Boolean]
|
72
|
+
#
|
73
|
+
# @overload required(required)
|
74
|
+
# Change key's "requireness"
|
75
|
+
#
|
76
|
+
# @param [Boolean] required New value
|
77
|
+
# @return [Dry::Types::Schema::Key]
|
78
|
+
#
|
79
|
+
# @api public
|
80
|
+
def required(required = Undefined)
|
81
|
+
if Undefined.equal?(required)
|
82
|
+
options.fetch(:required)
|
83
|
+
else
|
84
|
+
with(required: required)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Make key not required
|
89
|
+
#
|
90
|
+
# @return [Dry::Types::Schema::Key]
|
91
|
+
#
|
92
|
+
# @api public
|
93
|
+
def omittable
|
94
|
+
required(false)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Turn key into a lax type. Lax types are not strict hence such keys are not required
|
98
|
+
#
|
99
|
+
# @return [Lax]
|
100
|
+
#
|
101
|
+
# @api public
|
102
|
+
def lax
|
103
|
+
__new__(type.lax).required(false)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Make wrapped type optional
|
107
|
+
#
|
108
|
+
# @return [Key]
|
109
|
+
#
|
110
|
+
# @api public
|
111
|
+
def optional
|
112
|
+
__new__(type.optional)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Dump to internal AST representation
|
116
|
+
#
|
117
|
+
# @return [Array]
|
118
|
+
#
|
119
|
+
# @api public
|
120
|
+
def to_ast(meta: true)
|
121
|
+
[
|
122
|
+
:key,
|
123
|
+
[
|
124
|
+
name,
|
125
|
+
required,
|
126
|
+
type.to_ast(meta: meta)
|
127
|
+
]
|
128
|
+
]
|
129
|
+
end
|
130
|
+
|
131
|
+
# @see Dry::Types::Meta#meta
|
132
|
+
#
|
133
|
+
# @api public
|
134
|
+
def meta(data = Undefined)
|
135
|
+
if Undefined.equal?(data) || !data.key?(:omittable)
|
136
|
+
super
|
137
|
+
else
|
138
|
+
self.class.warn(
|
139
|
+
"Using meta for making schema keys is deprecated, " \
|
140
|
+
"please use .omittable or .required(false) instead" \
|
141
|
+
"\n" + Core::Deprecations::STACK.()
|
142
|
+
)
|
143
|
+
super.required(!data[:omittable])
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
# @api private
|
150
|
+
def decorate?(response)
|
151
|
+
response.is_a?(Type)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
data/lib/dry/types/spec/types.rb
CHANGED
@@ -1,94 +1,164 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.shared_examples_for "Dry::Types::Nominal without primitive" do
|
2
4
|
def be_boolean
|
3
|
-
satisfy { |x| x == true || x == false
|
5
|
+
satisfy { |x| x == true || x == false }
|
4
6
|
end
|
5
7
|
|
6
|
-
describe
|
7
|
-
it
|
8
|
+
describe "#constrained?" do
|
9
|
+
it "returns a boolean value" do
|
8
10
|
expect(type.constrained?).to be_boolean
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
12
|
-
describe
|
13
|
-
it
|
14
|
+
describe "#default?" do
|
15
|
+
it "returns a boolean value" do
|
14
16
|
expect(type.default?).to be_boolean
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
|
-
describe
|
19
|
-
it
|
20
|
+
describe "#valid?" do
|
21
|
+
it "returns a boolean value" do
|
20
22
|
expect(type.valid?(1)).to be_boolean
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
|
-
describe
|
25
|
-
it
|
26
|
+
describe "#eql?" do
|
27
|
+
it "has #eql? defined" do
|
26
28
|
expect(type).to eql(type)
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
30
|
-
describe
|
31
|
-
it
|
32
|
+
describe "#==" do
|
33
|
+
it "has #== defined" do
|
32
34
|
expect(type).to eq(type)
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
36
|
-
describe
|
37
|
-
it
|
38
|
+
describe "#optional?" do
|
39
|
+
it "returns a boolean value" do
|
38
40
|
expect(type.optional?).to be_boolean
|
39
41
|
end
|
40
42
|
end
|
43
|
+
|
44
|
+
describe "#to_s" do
|
45
|
+
it "returns a custom string representation" do
|
46
|
+
expect(type.to_s).to start_with("#<Dry::Types") if type.class.name.start_with?("Dry::Types")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#to_proc" do
|
51
|
+
subject(:callable) { type.to_proc }
|
52
|
+
|
53
|
+
it "converts a type to a proc" do
|
54
|
+
expect(callable).to be_a(Proc)
|
55
|
+
end
|
56
|
+
end
|
41
57
|
end
|
42
58
|
|
43
|
-
RSpec.shared_examples_for
|
44
|
-
describe
|
45
|
-
it
|
46
|
-
with_meta = type.meta(foo: :bar).meta(baz:
|
59
|
+
RSpec.shared_examples_for "Dry::Types::Nominal#meta" do
|
60
|
+
describe "#meta" do
|
61
|
+
it "allows setting meta information" do
|
62
|
+
with_meta = type.meta(foo: :bar).meta(baz: "1")
|
47
63
|
|
48
64
|
expect(with_meta).to be_instance_of(type.class)
|
49
|
-
expect(with_meta.meta).to eql(foo: :bar, baz:
|
65
|
+
expect(with_meta.meta).to eql(foo: :bar, baz: "1")
|
50
66
|
end
|
51
67
|
|
52
|
-
it
|
68
|
+
it "equalizes on empty meta" do
|
53
69
|
expect(type).to eql(type.meta({}))
|
54
70
|
end
|
55
71
|
|
56
|
-
it
|
57
|
-
expect(type).to_not eql(type.meta(i_am:
|
72
|
+
it "equalizes on filled meta" do
|
73
|
+
expect(type).to_not eql(type.meta(i_am: "different"))
|
58
74
|
end
|
59
75
|
|
60
|
-
it
|
76
|
+
it "is locally immutable" do
|
61
77
|
expect(type.meta).to be_a ::Hash
|
62
78
|
expect(type.meta).to be_frozen
|
63
79
|
expect(type.meta).not_to have_key :immutable_test
|
64
|
-
derived = type.
|
80
|
+
derived = type.meta(immutable_test: 1)
|
65
81
|
expect(derived.meta).to be_frozen
|
66
|
-
expect(derived.meta).to eql(
|
82
|
+
expect(derived.meta).to eql(immutable_test: 1)
|
67
83
|
expect(type.meta).not_to have_key :immutable_test
|
68
84
|
end
|
69
85
|
end
|
70
86
|
|
71
|
-
describe
|
72
|
-
it
|
87
|
+
describe "#pristine" do
|
88
|
+
it "erases meta" do
|
73
89
|
expect(type.meta(foo: :bar).pristine).to eql(type)
|
74
90
|
end
|
75
91
|
end
|
76
92
|
end
|
77
93
|
|
78
|
-
RSpec.shared_examples_for Dry::Types::
|
79
|
-
it_behaves_like
|
94
|
+
RSpec.shared_examples_for Dry::Types::Nominal do
|
95
|
+
it_behaves_like "Dry::Types::Nominal without primitive"
|
80
96
|
|
81
|
-
describe
|
82
|
-
it
|
97
|
+
describe "#primitive" do
|
98
|
+
it "returns a class" do
|
83
99
|
expect(type.primitive).to be_instance_of(Class)
|
84
100
|
end
|
85
101
|
end
|
86
102
|
|
87
|
-
describe
|
88
|
-
it
|
103
|
+
describe "#constructor" do
|
104
|
+
it "returns a constructor" do
|
89
105
|
constructor = type.constructor(&:to_s)
|
90
106
|
|
91
107
|
expect(constructor).to be_a(Dry::Types::Type)
|
92
108
|
end
|
93
109
|
end
|
94
110
|
end
|
111
|
+
|
112
|
+
RSpec.shared_examples_for "a constrained type" do |options = {inputs: Object.new}|
|
113
|
+
inputs = options[:inputs]
|
114
|
+
|
115
|
+
let(:fallback) { Object.new }
|
116
|
+
|
117
|
+
describe "#call" do
|
118
|
+
it "yields a block on failure" do
|
119
|
+
Array(inputs).each do |input|
|
120
|
+
expect(type.(input) { fallback }).to be(fallback)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
it "throws an error on invalid input" do
|
125
|
+
Array(inputs).each do |input|
|
126
|
+
expect { type.(input) }.to raise_error(Dry::Types::CoercionError)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "#constructor" do
|
132
|
+
let(:wrapping_constructor) do
|
133
|
+
type.constructor { |input, type| type.(input) { fallback } }
|
134
|
+
end
|
135
|
+
|
136
|
+
it "can be wrapped" do
|
137
|
+
Array(inputs).each do |input|
|
138
|
+
expect(wrapping_constructor.(input)).to be(fallback)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
RSpec.shared_examples_for "a nominal type" do |inputs: Object.new|
|
145
|
+
describe "#call" do
|
146
|
+
it "always returns the input back" do
|
147
|
+
Array(inputs).each do |input|
|
148
|
+
expect(type.(input) { raise }).to be(input)
|
149
|
+
expect(type.(input)).to be(input)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
RSpec.shared_examples_for "a composable constructor" do
|
156
|
+
describe "#constructor" do
|
157
|
+
it "has aliases for composition" do
|
158
|
+
expect(type.method(:append)).to eql(type.method(:constructor))
|
159
|
+
expect(type.method(:prepend)).to eql(type.method(:constructor))
|
160
|
+
expect(type.method(:<<)).to eql(type.method(:constructor))
|
161
|
+
expect(type.method(:>>)).to eql(type.method(:constructor))
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
data/lib/dry/types/sum.rb
CHANGED
@@ -1,12 +1,21 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/equalizer"
|
4
|
+
require "dry/types/options"
|
5
|
+
require "dry/types/meta"
|
2
6
|
|
3
7
|
module Dry
|
4
8
|
module Types
|
9
|
+
# Sum type
|
10
|
+
#
|
11
|
+
# @api public
|
5
12
|
class Sum
|
6
13
|
include Type
|
7
|
-
include Dry::Equalizer(:left, :right, :options, :meta)
|
8
14
|
include Builder
|
9
15
|
include Options
|
16
|
+
include Meta
|
17
|
+
include Printable
|
18
|
+
include Dry::Equalizer(:left, :right, :options, :meta, inspect: false, immutable: true)
|
10
19
|
|
11
20
|
# @return [Type]
|
12
21
|
attr_reader :left
|
@@ -14,6 +23,7 @@ module Dry
|
|
14
23
|
# @return [Type]
|
15
24
|
attr_reader :right
|
16
25
|
|
26
|
+
# @api private
|
17
27
|
class Constrained < Sum
|
18
28
|
# @return [Dry::Logic::Operations::Or]
|
19
29
|
def rule
|
@@ -24,68 +34,81 @@ module Dry
|
|
24
34
|
def constrained?
|
25
35
|
true
|
26
36
|
end
|
27
|
-
|
28
|
-
# @param [Object] input
|
29
|
-
# @return [Object]
|
30
|
-
# @raise [ConstraintError] if given +input+ not passing {#try}
|
31
|
-
def call(input)
|
32
|
-
try(input) do |result|
|
33
|
-
raise ConstraintError.new(result, input)
|
34
|
-
end.input
|
35
|
-
end
|
36
|
-
alias_method :[], :call
|
37
37
|
end
|
38
38
|
|
39
39
|
# @param [Type] left
|
40
40
|
# @param [Type] right
|
41
41
|
# @param [Hash] options
|
42
|
-
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
def initialize(left, right, **options)
|
43
45
|
super
|
44
46
|
@left, @right = left, right
|
45
47
|
freeze
|
46
48
|
end
|
47
49
|
|
48
50
|
# @return [String]
|
51
|
+
#
|
52
|
+
# @api public
|
49
53
|
def name
|
50
|
-
[left, right].map(&:name).join(
|
54
|
+
[left, right].map(&:name).join(" | ")
|
51
55
|
end
|
52
56
|
|
53
57
|
# @return [false]
|
58
|
+
#
|
59
|
+
# @api public
|
54
60
|
def default?
|
55
61
|
false
|
56
62
|
end
|
57
63
|
|
58
64
|
# @return [false]
|
65
|
+
#
|
66
|
+
# @api public
|
59
67
|
def constrained?
|
60
68
|
false
|
61
69
|
end
|
62
70
|
|
63
71
|
# @return [Boolean]
|
72
|
+
#
|
73
|
+
# @api public
|
64
74
|
def optional?
|
65
|
-
|
75
|
+
primitive?(nil)
|
66
76
|
end
|
67
77
|
|
68
78
|
# @param [Object] input
|
79
|
+
#
|
69
80
|
# @return [Object]
|
70
|
-
|
71
|
-
|
81
|
+
#
|
82
|
+
# @api private
|
83
|
+
def call_unsafe(input)
|
84
|
+
left.call_safe(input) { right.call_unsafe(input) }
|
72
85
|
end
|
73
|
-
alias_method :[], :call
|
74
|
-
|
75
|
-
def try(input, &block)
|
76
|
-
result = left.try(input) do
|
77
|
-
right.try(input)
|
78
|
-
end
|
79
86
|
|
80
|
-
|
87
|
+
# @param [Object] input
|
88
|
+
#
|
89
|
+
# @return [Object]
|
90
|
+
#
|
91
|
+
# @api private
|
92
|
+
def call_safe(input, &block)
|
93
|
+
left.call_safe(input) { right.call_safe(input, &block) }
|
94
|
+
end
|
81
95
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
96
|
+
# @param [Object] input
|
97
|
+
#
|
98
|
+
# @api public
|
99
|
+
def try(input)
|
100
|
+
left.try(input) do
|
101
|
+
right.try(input) do |failure|
|
102
|
+
if block_given?
|
103
|
+
yield(failure)
|
104
|
+
else
|
105
|
+
failure
|
106
|
+
end
|
107
|
+
end
|
86
108
|
end
|
87
109
|
end
|
88
110
|
|
111
|
+
# @api private
|
89
112
|
def success(input)
|
90
113
|
if left.valid?(input)
|
91
114
|
left.success(input)
|
@@ -96,6 +119,7 @@ module Dry
|
|
96
119
|
end
|
97
120
|
end
|
98
121
|
|
122
|
+
# @api private
|
99
123
|
def failure(input, _error = nil)
|
100
124
|
if !left.valid?(input)
|
101
125
|
left.failure(input, left.try(input).error)
|
@@ -105,28 +129,44 @@ module Dry
|
|
105
129
|
end
|
106
130
|
|
107
131
|
# @param [Object] value
|
132
|
+
#
|
108
133
|
# @return [Boolean]
|
134
|
+
#
|
135
|
+
# @api private
|
109
136
|
def primitive?(value)
|
110
137
|
left.primitive?(value) || right.primitive?(value)
|
111
138
|
end
|
112
139
|
|
113
|
-
#
|
114
|
-
#
|
115
|
-
|
116
|
-
|
140
|
+
# Manage metadata to the type. If the type is an optional, #meta delegates
|
141
|
+
# to the right branch
|
142
|
+
#
|
143
|
+
# @see [Meta#meta]
|
144
|
+
#
|
145
|
+
# @api public
|
146
|
+
def meta(data = Undefined)
|
147
|
+
if Undefined.equal?(data)
|
148
|
+
optional? ? right.meta : super
|
149
|
+
elsif optional?
|
150
|
+
self.class.new(left, right.meta(data), **options)
|
151
|
+
else
|
152
|
+
super
|
153
|
+
end
|
117
154
|
end
|
118
|
-
alias_method :===, :valid?
|
119
155
|
|
120
|
-
# @
|
156
|
+
# @see Nominal#to_ast
|
121
157
|
#
|
122
|
-
# @
|
158
|
+
# @api public
|
123
159
|
def to_ast(meta: true)
|
124
160
|
[:sum, [left.to_ast(meta: meta), right.to_ast(meta: meta), meta ? self.meta : EMPTY_HASH]]
|
125
161
|
end
|
126
162
|
|
127
163
|
# @param [Hash] options
|
164
|
+
#
|
128
165
|
# @return [Constrained,Sum]
|
166
|
+
#
|
129
167
|
# @see Builder#constrained
|
168
|
+
#
|
169
|
+
# @api public
|
130
170
|
def constrained(options)
|
131
171
|
if optional?
|
132
172
|
right.constrained(options).optional
|
@@ -134,6 +174,15 @@ module Dry
|
|
134
174
|
super
|
135
175
|
end
|
136
176
|
end
|
177
|
+
|
178
|
+
# Wrap the type with a proc
|
179
|
+
#
|
180
|
+
# @return [Proc]
|
181
|
+
#
|
182
|
+
# @api public
|
183
|
+
def to_proc
|
184
|
+
proc { |value| self.(value) }
|
185
|
+
end
|
137
186
|
end
|
138
187
|
end
|
139
188
|
end
|