dry-types 0.15.0 → 1.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|