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/coercions.rb
CHANGED
@@ -1,50 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dry
|
2
4
|
module Types
|
5
|
+
# Common coercion functions used by the built-in `Params` and `JSON` types
|
6
|
+
#
|
7
|
+
# @api public
|
3
8
|
module Coercions
|
4
9
|
include Dry::Core::Constants
|
5
10
|
|
6
11
|
# @param [String, Object] input
|
7
|
-
#
|
8
|
-
# @return [
|
9
|
-
|
10
|
-
|
12
|
+
#
|
13
|
+
# @return [nil] if the input is an empty string or nil
|
14
|
+
#
|
15
|
+
# @raise CoercionError
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
def to_nil(input, &_block)
|
19
|
+
if input.nil? || empty_str?(input)
|
20
|
+
nil
|
21
|
+
elsif block_given?
|
22
|
+
yield
|
23
|
+
else
|
24
|
+
raise CoercionError, "#{input.inspect} is not nil"
|
25
|
+
end
|
11
26
|
end
|
12
27
|
|
13
28
|
# @param [#to_str, Object] input
|
29
|
+
#
|
14
30
|
# @return [Date, Object]
|
31
|
+
#
|
15
32
|
# @see Date.parse
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
33
|
+
#
|
34
|
+
# @api public
|
35
|
+
def to_date(input, &block)
|
36
|
+
if input.respond_to?(:to_str)
|
37
|
+
begin
|
38
|
+
::Date.parse(input)
|
39
|
+
rescue ArgumentError, RangeError => e
|
40
|
+
CoercionError.handle(e, &block)
|
41
|
+
end
|
42
|
+
elsif block_given?
|
43
|
+
yield
|
44
|
+
else
|
45
|
+
raise CoercionError, "#{input.inspect} is not a string"
|
46
|
+
end
|
21
47
|
end
|
22
48
|
|
23
49
|
# @param [#to_str, Object] input
|
50
|
+
#
|
24
51
|
# @return [DateTime, Object]
|
52
|
+
#
|
25
53
|
# @see DateTime.parse
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
54
|
+
#
|
55
|
+
# @api public
|
56
|
+
def to_date_time(input, &block)
|
57
|
+
if input.respond_to?(:to_str)
|
58
|
+
begin
|
59
|
+
::DateTime.parse(input)
|
60
|
+
rescue ArgumentError => e
|
61
|
+
CoercionError.handle(e, &block)
|
62
|
+
end
|
63
|
+
elsif block_given?
|
64
|
+
yield
|
65
|
+
else
|
66
|
+
raise CoercionError, "#{input.inspect} is not a string"
|
67
|
+
end
|
31
68
|
end
|
32
69
|
|
33
70
|
# @param [#to_str, Object] input
|
71
|
+
#
|
34
72
|
# @return [Time, Object]
|
73
|
+
#
|
35
74
|
# @see Time.parse
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
75
|
+
#
|
76
|
+
# @api public
|
77
|
+
def to_time(input, &block)
|
78
|
+
if input.respond_to?(:to_str)
|
79
|
+
begin
|
80
|
+
::Time.parse(input)
|
81
|
+
rescue ArgumentError => e
|
82
|
+
CoercionError.handle(e, &block)
|
83
|
+
end
|
84
|
+
elsif block_given?
|
85
|
+
yield
|
86
|
+
else
|
87
|
+
raise CoercionError, "#{input.inspect} is not a string"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# @param [#to_sym, Object] input
|
92
|
+
#
|
93
|
+
# @return [Symbol, Object]
|
94
|
+
#
|
95
|
+
# @raise CoercionError
|
96
|
+
#
|
97
|
+
# @api public
|
98
|
+
def to_symbol(input, &block)
|
99
|
+
input.to_sym
|
100
|
+
rescue NoMethodError => e
|
101
|
+
CoercionError.handle(e, &block)
|
41
102
|
end
|
42
103
|
|
43
104
|
private
|
44
105
|
|
45
106
|
# Checks whether String is empty
|
107
|
+
#
|
46
108
|
# @param [String, Object] value
|
109
|
+
#
|
47
110
|
# @return [Boolean]
|
111
|
+
#
|
112
|
+
# @api private
|
48
113
|
def empty_str?(value)
|
49
114
|
EMPTY_STRING.eql?(value)
|
50
115
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'date'
|
2
4
|
require 'bigdecimal'
|
3
5
|
require 'bigdecimal/util'
|
@@ -6,14 +8,31 @@ require 'time'
|
|
6
8
|
module Dry
|
7
9
|
module Types
|
8
10
|
module Coercions
|
11
|
+
# JSON-specific coercions
|
12
|
+
#
|
13
|
+
# @api public
|
9
14
|
module JSON
|
10
15
|
extend Coercions
|
11
16
|
|
12
17
|
# @param [#to_d, Object] input
|
18
|
+
#
|
13
19
|
# @return [BigDecimal,nil]
|
14
|
-
|
15
|
-
|
16
|
-
|
20
|
+
#
|
21
|
+
# @raise CoercionError
|
22
|
+
#
|
23
|
+
# @api public
|
24
|
+
def self.to_decimal(input, &block)
|
25
|
+
if input.is_a?(::Float)
|
26
|
+
input.to_d
|
27
|
+
else
|
28
|
+
BigDecimal(input)
|
29
|
+
end
|
30
|
+
rescue ArgumentError, TypeError
|
31
|
+
if block_given?
|
32
|
+
yield
|
33
|
+
else
|
34
|
+
raise CoercionError, "#{input} cannot be coerced to decimal"
|
35
|
+
end
|
17
36
|
end
|
18
37
|
end
|
19
38
|
end
|
@@ -1,80 +1,148 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'bigdecimal'
|
2
4
|
require 'bigdecimal/util'
|
3
5
|
|
4
6
|
module Dry
|
5
7
|
module Types
|
6
8
|
module Coercions
|
9
|
+
# Params-specific coercions
|
10
|
+
#
|
11
|
+
# @api public
|
7
12
|
module Params
|
8
13
|
TRUE_VALUES = %w[1 on On ON t true True TRUE T y yes Yes YES Y].freeze
|
9
14
|
FALSE_VALUES = %w[0 off Off OFF f false False FALSE F n no No NO N].freeze
|
10
|
-
BOOLEAN_MAP = ::Hash[
|
15
|
+
BOOLEAN_MAP = ::Hash[
|
16
|
+
TRUE_VALUES.product([true]) + FALSE_VALUES.product([false])
|
17
|
+
].freeze
|
11
18
|
|
12
19
|
extend Coercions
|
13
20
|
|
14
21
|
# @param [String, Object] input
|
22
|
+
#
|
15
23
|
# @return [Boolean,Object]
|
24
|
+
#
|
16
25
|
# @see TRUE_VALUES
|
17
26
|
# @see FALSE_VALUES
|
18
|
-
|
19
|
-
|
27
|
+
#
|
28
|
+
# @raise CoercionError
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
def self.to_true(input, &_block)
|
32
|
+
BOOLEAN_MAP.fetch(input.to_s) do
|
33
|
+
if block_given?
|
34
|
+
yield
|
35
|
+
else
|
36
|
+
raise CoercionError, "#{input} cannot be coerced to true"
|
37
|
+
end
|
38
|
+
end
|
20
39
|
end
|
21
40
|
|
22
41
|
# @param [String, Object] input
|
42
|
+
#
|
23
43
|
# @return [Boolean,Object]
|
44
|
+
#
|
24
45
|
# @see TRUE_VALUES
|
25
46
|
# @see FALSE_VALUES
|
26
|
-
|
27
|
-
|
47
|
+
#
|
48
|
+
# @raise CoercionError
|
49
|
+
#
|
50
|
+
# @api public
|
51
|
+
def self.to_false(input, &_block)
|
52
|
+
BOOLEAN_MAP.fetch(input.to_s) do
|
53
|
+
if block_given?
|
54
|
+
yield
|
55
|
+
else
|
56
|
+
raise CoercionError, "#{input} cannot be coerced to false"
|
57
|
+
end
|
58
|
+
end
|
28
59
|
end
|
29
60
|
|
30
61
|
# @param [#to_int, #to_i, Object] input
|
62
|
+
#
|
31
63
|
# @return [Integer, nil, Object]
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
64
|
+
#
|
65
|
+
# @raise CoercionError
|
66
|
+
#
|
67
|
+
# @api public
|
68
|
+
def self.to_int(input, &block)
|
69
|
+
if input.is_a? String
|
36
70
|
Integer(input, 10)
|
37
71
|
else
|
38
72
|
Integer(input)
|
39
73
|
end
|
40
|
-
rescue ArgumentError, TypeError
|
41
|
-
|
74
|
+
rescue ArgumentError, TypeError => e
|
75
|
+
CoercionError.handle(e, &block)
|
42
76
|
end
|
43
77
|
|
44
78
|
# @param [#to_f, Object] input
|
79
|
+
#
|
45
80
|
# @return [Float, nil, Object]
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
rescue ArgumentError, TypeError
|
53
|
-
|
81
|
+
#
|
82
|
+
# @raise CoercionError
|
83
|
+
#
|
84
|
+
# @api public
|
85
|
+
def self.to_float(input, &block)
|
86
|
+
Float(input)
|
87
|
+
rescue ArgumentError, TypeError => e
|
88
|
+
CoercionError.handle(e, &block)
|
54
89
|
end
|
55
90
|
|
56
91
|
# @param [#to_d, Object] input
|
92
|
+
#
|
57
93
|
# @return [BigDecimal, nil, Object]
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
94
|
+
#
|
95
|
+
# @raise CoercionError
|
96
|
+
#
|
97
|
+
# @api public
|
98
|
+
def self.to_decimal(input, &block)
|
99
|
+
to_float(input) do
|
100
|
+
if block_given?
|
101
|
+
return yield
|
102
|
+
else
|
103
|
+
raise CoercionError, "#{input.inspect} cannot be coerced to decimal"
|
104
|
+
end
|
65
105
|
end
|
106
|
+
|
107
|
+
input.to_d
|
66
108
|
end
|
67
109
|
|
68
110
|
# @param [Array, String, Object] input
|
111
|
+
#
|
69
112
|
# @return [Array, Object]
|
70
|
-
|
71
|
-
|
113
|
+
#
|
114
|
+
# @raise CoercionError
|
115
|
+
#
|
116
|
+
# @api public
|
117
|
+
def self.to_ary(input, &_block)
|
118
|
+
if empty_str?(input)
|
119
|
+
[]
|
120
|
+
elsif input.is_a?(::Array)
|
121
|
+
input
|
122
|
+
elsif block_given?
|
123
|
+
yield
|
124
|
+
else
|
125
|
+
raise CoercionError, "#{input.inspect} cannot be coerced to array"
|
126
|
+
end
|
72
127
|
end
|
73
128
|
|
74
129
|
# @param [Hash, String, Object] input
|
130
|
+
#
|
75
131
|
# @return [Hash, Object]
|
76
|
-
|
77
|
-
|
132
|
+
#
|
133
|
+
# @raise CoercionError
|
134
|
+
#
|
135
|
+
# @api public
|
136
|
+
def self.to_hash(input, &_block)
|
137
|
+
if empty_str?(input)
|
138
|
+
{}
|
139
|
+
elsif input.is_a?(::Hash)
|
140
|
+
input
|
141
|
+
elsif block_given?
|
142
|
+
yield
|
143
|
+
else
|
144
|
+
raise CoercionError, "#{input.inspect} cannot be coerced to hash"
|
145
|
+
end
|
78
146
|
end
|
79
147
|
end
|
80
148
|
end
|
data/lib/dry/types/compiler.rb
CHANGED
@@ -1,6 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/core/deprecations'
|
4
|
+
|
1
5
|
module Dry
|
2
6
|
module Types
|
7
|
+
# @api private
|
3
8
|
class Compiler
|
9
|
+
extend ::Dry::Core::Deprecations[:'dry-types']
|
10
|
+
|
4
11
|
attr_reader :registry
|
5
12
|
|
6
13
|
def initialize(registry)
|
@@ -13,29 +20,29 @@ module Dry
|
|
13
20
|
|
14
21
|
def visit(node)
|
15
22
|
type, body = node
|
16
|
-
send(:"visit_#{
|
23
|
+
send(:"visit_#{type}", body)
|
17
24
|
end
|
18
25
|
|
19
26
|
def visit_constrained(node)
|
20
|
-
nominal, rule
|
21
|
-
|
27
|
+
nominal, rule = node
|
28
|
+
type = visit(nominal)
|
29
|
+
type.constrained_type.new(type, rule: visit_rule(rule))
|
22
30
|
end
|
23
31
|
|
24
32
|
def visit_constructor(node)
|
25
|
-
nominal,
|
26
|
-
fn = Dry::Types::FnContainer[fn_register_name]
|
33
|
+
nominal, fn = node
|
27
34
|
primitive = visit(nominal)
|
28
|
-
|
35
|
+
primitive.constructor(compile_fn(fn))
|
29
36
|
end
|
30
37
|
|
31
|
-
def
|
32
|
-
|
33
|
-
Types::Safe.new(visit(ast), meta: meta)
|
38
|
+
def visit_lax(node)
|
39
|
+
Types::Lax.new(visit(node))
|
34
40
|
end
|
41
|
+
deprecate(:visit_safe, :visit_lax)
|
35
42
|
|
36
43
|
def visit_nominal(node)
|
37
44
|
type, meta = node
|
38
|
-
nominal_name = "nominal.#{
|
45
|
+
nominal_name = "nominal.#{Types.identifier(type)}"
|
39
46
|
|
40
47
|
if registry.registered?(nominal_name)
|
41
48
|
registry[nominal_name].meta(meta)
|
@@ -95,8 +102,8 @@ module Dry
|
|
95
102
|
end
|
96
103
|
|
97
104
|
def visit_enum(node)
|
98
|
-
type, mapping
|
99
|
-
Enum.new(visit(type), mapping: mapping
|
105
|
+
type, mapping = node
|
106
|
+
Enum.new(visit(type), mapping: mapping)
|
100
107
|
end
|
101
108
|
|
102
109
|
def visit_map(node)
|
@@ -107,6 +114,22 @@ module Dry
|
|
107
114
|
def visit_any(meta)
|
108
115
|
registry['any'].meta(meta)
|
109
116
|
end
|
117
|
+
|
118
|
+
def compile_fn(fn)
|
119
|
+
type, *node = fn
|
120
|
+
|
121
|
+
case type
|
122
|
+
when :id
|
123
|
+
Dry::Types::FnContainer[node.fetch(0)]
|
124
|
+
when :callable
|
125
|
+
node.fetch(0)
|
126
|
+
when :method
|
127
|
+
target, method = node
|
128
|
+
target.method(method)
|
129
|
+
else
|
130
|
+
raise ArgumentError, "Cannot build callable from #{fn.inspect}"
|
131
|
+
end
|
132
|
+
end
|
110
133
|
end
|
111
134
|
end
|
112
135
|
end
|
@@ -1,94 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'dry/types/decorator'
|
2
4
|
require 'dry/types/constraints'
|
3
5
|
require 'dry/types/constrained/coercible'
|
4
6
|
|
5
7
|
module Dry
|
6
8
|
module Types
|
9
|
+
# Constrained types apply rules to the input
|
10
|
+
#
|
11
|
+
# @api public
|
7
12
|
class Constrained
|
8
13
|
include Type
|
9
14
|
include Decorator
|
10
15
|
include Builder
|
11
16
|
include Printable
|
12
|
-
include Dry::Equalizer(:type, :
|
17
|
+
include Dry::Equalizer(:type, :rule, inspect: false)
|
13
18
|
|
14
19
|
# @return [Dry::Logic::Rule]
|
15
20
|
attr_reader :rule
|
16
21
|
|
17
22
|
# @param [Type] type
|
23
|
+
#
|
18
24
|
# @param [Hash] options
|
25
|
+
#
|
26
|
+
# @api public
|
19
27
|
def initialize(type, options)
|
20
28
|
super
|
21
29
|
@rule = options.fetch(:rule)
|
22
30
|
end
|
23
31
|
|
24
|
-
# @
|
32
|
+
# @api private
|
33
|
+
#
|
25
34
|
# @return [Object]
|
26
|
-
#
|
27
|
-
|
28
|
-
|
35
|
+
#
|
36
|
+
# @api public
|
37
|
+
def call_unsafe(input)
|
38
|
+
result = rule.(input)
|
39
|
+
|
40
|
+
if result.success?
|
41
|
+
type.call_unsafe(input)
|
42
|
+
else
|
29
43
|
raise ConstraintError.new(result, input)
|
30
|
-
|
44
|
+
end
|
31
45
|
end
|
32
|
-
|
33
|
-
|
34
|
-
#
|
35
|
-
# @
|
36
|
-
#
|
37
|
-
# @
|
38
|
-
|
39
|
-
|
46
|
+
|
47
|
+
# @api private
|
48
|
+
#
|
49
|
+
# @return [Object]
|
50
|
+
#
|
51
|
+
# @api public
|
52
|
+
def call_safe(input, &block)
|
53
|
+
if rule[input]
|
54
|
+
type.call_safe(input, &block)
|
55
|
+
else
|
56
|
+
yield
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Safe coercion attempt. It is similar to #call with a
|
61
|
+
# block given but returns a Result instance with metadata
|
62
|
+
# about errors (if any).
|
63
|
+
#
|
64
|
+
# @overload try(input)
|
65
|
+
# @param [Object] input
|
66
|
+
# @return [Logic::Result]
|
67
|
+
#
|
68
|
+
# @overload try(input)
|
69
|
+
# @param [Object] input
|
70
|
+
# @yieldparam [Failure] failure
|
71
|
+
# @yieldreturn [Object]
|
72
|
+
# @return [Object]
|
73
|
+
#
|
74
|
+
# @api public
|
40
75
|
def try(input, &block)
|
41
76
|
result = rule.(input)
|
42
77
|
|
43
78
|
if result.success?
|
44
79
|
type.try(input, &block)
|
45
80
|
else
|
46
|
-
failure = failure(input, result)
|
47
|
-
|
81
|
+
failure = failure(input, ConstraintError.new(result, input))
|
82
|
+
block_given? ? yield(failure) : failure
|
48
83
|
end
|
49
84
|
end
|
50
85
|
|
51
|
-
# @param [Object] value
|
52
|
-
# @return [Boolean]
|
53
|
-
def valid?(value)
|
54
|
-
rule.(value).success? && type.valid?(value)
|
55
|
-
end
|
56
|
-
|
57
86
|
# @param [Hash] options
|
58
87
|
# The options hash provided to {Types.Rule} and combined
|
59
88
|
# using {&} with previous {#rule}
|
89
|
+
#
|
60
90
|
# @return [Constrained]
|
91
|
+
#
|
61
92
|
# @see Dry::Logic::Operators#and
|
93
|
+
#
|
94
|
+
# @api public
|
62
95
|
def constrained(options)
|
63
96
|
with(rule: rule & Types.Rule(options))
|
64
97
|
end
|
65
98
|
|
66
99
|
# @return [true]
|
100
|
+
#
|
101
|
+
# @api public
|
67
102
|
def constrained?
|
68
103
|
true
|
69
104
|
end
|
70
105
|
|
71
106
|
# @param [Object] value
|
107
|
+
#
|
72
108
|
# @return [Boolean]
|
109
|
+
#
|
110
|
+
# @api public
|
73
111
|
def ===(value)
|
74
112
|
valid?(value)
|
75
113
|
end
|
76
114
|
|
77
|
-
#
|
115
|
+
# Build lax type. Constraints are not applicable to lax types hence unwrapping
|
78
116
|
#
|
117
|
+
# @return [Lax]
|
118
|
+
# @api public
|
119
|
+
def lax
|
120
|
+
type.lax
|
121
|
+
end
|
122
|
+
|
79
123
|
# @see Nominal#to_ast
|
124
|
+
# @api public
|
80
125
|
def to_ast(meta: true)
|
81
|
-
[:constrained, [type.to_ast(meta: meta),
|
82
|
-
|
83
|
-
|
126
|
+
[:constrained, [type.to_ast(meta: meta), rule.to_ast]]
|
127
|
+
end
|
128
|
+
|
129
|
+
# @api private
|
130
|
+
def constructor_type
|
131
|
+
type.constructor_type
|
84
132
|
end
|
85
133
|
|
86
134
|
private
|
87
135
|
|
88
136
|
# @param [Object] response
|
137
|
+
#
|
89
138
|
# @return [Boolean]
|
139
|
+
#
|
140
|
+
# @api private
|
90
141
|
def decorate?(response)
|
91
|
-
super || response.
|
142
|
+
super || response.is_a?(Constructor)
|
92
143
|
end
|
93
144
|
end
|
94
145
|
end
|