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/options.rb
CHANGED
@@ -1,42 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dry
|
2
4
|
module Types
|
5
|
+
# Common API for types with options
|
6
|
+
#
|
7
|
+
# @api private
|
3
8
|
module Options
|
4
9
|
# @return [Hash]
|
5
10
|
attr_reader :options
|
6
11
|
|
7
12
|
# @see Nominal#initialize
|
8
|
-
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
def initialize(*args, **options)
|
9
16
|
@__args__ = args.freeze
|
10
17
|
@options = options.freeze
|
11
|
-
@meta = meta.freeze
|
12
18
|
end
|
13
19
|
|
14
20
|
# @param [Hash] new_options
|
21
|
+
#
|
15
22
|
# @return [Type]
|
16
|
-
def with(**new_options)
|
17
|
-
self.class.new(*@__args__, **options, meta: @meta, **new_options)
|
18
|
-
end
|
19
|
-
|
20
|
-
# @overload meta
|
21
|
-
# @return [Hash] metadata associated with type
|
22
23
|
#
|
23
|
-
# @
|
24
|
-
|
25
|
-
|
26
|
-
def meta(data = nil)
|
27
|
-
if !data
|
28
|
-
@meta
|
29
|
-
elsif data.empty?
|
30
|
-
self
|
31
|
-
else
|
32
|
-
with(meta: @meta.merge(data))
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# Resets meta
|
37
|
-
# @return [Dry::Types::Type]
|
38
|
-
def pristine
|
39
|
-
with(meta: EMPTY_HASH)
|
24
|
+
# @api private
|
25
|
+
def with(**new_options)
|
26
|
+
self.class.new(*@__args__, **options, **new_options)
|
40
27
|
end
|
41
28
|
end
|
42
29
|
end
|
data/lib/dry/types/params.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'dry/types/coercions/params'
|
2
4
|
|
3
5
|
module Dry
|
@@ -27,7 +29,7 @@ module Dry
|
|
27
29
|
end
|
28
30
|
|
29
31
|
register('params.bool') do
|
30
|
-
|
32
|
+
self['params.true'] | self['params.false']
|
31
33
|
end
|
32
34
|
|
33
35
|
register('params.integer') do
|
@@ -43,11 +45,20 @@ module Dry
|
|
43
45
|
end
|
44
46
|
|
45
47
|
register('params.array') do
|
46
|
-
self['nominal.array'].constructor(Coercions::Params.method(:to_ary))
|
48
|
+
self['nominal.array'].constructor(Coercions::Params.method(:to_ary))
|
47
49
|
end
|
48
50
|
|
49
51
|
register('params.hash') do
|
50
|
-
self['nominal.hash'].constructor(Coercions::Params.method(:to_hash))
|
52
|
+
self['nominal.hash'].constructor(Coercions::Params.method(:to_hash))
|
53
|
+
end
|
54
|
+
|
55
|
+
register('params.symbol') do
|
56
|
+
self['nominal.symbol'].constructor(Coercions::Params.method(:to_symbol))
|
57
|
+
end
|
58
|
+
|
59
|
+
COERCIBLE.each_key do |name|
|
60
|
+
next if name.equal?(:string)
|
61
|
+
register("optional.params.#{name}", self['params.nil'] | self["params.#{name}"])
|
51
62
|
end
|
52
63
|
end
|
53
64
|
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/core/cache'
|
4
|
+
require 'dry/types/predicate_registry'
|
5
|
+
|
6
|
+
module Dry
|
7
|
+
module Types
|
8
|
+
# PredicateInferrer returns the list of predicates used by a type.
|
9
|
+
#
|
10
|
+
# @api public
|
11
|
+
class PredicateInferrer
|
12
|
+
extend Core::Cache
|
13
|
+
|
14
|
+
TYPE_TO_PREDICATE = {
|
15
|
+
DateTime => :date_time?,
|
16
|
+
FalseClass => :false?,
|
17
|
+
Integer => :int?,
|
18
|
+
NilClass => :nil?,
|
19
|
+
String => :str?,
|
20
|
+
TrueClass => :true?,
|
21
|
+
BigDecimal => :decimal?
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
REDUCED_TYPES = {
|
25
|
+
[[[:true?], [:false?]]] => %i[bool?]
|
26
|
+
}.freeze
|
27
|
+
|
28
|
+
HASH = %i[hash?].freeze
|
29
|
+
|
30
|
+
ARRAY = %i[array?].freeze
|
31
|
+
|
32
|
+
NIL = %i[nil?].freeze
|
33
|
+
|
34
|
+
# Compiler reduces type AST into a list of predicates
|
35
|
+
#
|
36
|
+
# @api private
|
37
|
+
class Compiler
|
38
|
+
# @return [PredicateRegistry]
|
39
|
+
# @api private
|
40
|
+
attr_reader :registry
|
41
|
+
|
42
|
+
# @api private
|
43
|
+
def initialize(registry)
|
44
|
+
@registry = registry
|
45
|
+
end
|
46
|
+
|
47
|
+
# @api private
|
48
|
+
def infer_predicate(type)
|
49
|
+
[TYPE_TO_PREDICATE.fetch(type) { :"#{type.name.split('::').last.downcase}?" }]
|
50
|
+
end
|
51
|
+
|
52
|
+
# @api private
|
53
|
+
def visit(node)
|
54
|
+
meth, rest = node
|
55
|
+
public_send(:"visit_#{meth}", rest)
|
56
|
+
end
|
57
|
+
|
58
|
+
# @api private
|
59
|
+
def visit_nominal(node)
|
60
|
+
type = node[0]
|
61
|
+
predicate = infer_predicate(type)
|
62
|
+
|
63
|
+
if registry.key?(predicate[0])
|
64
|
+
predicate
|
65
|
+
else
|
66
|
+
[type?: type]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# @api private
|
71
|
+
def visit_hash(_)
|
72
|
+
HASH
|
73
|
+
end
|
74
|
+
|
75
|
+
# @api private
|
76
|
+
def visit_array(_)
|
77
|
+
ARRAY
|
78
|
+
end
|
79
|
+
|
80
|
+
# @api private
|
81
|
+
def visit_lax(node)
|
82
|
+
visit(node)
|
83
|
+
end
|
84
|
+
|
85
|
+
# @api private
|
86
|
+
def visit_constructor(node)
|
87
|
+
other, * = node
|
88
|
+
visit(other)
|
89
|
+
end
|
90
|
+
|
91
|
+
# @api private
|
92
|
+
def visit_enum(node)
|
93
|
+
other, * = node
|
94
|
+
visit(other)
|
95
|
+
end
|
96
|
+
|
97
|
+
# @api private
|
98
|
+
def visit_sum(node)
|
99
|
+
left_node, right_node, = node
|
100
|
+
left = visit(left_node)
|
101
|
+
right = visit(right_node)
|
102
|
+
|
103
|
+
if left.eql?(NIL)
|
104
|
+
right
|
105
|
+
else
|
106
|
+
[[left, right]]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# @api private
|
111
|
+
def visit_constrained(node)
|
112
|
+
other, rules = node
|
113
|
+
predicates = visit(rules)
|
114
|
+
|
115
|
+
if predicates.empty?
|
116
|
+
visit(other)
|
117
|
+
else
|
118
|
+
[*visit(other), *merge_predicates(predicates)]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# @api private
|
123
|
+
def visit_any(_)
|
124
|
+
EMPTY_ARRAY
|
125
|
+
end
|
126
|
+
|
127
|
+
# @api private
|
128
|
+
def visit_and(node)
|
129
|
+
left, right = node
|
130
|
+
visit(left) + visit(right)
|
131
|
+
end
|
132
|
+
|
133
|
+
# @api private
|
134
|
+
def visit_predicate(node)
|
135
|
+
pred, args = node
|
136
|
+
|
137
|
+
if pred.equal?(:type?)
|
138
|
+
EMPTY_ARRAY
|
139
|
+
elsif registry.key?(pred)
|
140
|
+
*curried, _ = args
|
141
|
+
values = curried.map { |_, v| v }
|
142
|
+
|
143
|
+
if values.empty?
|
144
|
+
[pred]
|
145
|
+
else
|
146
|
+
[pred => values[0]]
|
147
|
+
end
|
148
|
+
else
|
149
|
+
EMPTY_ARRAY
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
# @api private
|
156
|
+
def merge_predicates(nodes)
|
157
|
+
preds, merged = nodes.each_with_object([[], {}]) do |predicate, (ps, h)|
|
158
|
+
if predicate.is_a?(::Hash)
|
159
|
+
h.update(predicate)
|
160
|
+
else
|
161
|
+
ps << predicate
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
merged.empty? ? preds : [*preds, merged]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# @return [Compiler]
|
170
|
+
# @api private
|
171
|
+
attr_reader :compiler
|
172
|
+
|
173
|
+
# @api private
|
174
|
+
def initialize(registry = PredicateRegistry.new)
|
175
|
+
@compiler = Compiler.new(registry)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Infer predicate identifier from the provided type
|
179
|
+
#
|
180
|
+
# @param [Type] type
|
181
|
+
# @return [Symbol]
|
182
|
+
#
|
183
|
+
# @api private
|
184
|
+
def [](type)
|
185
|
+
self.class.fetch_or_store(type) do
|
186
|
+
predicates = compiler.visit(type.to_ast)
|
187
|
+
|
188
|
+
if predicates.is_a?(::Hash)
|
189
|
+
predicates
|
190
|
+
else
|
191
|
+
REDUCED_TYPES[predicates] || predicates
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/logic/predicates'
|
4
|
+
|
5
|
+
module Dry
|
6
|
+
module Types
|
7
|
+
# A registry with predicate objects from `Dry::Logic::Predicates`
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
class PredicateRegistry
|
11
|
+
# @api private
|
12
|
+
attr_reader :predicates
|
13
|
+
|
14
|
+
# @api private
|
15
|
+
attr_reader :has_predicate
|
16
|
+
|
17
|
+
# @api private
|
18
|
+
def initialize(predicates = Logic::Predicates)
|
19
|
+
@predicates = predicates
|
20
|
+
@has_predicate = ::Kernel.instance_method(:respond_to?).bind(@predicates)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @api private
|
24
|
+
def [](name)
|
25
|
+
predicates[name]
|
26
|
+
end
|
27
|
+
|
28
|
+
# @api private
|
29
|
+
def key?(name)
|
30
|
+
has_predicate.(name)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/core/cache'
|
4
|
+
|
5
|
+
module Dry
|
6
|
+
module Types
|
7
|
+
# PrimitiveInferrer returns the list of classes matching a type.
|
8
|
+
#
|
9
|
+
# @api public
|
10
|
+
class PrimitiveInferrer
|
11
|
+
extend Core::Cache
|
12
|
+
|
13
|
+
# Compiler reduces type AST into a list of primitives
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
class Compiler
|
17
|
+
# @api private
|
18
|
+
def visit(node)
|
19
|
+
meth, rest = node
|
20
|
+
public_send(:"visit_#{meth}", rest)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @api private
|
24
|
+
def visit_nominal(node)
|
25
|
+
type, _ = node
|
26
|
+
type
|
27
|
+
end
|
28
|
+
|
29
|
+
# @api private
|
30
|
+
def visit_hash(_)
|
31
|
+
::Hash
|
32
|
+
end
|
33
|
+
alias_method :visit_schema, :visit_hash
|
34
|
+
|
35
|
+
# @api private
|
36
|
+
def visit_array(_)
|
37
|
+
::Array
|
38
|
+
end
|
39
|
+
|
40
|
+
# @api private
|
41
|
+
def visit_lax(node)
|
42
|
+
visit(node)
|
43
|
+
end
|
44
|
+
|
45
|
+
# @api private
|
46
|
+
def visit_constructor(node)
|
47
|
+
other, * = node
|
48
|
+
visit(other)
|
49
|
+
end
|
50
|
+
|
51
|
+
# @api private
|
52
|
+
def visit_enum(node)
|
53
|
+
other, * = node
|
54
|
+
visit(other)
|
55
|
+
end
|
56
|
+
|
57
|
+
# @api private
|
58
|
+
def visit_sum(node)
|
59
|
+
left, right = node
|
60
|
+
|
61
|
+
[visit(left), visit(right)].flatten(1)
|
62
|
+
end
|
63
|
+
|
64
|
+
# @api private
|
65
|
+
def visit_constrained(node)
|
66
|
+
other, * = node
|
67
|
+
visit(other)
|
68
|
+
end
|
69
|
+
|
70
|
+
# @api private
|
71
|
+
def visit_any(_)
|
72
|
+
::Object
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# @return [Compiler]
|
77
|
+
# @api private
|
78
|
+
attr_reader :compiler
|
79
|
+
|
80
|
+
# @api private
|
81
|
+
def initialize
|
82
|
+
@compiler = Compiler.new
|
83
|
+
end
|
84
|
+
|
85
|
+
# Infer primitives from the provided type
|
86
|
+
#
|
87
|
+
# @return [Array[Class]]
|
88
|
+
#
|
89
|
+
# @api private
|
90
|
+
def [](type)
|
91
|
+
self.class.fetch_or_store(type) do
|
92
|
+
Array(compiler.visit(type.to_ast)).freeze
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/lib/dry/types/printable.rb
CHANGED
data/lib/dry/types/printer.rb
CHANGED
@@ -8,6 +8,7 @@ module Dry
|
|
8
8
|
Nominal => :visit_nominal,
|
9
9
|
Constructor => :visit_constructor,
|
10
10
|
Hash::Constructor => :visit_constructor,
|
11
|
+
Array::Constructor => :visit_constructor,
|
11
12
|
Constrained => :visit_constrained,
|
12
13
|
Constrained::Coercible => :visit_constrained,
|
13
14
|
Hash => :visit_hash,
|
@@ -16,7 +17,7 @@ module Dry
|
|
16
17
|
Map => :visit_map,
|
17
18
|
Array => :visit_array,
|
18
19
|
Array::Member => :visit_array_member,
|
19
|
-
|
20
|
+
Lax => :visit_lax,
|
20
21
|
Enum => :visit_enum,
|
21
22
|
Default => :visit_default,
|
22
23
|
Default::Callable => :visit_default,
|
@@ -26,9 +27,9 @@ module Dry
|
|
26
27
|
}
|
27
28
|
|
28
29
|
def call(type)
|
29
|
-
output =
|
30
|
+
output = ''.dup
|
30
31
|
visit(type) { |str| output << str }
|
31
|
-
"#<Dry::Types[#{
|
32
|
+
"#<Dry::Types[#{output}]>"
|
32
33
|
end
|
33
34
|
|
34
35
|
def visit(type, &block)
|
@@ -36,34 +37,38 @@ module Dry
|
|
36
37
|
if type.is_a?(Type)
|
37
38
|
return yield type.inspect
|
38
39
|
else
|
39
|
-
raise ArgumentError, "Do not know how to print #{
|
40
|
+
raise ArgumentError, "Do not know how to print #{type.class}"
|
40
41
|
end
|
41
42
|
end
|
42
43
|
send(print_with, type, &block)
|
43
44
|
end
|
44
45
|
|
45
46
|
def visit_any(_)
|
46
|
-
yield
|
47
|
+
yield 'Any'
|
47
48
|
end
|
48
49
|
|
49
|
-
def visit_array(
|
50
|
-
|
50
|
+
def visit_array(type)
|
51
|
+
visit_options(EMPTY_HASH, type.meta) do |opts|
|
52
|
+
yield "Array#{opts}"
|
53
|
+
end
|
51
54
|
end
|
52
55
|
|
53
56
|
def visit_array_member(array)
|
54
57
|
visit(array.member) do |type|
|
55
|
-
|
58
|
+
visit_options(EMPTY_HASH, array.meta) do |opts|
|
59
|
+
yield "Array<#{type}#{opts}>"
|
60
|
+
end
|
56
61
|
end
|
57
62
|
end
|
58
63
|
|
59
64
|
def visit_constructor(constructor)
|
60
65
|
visit(constructor.type) do |type|
|
61
|
-
visit_callable(constructor.fn) do |fn|
|
66
|
+
visit_callable(constructor.fn.fn) do |fn|
|
62
67
|
options = constructor.options.dup
|
63
68
|
options.delete(:fn)
|
64
69
|
|
65
|
-
visit_options(options
|
66
|
-
yield "Constructor<#{
|
70
|
+
visit_options(options) do |opts|
|
71
|
+
yield "Constructor<#{type} fn=#{fn}#{opts}>"
|
67
72
|
end
|
68
73
|
end
|
69
74
|
end
|
@@ -74,8 +79,8 @@ module Dry
|
|
74
79
|
options = constrained.options.dup
|
75
80
|
rule = options.delete(:rule)
|
76
81
|
|
77
|
-
visit_options(options
|
78
|
-
yield "Constrained<#{
|
82
|
+
visit_options(options) do |_opts|
|
83
|
+
yield "Constrained<#{type} rule=[#{rule}]>"
|
79
84
|
end
|
80
85
|
end
|
81
86
|
end
|
@@ -83,37 +88,38 @@ module Dry
|
|
83
88
|
def visit_schema(schema)
|
84
89
|
options = schema.options.dup
|
85
90
|
size = schema.count
|
86
|
-
key_fn_str =
|
87
|
-
type_fn_str =
|
88
|
-
strict_str =
|
91
|
+
key_fn_str = ''
|
92
|
+
type_fn_str = ''
|
93
|
+
strict_str = ''
|
89
94
|
|
90
|
-
strict_str =
|
95
|
+
strict_str = 'strict ' if options.delete(:strict)
|
91
96
|
|
92
97
|
if key_fn = options.delete(:key_transform_fn)
|
93
98
|
visit_callable(key_fn) do |fn|
|
94
|
-
key_fn_str = "key_fn=#{
|
99
|
+
key_fn_str = "key_fn=#{fn} "
|
95
100
|
end
|
96
101
|
end
|
97
102
|
|
98
103
|
if type_fn = options.delete(:type_transform_fn)
|
99
104
|
visit_callable(type_fn) do |fn|
|
100
|
-
type_fn_str = "type_fn=#{
|
105
|
+
type_fn_str = "type_fn=#{fn} "
|
101
106
|
end
|
102
107
|
end
|
103
108
|
|
104
109
|
keys = options.delete(:keys)
|
105
110
|
|
106
111
|
visit_options(options, schema.meta) do |opts|
|
107
|
-
|
112
|
+
opts = "#{opts[1..-1]} " unless opts.empty?
|
113
|
+
schema_parameters = "#{key_fn_str}#{type_fn_str}#{strict_str}#{opts}"
|
108
114
|
|
109
|
-
header = "Schema<#{
|
115
|
+
header = "Schema<#{schema_parameters}keys={"
|
110
116
|
|
111
117
|
if size.zero?
|
112
|
-
yield "#{
|
118
|
+
yield "#{header}}>"
|
113
119
|
else
|
114
120
|
yield header.dup << keys.map { |key|
|
115
121
|
visit(key) { |type| type }
|
116
|
-
}.join(
|
122
|
+
}.join(' ') << '}>'
|
117
123
|
end
|
118
124
|
end
|
119
125
|
end
|
@@ -125,8 +131,8 @@ module Dry
|
|
125
131
|
options.delete(:key_type)
|
126
132
|
options.delete(:value_type)
|
127
133
|
|
128
|
-
visit_options(options
|
129
|
-
yield "Map<#{
|
134
|
+
visit_options(options) do |_opts|
|
135
|
+
yield "Map<#{key} => #{value}>"
|
130
136
|
end
|
131
137
|
end
|
132
138
|
end
|
@@ -135,9 +141,9 @@ module Dry
|
|
135
141
|
def visit_key(key)
|
136
142
|
visit(key.type) do |type|
|
137
143
|
if key.required?
|
138
|
-
yield "#{
|
144
|
+
yield "#{key.name}: #{type}"
|
139
145
|
else
|
140
|
-
yield "#{
|
146
|
+
yield "#{key.name}?: #{type}"
|
141
147
|
end
|
142
148
|
end
|
143
149
|
end
|
@@ -145,7 +151,7 @@ module Dry
|
|
145
151
|
def visit_sum(sum)
|
146
152
|
visit_sum_constructors(sum) do |constructors|
|
147
153
|
visit_options(sum.options, sum.meta) do |opts|
|
148
|
-
yield "Sum<#{
|
154
|
+
yield "Sum<#{constructors}#{opts}>"
|
149
155
|
end
|
150
156
|
end
|
151
157
|
end
|
@@ -157,11 +163,11 @@ module Dry
|
|
157
163
|
case sum.right
|
158
164
|
when Sum
|
159
165
|
visit_sum_constructors(sum.right) do |right|
|
160
|
-
yield "#{
|
166
|
+
yield "#{left} | #{right}"
|
161
167
|
end
|
162
168
|
else
|
163
169
|
visit(sum.right) do |right|
|
164
|
-
yield "#{
|
170
|
+
yield "#{left} | #{right}"
|
165
171
|
end
|
166
172
|
end
|
167
173
|
end
|
@@ -170,11 +176,11 @@ module Dry
|
|
170
176
|
case sum.right
|
171
177
|
when Sum
|
172
178
|
visit_sum_constructors(sum.right) do |right|
|
173
|
-
yield "#{
|
179
|
+
yield "#{left} | #{right}"
|
174
180
|
end
|
175
181
|
else
|
176
182
|
visit(sum.right) do |right|
|
177
|
-
yield "#{
|
183
|
+
yield "#{left} | #{right}"
|
178
184
|
end
|
179
185
|
end
|
180
186
|
end
|
@@ -186,15 +192,15 @@ module Dry
|
|
186
192
|
options = enum.options.dup
|
187
193
|
mapping = options.delete(:mapping)
|
188
194
|
|
189
|
-
visit_options(options
|
195
|
+
visit_options(options) do |opts|
|
190
196
|
if mapping == enum.inverted_mapping
|
191
|
-
values = mapping.values.map(&:inspect).join(
|
192
|
-
yield "Enum<#{
|
197
|
+
values = mapping.values.map(&:inspect).join(', ')
|
198
|
+
yield "Enum<#{type} values={#{values}}#{opts}>"
|
193
199
|
else
|
194
200
|
mapping_str = mapping.map { |key, value|
|
195
|
-
"#{
|
196
|
-
}.join(
|
197
|
-
yield "Enum<#{
|
201
|
+
"#{key.inspect}=>#{value.inspect}"
|
202
|
+
}.join(', ')
|
203
|
+
yield "Enum<#{type} mapping={#{mapping_str}}#{opts}>"
|
198
204
|
end
|
199
205
|
end
|
200
206
|
end
|
@@ -202,13 +208,13 @@ module Dry
|
|
202
208
|
|
203
209
|
def visit_default(default)
|
204
210
|
visit(default.type) do |type|
|
205
|
-
visit_options(default.options
|
211
|
+
visit_options(default.options) do |opts|
|
206
212
|
if default.is_a?(Default::Callable)
|
207
213
|
visit_callable(default.value) do |fn|
|
208
|
-
yield "Default<#{
|
214
|
+
yield "Default<#{type} value_fn=#{fn}#{opts}>"
|
209
215
|
end
|
210
216
|
else
|
211
|
-
yield "Default<#{
|
217
|
+
yield "Default<#{type} value=#{default.value.inspect}#{opts}>"
|
212
218
|
end
|
213
219
|
end
|
214
220
|
end
|
@@ -216,31 +222,31 @@ module Dry
|
|
216
222
|
|
217
223
|
def visit_nominal(type)
|
218
224
|
visit_options(type.options, type.meta) do |opts|
|
219
|
-
yield "Nominal<#{
|
225
|
+
yield "Nominal<#{type.primitive}#{opts}>"
|
220
226
|
end
|
221
227
|
end
|
222
228
|
|
223
|
-
def
|
224
|
-
visit(
|
225
|
-
yield "
|
229
|
+
def visit_lax(lax)
|
230
|
+
visit(lax.type) do |type|
|
231
|
+
yield "Lax<#{type}>"
|
226
232
|
end
|
227
233
|
end
|
228
234
|
|
229
235
|
def visit_hash(hash)
|
230
236
|
options = hash.options.dup
|
231
|
-
type_fn_str =
|
237
|
+
type_fn_str = ''
|
232
238
|
|
233
239
|
if type_fn = options.delete(:type_transform_fn)
|
234
240
|
visit_callable(type_fn) do |fn|
|
235
|
-
type_fn_str = "type_fn=#{
|
241
|
+
type_fn_str = "type_fn=#{fn}"
|
236
242
|
end
|
237
243
|
end
|
238
244
|
|
239
245
|
visit_options(options, hash.meta) do |opts|
|
240
246
|
if opts.empty? && type_fn_str.empty?
|
241
|
-
yield
|
247
|
+
yield 'Hash'
|
242
248
|
else
|
243
|
-
yield "Hash<#{
|
249
|
+
yield "Hash<#{type_fn_str}#{opts}>"
|
244
250
|
end
|
245
251
|
end
|
246
252
|
end
|
@@ -250,41 +256,41 @@ module Dry
|
|
250
256
|
|
251
257
|
case fn
|
252
258
|
when Method
|
253
|
-
yield "#{
|
259
|
+
yield "#{fn.receiver}.#{fn.name}"
|
254
260
|
when Proc
|
255
261
|
path, line = fn.source_location
|
256
262
|
|
257
|
-
if line
|
258
|
-
yield ".#{
|
263
|
+
if line&.zero?
|
264
|
+
yield ".#{path}"
|
259
265
|
elsif path
|
260
|
-
yield "#{
|
266
|
+
yield "#{path.sub(Dir.pwd + '/', EMPTY_STRING)}:#{line}"
|
261
267
|
elsif fn.lambda?
|
262
|
-
yield
|
268
|
+
yield '(lambda)'
|
263
269
|
else
|
264
270
|
match = fn.to_s.match(/\A#<Proc:0x\h+\(&:(\w+)\)>\z/)
|
265
271
|
|
266
272
|
if match
|
267
|
-
yield ".#{
|
273
|
+
yield ".#{match[1]}"
|
268
274
|
else
|
269
|
-
yield
|
275
|
+
yield '(proc)'
|
270
276
|
end
|
271
277
|
end
|
272
278
|
else
|
273
279
|
call = fn.method(:call)
|
274
280
|
|
275
281
|
if call.owner == fn.class
|
276
|
-
yield "#{
|
282
|
+
yield "#{fn.class}#call"
|
277
283
|
else
|
278
|
-
yield "#{
|
284
|
+
yield "#{fn}.call"
|
279
285
|
end
|
280
286
|
end
|
281
287
|
end
|
282
288
|
|
283
|
-
def visit_options(options, meta)
|
289
|
+
def visit_options(options, meta = EMPTY_HASH)
|
284
290
|
if options.empty? && meta.empty?
|
285
|
-
yield
|
291
|
+
yield ''
|
286
292
|
else
|
287
|
-
opts = options.empty? ?
|
293
|
+
opts = options.empty? ? '' : " options=#{options.inspect}"
|
288
294
|
|
289
295
|
if meta.empty?
|
290
296
|
yield opts
|
@@ -292,13 +298,13 @@ module Dry
|
|
292
298
|
values = meta.map do |key, value|
|
293
299
|
case key
|
294
300
|
when Symbol
|
295
|
-
"#{
|
301
|
+
"#{key}: #{value.inspect}"
|
296
302
|
else
|
297
|
-
"#{
|
303
|
+
"#{key.inspect}=>#{value.inspect}"
|
298
304
|
end
|
299
305
|
end
|
300
306
|
|
301
|
-
yield "#{
|
307
|
+
yield "#{opts} meta={#{values.join(', ')}}"
|
302
308
|
end
|
303
309
|
end
|
304
310
|
end
|