dry-types 0.15.0 → 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 +547 -161
- data/LICENSE +17 -17
- data/README.md +15 -13
- data/dry-types.gemspec +27 -30
- data/lib/dry/types/any.rb +23 -12
- data/lib/dry/types/array/constructor.rb +32 -0
- data/lib/dry/types/array/member.rb +74 -15
- data/lib/dry/types/array.rb +18 -2
- data/lib/dry/types/builder.rb +118 -22
- data/lib/dry/types/builder_methods.rb +46 -16
- data/lib/dry/types/coercions/json.rb +43 -7
- data/lib/dry/types/coercions/params.rb +117 -32
- data/lib/dry/types/coercions.rb +76 -22
- data/lib/dry/types/compiler.rb +44 -21
- data/lib/dry/types/constrained/coercible.rb +36 -6
- data/lib/dry/types/constrained.rb +79 -31
- 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 +110 -61
- data/lib/dry/types/container.rb +6 -1
- data/lib/dry/types/core.rb +34 -11
- data/lib/dry/types/decorator.rb +38 -17
- data/lib/dry/types/default.rb +61 -16
- data/lib/dry/types/enum.rb +36 -20
- data/lib/dry/types/errors.rb +74 -8
- data/lib/dry/types/extensions/maybe.rb +65 -17
- 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 +17 -4
- data/lib/dry/types/hash.rb +32 -20
- 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 +70 -32
- data/lib/dry/types/meta.rb +51 -0
- data/lib/dry/types/module.rb +16 -11
- data/lib/dry/types/nominal.rb +113 -22
- data/lib/dry/types/options.rb +12 -25
- 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 +5 -1
- data/lib/dry/types/printer.rb +63 -57
- data/lib/dry/types/result.rb +29 -3
- data/lib/dry/types/schema/key.rb +62 -36
- data/lib/dry/types/schema.rb +201 -91
- data/lib/dry/types/spec/types.rb +99 -37
- data/lib/dry/types/sum.rb +75 -25
- data/lib/dry/types/type.rb +49 -0
- data/lib/dry/types/version.rb +3 -1
- data/lib/dry/types.rb +106 -48
- data/lib/dry-types.rb +3 -1
- metadata +55 -78
- data/.codeclimate.yml +0 -15
- data/.gitignore +0 -10
- data/.rspec +0 -2
- data/.rubocop.yml +0 -43
- data/.travis.yml +0 -28
- data/.yardopts +0 -5
- data/CONTRIBUTING.md +0 -29
- data/Gemfile +0 -23
- data/Rakefile +0 -20
- data/benchmarks/hash_schemas.rb +0 -51
- data/lib/dry/types/safe.rb +0 -61
- data/log/.gitkeep +0 -0
@@ -1,5 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dry
|
2
4
|
module Types
|
5
|
+
# Common API for building type objects in a convenient way
|
6
|
+
#
|
7
|
+
#
|
8
|
+
# @api public
|
3
9
|
module BuilderMethods
|
4
10
|
# @api private
|
5
11
|
def included(base)
|
@@ -8,7 +14,8 @@ module Dry
|
|
8
14
|
end
|
9
15
|
|
10
16
|
# Build an array type.
|
11
|
-
#
|
17
|
+
#
|
18
|
+
# Shortcut for Array#of.
|
12
19
|
#
|
13
20
|
# @example
|
14
21
|
# Types::Strings = Types.Array(Types::String)
|
@@ -17,7 +24,7 @@ module Dry
|
|
17
24
|
#
|
18
25
|
# @return [Dry::Types::Array]
|
19
26
|
def Array(type)
|
20
|
-
|
27
|
+
Strict(::Array).of(type)
|
21
28
|
end
|
22
29
|
|
23
30
|
# Build a hash schema
|
@@ -25,9 +32,8 @@ module Dry
|
|
25
32
|
# @param [Hash{Symbol => Dry::Types::Type}] type_map
|
26
33
|
#
|
27
34
|
# @return [Dry::Types::Array]
|
28
|
-
# @api public
|
29
35
|
def Hash(type_map)
|
30
|
-
|
36
|
+
Strict(::Hash).schema(type_map)
|
31
37
|
end
|
32
38
|
|
33
39
|
# Build a type which values are instances of a given class
|
@@ -41,9 +47,8 @@ module Dry
|
|
41
47
|
# @param [Class,Module] klass Class or module
|
42
48
|
#
|
43
49
|
# @return [Dry::Types::Type]
|
44
|
-
# @api public
|
45
50
|
def Instance(klass)
|
46
|
-
Nominal
|
51
|
+
Nominal(klass).constrained(type: klass)
|
47
52
|
end
|
48
53
|
alias_method :Strict, :Instance
|
49
54
|
|
@@ -53,9 +58,8 @@ module Dry
|
|
53
58
|
# @param [Object] value
|
54
59
|
#
|
55
60
|
# @return [Dry::Types::Type]
|
56
|
-
# @api public
|
57
61
|
def Value(value)
|
58
|
-
Nominal
|
62
|
+
Nominal(value.class).constrained(eql: value)
|
59
63
|
end
|
60
64
|
|
61
65
|
# Build a type with a single value
|
@@ -64,9 +68,8 @@ module Dry
|
|
64
68
|
# @param [Object] object
|
65
69
|
#
|
66
70
|
# @return [Dry::Types::Type]
|
67
|
-
# @api public
|
68
71
|
def Constant(object)
|
69
|
-
Nominal
|
72
|
+
Nominal(object.class).constrained(is: object)
|
70
73
|
end
|
71
74
|
|
72
75
|
# Build a constructor type
|
@@ -77,9 +80,16 @@ module Dry
|
|
77
80
|
# @param [#call,nil] block Value constructor
|
78
81
|
#
|
79
82
|
# @return [Dry::Types::Type]
|
80
|
-
# @api public
|
81
83
|
def Constructor(klass, cons = nil, &block)
|
82
|
-
|
84
|
+
if klass.is_a?(Type)
|
85
|
+
if cons || block
|
86
|
+
klass.constructor(cons || block)
|
87
|
+
else
|
88
|
+
klass
|
89
|
+
end
|
90
|
+
else
|
91
|
+
Nominal(klass).constructor(cons || block || klass.method(:new))
|
92
|
+
end
|
83
93
|
end
|
84
94
|
|
85
95
|
# Build a nominal type
|
@@ -87,9 +97,14 @@ module Dry
|
|
87
97
|
# @param [Class] klass
|
88
98
|
#
|
89
99
|
# @return [Dry::Types::Type]
|
90
|
-
# @api public
|
91
100
|
def Nominal(klass)
|
92
|
-
|
101
|
+
if klass <= ::Array
|
102
|
+
Array.new(klass)
|
103
|
+
elsif klass <= ::Hash
|
104
|
+
Hash.new(klass)
|
105
|
+
else
|
106
|
+
Nominal.new(klass)
|
107
|
+
end
|
93
108
|
end
|
94
109
|
|
95
110
|
# Build a map type
|
@@ -102,9 +117,24 @@ module Dry
|
|
102
117
|
# @param [Type] value_type Value type
|
103
118
|
#
|
104
119
|
# @return [Dry::Types::Map]
|
105
|
-
# @api public
|
106
120
|
def Map(key_type, value_type)
|
107
|
-
|
121
|
+
Nominal(::Hash).map(key_type, value_type)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Builds a constrained nominal type accepting any value that
|
125
|
+
# responds to given methods
|
126
|
+
#
|
127
|
+
# @example
|
128
|
+
# Types::Callable = Types.Interface(:call)
|
129
|
+
# Types::Contact = Types.Interface(:name, :address)
|
130
|
+
#
|
131
|
+
# @param methods [Array<String, Symbol>] Method names
|
132
|
+
#
|
133
|
+
# @return [Dry::Types::Contrained]
|
134
|
+
def Interface(*methods)
|
135
|
+
methods.reduce(Types["nominal.any"]) do |type, method|
|
136
|
+
type.constrained(respond_to: method)
|
137
|
+
end
|
108
138
|
end
|
109
139
|
end
|
110
140
|
end
|
@@ -1,19 +1,55 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
require "bigdecimal"
|
5
|
+
require "bigdecimal/util"
|
6
|
+
require "time"
|
5
7
|
|
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
|
|
17
|
+
# @param [Object] input
|
18
|
+
#
|
19
|
+
# @return [nil] if the input is nil
|
20
|
+
#
|
21
|
+
# @raise CoercionError
|
22
|
+
#
|
23
|
+
# @api public
|
24
|
+
def self.to_nil(input, &_block)
|
25
|
+
if input.nil?
|
26
|
+
nil
|
27
|
+
elsif block_given?
|
28
|
+
yield
|
29
|
+
else
|
30
|
+
raise CoercionError, "#{input.inspect} is not nil"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
12
34
|
# @param [#to_d, Object] input
|
35
|
+
#
|
13
36
|
# @return [BigDecimal,nil]
|
14
|
-
|
15
|
-
|
16
|
-
|
37
|
+
#
|
38
|
+
# @raise CoercionError
|
39
|
+
#
|
40
|
+
# @api public
|
41
|
+
def self.to_decimal(input, &_block)
|
42
|
+
if input.is_a?(::Float)
|
43
|
+
input.to_d
|
44
|
+
else
|
45
|
+
BigDecimal(input)
|
46
|
+
end
|
47
|
+
rescue ArgumentError, TypeError
|
48
|
+
if block_given?
|
49
|
+
yield
|
50
|
+
else
|
51
|
+
raise CoercionError, "#{input} cannot be coerced to decimal"
|
52
|
+
end
|
17
53
|
end
|
18
54
|
end
|
19
55
|
end
|
@@ -1,80 +1,165 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bigdecimal"
|
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
|
+
].merge(true => true, false => false).freeze
|
11
18
|
|
12
19
|
extend Coercions
|
13
20
|
|
21
|
+
# @param [Object] input
|
22
|
+
#
|
23
|
+
# @return [nil] if the input is an empty string or nil
|
24
|
+
#
|
25
|
+
# @raise CoercionError
|
26
|
+
#
|
27
|
+
# @api public
|
28
|
+
def self.to_nil(input, &_block)
|
29
|
+
if input.nil? || empty_str?(input)
|
30
|
+
nil
|
31
|
+
elsif block_given?
|
32
|
+
yield
|
33
|
+
else
|
34
|
+
raise CoercionError, "#{input.inspect} is not nil"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
14
38
|
# @param [String, Object] input
|
39
|
+
#
|
15
40
|
# @return [Boolean,Object]
|
41
|
+
#
|
16
42
|
# @see TRUE_VALUES
|
17
43
|
# @see FALSE_VALUES
|
18
|
-
|
19
|
-
|
44
|
+
#
|
45
|
+
# @raise CoercionError
|
46
|
+
#
|
47
|
+
# @api public
|
48
|
+
def self.to_true(input, &_block)
|
49
|
+
BOOLEAN_MAP.fetch(input.to_s) do
|
50
|
+
if block_given?
|
51
|
+
yield
|
52
|
+
else
|
53
|
+
raise CoercionError, "#{input} cannot be coerced to true"
|
54
|
+
end
|
55
|
+
end
|
20
56
|
end
|
21
57
|
|
22
58
|
# @param [String, Object] input
|
59
|
+
#
|
23
60
|
# @return [Boolean,Object]
|
61
|
+
#
|
24
62
|
# @see TRUE_VALUES
|
25
63
|
# @see FALSE_VALUES
|
26
|
-
|
27
|
-
|
64
|
+
#
|
65
|
+
# @raise CoercionError
|
66
|
+
#
|
67
|
+
# @api public
|
68
|
+
def self.to_false(input, &_block)
|
69
|
+
BOOLEAN_MAP.fetch(input.to_s) do
|
70
|
+
if block_given?
|
71
|
+
yield
|
72
|
+
else
|
73
|
+
raise CoercionError, "#{input} cannot be coerced to false"
|
74
|
+
end
|
75
|
+
end
|
28
76
|
end
|
29
77
|
|
30
78
|
# @param [#to_int, #to_i, Object] input
|
79
|
+
#
|
31
80
|
# @return [Integer, nil, Object]
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
81
|
+
#
|
82
|
+
# @raise CoercionError
|
83
|
+
#
|
84
|
+
# @api public
|
85
|
+
def self.to_int(input, &block)
|
86
|
+
if input.is_a? String
|
36
87
|
Integer(input, 10)
|
37
88
|
else
|
38
89
|
Integer(input)
|
39
90
|
end
|
40
|
-
rescue ArgumentError, TypeError
|
41
|
-
|
91
|
+
rescue ArgumentError, TypeError => e
|
92
|
+
CoercionError.handle(e, &block)
|
42
93
|
end
|
43
94
|
|
44
95
|
# @param [#to_f, Object] input
|
96
|
+
#
|
45
97
|
# @return [Float, nil, Object]
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
rescue ArgumentError, TypeError
|
53
|
-
|
98
|
+
#
|
99
|
+
# @raise CoercionError
|
100
|
+
#
|
101
|
+
# @api public
|
102
|
+
def self.to_float(input, &block)
|
103
|
+
Float(input)
|
104
|
+
rescue ArgumentError, TypeError => e
|
105
|
+
CoercionError.handle(e, &block)
|
54
106
|
end
|
55
107
|
|
56
108
|
# @param [#to_d, Object] input
|
109
|
+
#
|
57
110
|
# @return [BigDecimal, nil, Object]
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
111
|
+
#
|
112
|
+
# @raise CoercionError
|
113
|
+
#
|
114
|
+
# @api public
|
115
|
+
def self.to_decimal(input, &_block)
|
116
|
+
to_float(input) do
|
117
|
+
if block_given?
|
118
|
+
return yield
|
119
|
+
else
|
120
|
+
raise CoercionError, "#{input.inspect} cannot be coerced to decimal"
|
121
|
+
end
|
65
122
|
end
|
123
|
+
|
124
|
+
input.to_d
|
66
125
|
end
|
67
126
|
|
68
127
|
# @param [Array, String, Object] input
|
128
|
+
#
|
69
129
|
# @return [Array, Object]
|
70
|
-
|
71
|
-
|
130
|
+
#
|
131
|
+
# @raise CoercionError
|
132
|
+
#
|
133
|
+
# @api public
|
134
|
+
def self.to_ary(input, &_block)
|
135
|
+
if empty_str?(input)
|
136
|
+
[]
|
137
|
+
elsif input.is_a?(::Array)
|
138
|
+
input
|
139
|
+
elsif block_given?
|
140
|
+
yield
|
141
|
+
else
|
142
|
+
raise CoercionError, "#{input.inspect} cannot be coerced to array"
|
143
|
+
end
|
72
144
|
end
|
73
145
|
|
74
146
|
# @param [Hash, String, Object] input
|
147
|
+
#
|
75
148
|
# @return [Hash, Object]
|
76
|
-
|
77
|
-
|
149
|
+
#
|
150
|
+
# @raise CoercionError
|
151
|
+
#
|
152
|
+
# @api public
|
153
|
+
def self.to_hash(input, &_block)
|
154
|
+
if empty_str?(input)
|
155
|
+
{}
|
156
|
+
elsif input.is_a?(::Hash)
|
157
|
+
input
|
158
|
+
elsif block_given?
|
159
|
+
yield
|
160
|
+
else
|
161
|
+
raise CoercionError, "#{input.inspect} cannot be coerced to hash"
|
162
|
+
end
|
78
163
|
end
|
79
164
|
end
|
80
165
|
end
|
data/lib/dry/types/coercions.rb
CHANGED
@@ -1,50 +1,104 @@
|
|
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
|
-
# @param [String, Object] input
|
7
|
-
# @return [nil] if the input is an empty string
|
8
|
-
# @return [Object] otherwise the input object is returned
|
9
|
-
def to_nil(input)
|
10
|
-
input unless empty_str?(input)
|
11
|
-
end
|
12
|
-
|
13
11
|
# @param [#to_str, Object] input
|
12
|
+
#
|
14
13
|
# @return [Date, Object]
|
14
|
+
#
|
15
15
|
# @see Date.parse
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
def to_date(input, &block)
|
19
|
+
if input.respond_to?(:to_str)
|
20
|
+
begin
|
21
|
+
::Date.parse(input)
|
22
|
+
rescue ArgumentError, RangeError => e
|
23
|
+
CoercionError.handle(e, &block)
|
24
|
+
end
|
25
|
+
elsif input.is_a?(::Date)
|
26
|
+
input
|
27
|
+
elsif block_given?
|
28
|
+
yield
|
29
|
+
else
|
30
|
+
raise CoercionError, "#{input.inspect} is not a string"
|
31
|
+
end
|
21
32
|
end
|
22
33
|
|
23
34
|
# @param [#to_str, Object] input
|
35
|
+
#
|
24
36
|
# @return [DateTime, Object]
|
37
|
+
#
|
25
38
|
# @see DateTime.parse
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
39
|
+
#
|
40
|
+
# @api public
|
41
|
+
def to_date_time(input, &block)
|
42
|
+
if input.respond_to?(:to_str)
|
43
|
+
begin
|
44
|
+
::DateTime.parse(input)
|
45
|
+
rescue ArgumentError => e
|
46
|
+
CoercionError.handle(e, &block)
|
47
|
+
end
|
48
|
+
elsif input.is_a?(::DateTime)
|
49
|
+
input
|
50
|
+
elsif block_given?
|
51
|
+
yield
|
52
|
+
else
|
53
|
+
raise CoercionError, "#{input.inspect} is not a string"
|
54
|
+
end
|
31
55
|
end
|
32
56
|
|
33
57
|
# @param [#to_str, Object] input
|
58
|
+
#
|
34
59
|
# @return [Time, Object]
|
60
|
+
#
|
35
61
|
# @see Time.parse
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
62
|
+
#
|
63
|
+
# @api public
|
64
|
+
def to_time(input, &block)
|
65
|
+
if input.respond_to?(:to_str)
|
66
|
+
begin
|
67
|
+
::Time.parse(input)
|
68
|
+
rescue ArgumentError => e
|
69
|
+
CoercionError.handle(e, &block)
|
70
|
+
end
|
71
|
+
elsif input.is_a?(::Time)
|
72
|
+
input
|
73
|
+
elsif block_given?
|
74
|
+
yield
|
75
|
+
else
|
76
|
+
raise CoercionError, "#{input.inspect} is not a string"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# @param [#to_sym, Object] input
|
81
|
+
#
|
82
|
+
# @return [Symbol, Object]
|
83
|
+
#
|
84
|
+
# @raise CoercionError
|
85
|
+
#
|
86
|
+
# @api public
|
87
|
+
def to_symbol(input, &block)
|
88
|
+
input.to_sym
|
89
|
+
rescue NoMethodError => e
|
90
|
+
CoercionError.handle(e, &block)
|
41
91
|
end
|
42
92
|
|
43
93
|
private
|
44
94
|
|
45
95
|
# Checks whether String is empty
|
96
|
+
#
|
46
97
|
# @param [String, Object] value
|
98
|
+
#
|
47
99
|
# @return [Boolean]
|
100
|
+
#
|
101
|
+
# @api private
|
48
102
|
def empty_str?(value)
|
49
103
|
EMPTY_STRING.eql?(value)
|
50
104
|
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)
|
@@ -56,37 +63,37 @@ module Dry
|
|
56
63
|
def visit_array(node)
|
57
64
|
member, meta = node
|
58
65
|
member = member.is_a?(Class) ? member : visit(member)
|
59
|
-
registry[
|
66
|
+
registry["nominal.array"].of(member).meta(meta)
|
60
67
|
end
|
61
68
|
|
62
69
|
def visit_hash(node)
|
63
70
|
opts, meta = node
|
64
|
-
registry[
|
71
|
+
registry["nominal.hash"].with(**opts, meta: meta)
|
65
72
|
end
|
66
73
|
|
67
74
|
def visit_schema(node)
|
68
75
|
keys, options, meta = node
|
69
|
-
registry[
|
76
|
+
registry["nominal.hash"].schema(keys.map { |key| visit(key) }).with(**options, meta: meta)
|
70
77
|
end
|
71
78
|
|
72
79
|
def visit_json_hash(node)
|
73
80
|
keys, meta = node
|
74
|
-
registry[
|
81
|
+
registry["json.hash"].schema(keys.map { |key| visit(key) }, meta)
|
75
82
|
end
|
76
83
|
|
77
84
|
def visit_json_array(node)
|
78
85
|
member, meta = node
|
79
|
-
registry[
|
86
|
+
registry["json.array"].of(visit(member)).meta(meta)
|
80
87
|
end
|
81
88
|
|
82
89
|
def visit_params_hash(node)
|
83
90
|
keys, meta = node
|
84
|
-
registry[
|
91
|
+
registry["params.hash"].schema(keys.map { |key| visit(key) }, meta)
|
85
92
|
end
|
86
93
|
|
87
94
|
def visit_params_array(node)
|
88
95
|
member, meta = node
|
89
|
-
registry[
|
96
|
+
registry["params.array"].of(visit(member)).meta(meta)
|
90
97
|
end
|
91
98
|
|
92
99
|
def visit_key(node)
|
@@ -95,17 +102,33 @@ 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)
|
103
110
|
key_type, value_type, meta = node
|
104
|
-
registry[
|
111
|
+
registry["nominal.hash"].map(visit(key_type), visit(value_type)).meta(meta)
|
105
112
|
end
|
106
113
|
|
107
114
|
def visit_any(meta)
|
108
|
-
registry[
|
115
|
+
registry["any"].meta(meta)
|
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
|
109
132
|
end
|
110
133
|
end
|
111
134
|
end
|