dry-types 0.15.0 → 1.2.0
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/.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
|