dry-types 0.14.1 → 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 +631 -134
- data/LICENSE +17 -17
- data/README.md +15 -13
- data/dry-types.gemspec +27 -30
- data/lib/dry/types/any.rb +32 -12
- data/lib/dry/types/array/constructor.rb +32 -0
- data/lib/dry/types/array/member.rb +75 -16
- data/lib/dry/types/array.rb +19 -6
- data/lib/dry/types/builder.rb +131 -15
- data/lib/dry/types/builder_methods.rb +49 -20
- data/lib/dry/types/coercions/json.rb +43 -7
- data/lib/dry/types/coercions/params.rb +118 -31
- data/lib/dry/types/coercions.rb +76 -22
- data/lib/dry/types/compat.rb +0 -2
- data/lib/dry/types/compiler.rb +56 -41
- data/lib/dry/types/constrained/coercible.rb +36 -6
- data/lib/dry/types/constrained.rb +81 -32
- 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 +126 -56
- data/lib/dry/types/container.rb +7 -0
- data/lib/dry/types/core.rb +54 -21
- data/lib/dry/types/decorator.rb +38 -17
- data/lib/dry/types/default.rb +61 -16
- data/lib/dry/types/enum.rb +43 -20
- data/lib/dry/types/errors.rb +75 -9
- data/lib/dry/types/extensions/maybe.rb +74 -16
- 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 +33 -0
- data/lib/dry/types/hash.rb +86 -67
- 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 +76 -33
- data/lib/dry/types/meta.rb +51 -0
- data/lib/dry/types/module.rb +120 -0
- data/lib/dry/types/nominal.rb +210 -0
- data/lib/dry/types/options.rb +13 -26
- 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 +16 -0
- data/lib/dry/types/printer.rb +315 -0
- data/lib/dry/types/result.rb +29 -3
- data/lib/dry/types/schema/key.rb +156 -0
- data/lib/dry/types/schema.rb +408 -0
- data/lib/dry/types/spec/types.rb +103 -33
- data/lib/dry/types/sum.rb +84 -35
- data/lib/dry/types/type.rb +49 -0
- data/lib/dry/types/version.rb +3 -1
- data/lib/dry/types.rb +156 -76
- data/lib/dry-types.rb +3 -1
- metadata +65 -78
- data/.gitignore +0 -10
- data/.rspec +0 -2
- data/.travis.yml +0 -27
- data/.yardopts +0 -5
- data/CONTRIBUTING.md +0 -29
- data/Gemfile +0 -24
- data/Rakefile +0 -20
- data/benchmarks/hash_schemas.rb +0 -51
- data/lib/dry/types/compat/form_types.rb +0 -27
- data/lib/dry/types/compat/int.rb +0 -14
- data/lib/dry/types/definition.rb +0 -113
- data/lib/dry/types/hash/schema.rb +0 -199
- data/lib/dry/types/hash/schema_builder.rb +0 -75
- data/lib/dry/types/safe.rb +0 -59
- data/log/.gitkeep +0 -0
@@ -1,199 +0,0 @@
|
|
1
|
-
require 'dry/types/fn_container'
|
2
|
-
|
3
|
-
module Dry
|
4
|
-
module Types
|
5
|
-
class Hash < Definition
|
6
|
-
# The built-in Hash type has constructors that you can use to define
|
7
|
-
# hashes with explicit schemas and coercible values using the built-in types.
|
8
|
-
#
|
9
|
-
# Basic {Schema} evaluates default values for keys missing in input hash
|
10
|
-
# (see {Schema#resolve_missing_value})
|
11
|
-
#
|
12
|
-
# @see Dry::Types::Default#evaluate
|
13
|
-
# @see Dry::Types::Default::Callable#evaluate
|
14
|
-
class Schema < Hash
|
15
|
-
NO_TRANSFORM = Dry::Types::FnContainer.register { |x| x }
|
16
|
-
SYMBOLIZE_KEY = Dry::Types::FnContainer.register(:to_sym.to_proc)
|
17
|
-
|
18
|
-
# @return [Hash{Symbol => Definition}]
|
19
|
-
attr_reader :member_types
|
20
|
-
|
21
|
-
# @return [#call]
|
22
|
-
attr_reader :transform_key
|
23
|
-
|
24
|
-
# @param [Class] _primitive
|
25
|
-
# @param [Hash] options
|
26
|
-
# @option options [Hash{Symbol => Definition}] :member_types
|
27
|
-
# @option options [String] :key_transform_fn
|
28
|
-
def initialize(_primitive, **options)
|
29
|
-
@member_types = options.fetch(:member_types)
|
30
|
-
|
31
|
-
meta = options[:meta] || EMPTY_HASH
|
32
|
-
key_fn = meta.fetch(:key_transform_fn, NO_TRANSFORM)
|
33
|
-
|
34
|
-
@transform_key = Dry::Types::FnContainer[key_fn]
|
35
|
-
|
36
|
-
super
|
37
|
-
end
|
38
|
-
|
39
|
-
# @param [Hash] hash
|
40
|
-
# @return [Hash{Symbol => Object}]
|
41
|
-
def call(hash)
|
42
|
-
coerce(hash)
|
43
|
-
end
|
44
|
-
alias_method :[], :call
|
45
|
-
|
46
|
-
# @param [Hash] hash
|
47
|
-
# @yieldparam [Failure] failure
|
48
|
-
# @yieldreturn [Result]
|
49
|
-
# @return [Logic::Result]
|
50
|
-
# @return [Object] if coercion fails and a block is given
|
51
|
-
def try(hash)
|
52
|
-
if hash.is_a?(::Hash)
|
53
|
-
success = true
|
54
|
-
output = {}
|
55
|
-
|
56
|
-
begin
|
57
|
-
result = try_coerce(hash) do |key, member_result|
|
58
|
-
success &&= member_result.success?
|
59
|
-
output[key] = member_result.input
|
60
|
-
|
61
|
-
member_result
|
62
|
-
end
|
63
|
-
rescue ConstraintError, UnknownKeysError, SchemaError, MissingKeyError => e
|
64
|
-
success = false
|
65
|
-
result = e
|
66
|
-
end
|
67
|
-
else
|
68
|
-
success = false
|
69
|
-
output = hash
|
70
|
-
result = "#{hash} must be a hash"
|
71
|
-
end
|
72
|
-
|
73
|
-
if success
|
74
|
-
success(output)
|
75
|
-
else
|
76
|
-
failure = failure(output, result)
|
77
|
-
block_given? ? yield(failure) : failure
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# @param meta [Boolean] Whether to dump the meta to the AST
|
82
|
-
# @return [Array] An AST representation
|
83
|
-
def to_ast(meta: true)
|
84
|
-
[
|
85
|
-
:hash_schema,
|
86
|
-
[
|
87
|
-
member_types.map { |name, member| [:member, [name, member.to_ast(meta: meta)]] },
|
88
|
-
meta ? self.meta : EMPTY_HASH
|
89
|
-
]
|
90
|
-
]
|
91
|
-
end
|
92
|
-
|
93
|
-
# @param [Hash] hash
|
94
|
-
# @return [Boolean]
|
95
|
-
def valid?(hash)
|
96
|
-
result = try(hash)
|
97
|
-
result.success?
|
98
|
-
end
|
99
|
-
alias_method :===, :valid?
|
100
|
-
|
101
|
-
# Whether the schema rejects unknown keys
|
102
|
-
# @return [Boolean]
|
103
|
-
def strict?
|
104
|
-
meta.fetch(:strict, false)
|
105
|
-
end
|
106
|
-
|
107
|
-
# Make the schema intolerant to unknown keys
|
108
|
-
# @return [Schema]
|
109
|
-
def strict
|
110
|
-
meta(strict: true)
|
111
|
-
end
|
112
|
-
|
113
|
-
# Injects a key transformation function
|
114
|
-
# @param [#call,nil] proc
|
115
|
-
# @param [#call,nil] block
|
116
|
-
# @return [Schema]
|
117
|
-
def with_key_transform(proc = nil, &block)
|
118
|
-
fn = proc || block
|
119
|
-
|
120
|
-
if fn.nil?
|
121
|
-
raise ArgumentError, "a block or callable argument is required"
|
122
|
-
end
|
123
|
-
|
124
|
-
handle = Dry::Types::FnContainer.register(fn)
|
125
|
-
meta(key_transform_fn: handle)
|
126
|
-
end
|
127
|
-
|
128
|
-
# @param [{Symbol => Definition}] type_map
|
129
|
-
# @return [Schema]
|
130
|
-
def schema(type_map)
|
131
|
-
member_types = self.member_types.merge(transform_types(type_map))
|
132
|
-
Schema.new(primitive, **options, member_types: member_types, meta: meta)
|
133
|
-
end
|
134
|
-
|
135
|
-
private
|
136
|
-
|
137
|
-
def resolve(hash)
|
138
|
-
result = {}
|
139
|
-
|
140
|
-
hash.each do |key, value|
|
141
|
-
k = transform_key.(key)
|
142
|
-
|
143
|
-
if member_types.key?(k)
|
144
|
-
result[k] = yield(member_types[k], k, value)
|
145
|
-
elsif strict?
|
146
|
-
raise UnknownKeysError.new(*unexpected_keys(hash.keys))
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
if result.size < member_types.size
|
151
|
-
resolve_missing_keys(result, &Proc.new)
|
152
|
-
end
|
153
|
-
|
154
|
-
result
|
155
|
-
end
|
156
|
-
|
157
|
-
def resolve_missing_keys(result)
|
158
|
-
member_types.each do |k, type|
|
159
|
-
next if result.key?(k)
|
160
|
-
|
161
|
-
if type.default?
|
162
|
-
result[k] = yield(type, k, Undefined)
|
163
|
-
elsif !type.meta[:omittable]
|
164
|
-
raise MissingKeyError, k
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
# @param keys [Array<Symbol>]
|
170
|
-
# @return [Array<Symbol>]
|
171
|
-
def unexpected_keys(keys)
|
172
|
-
keys.map(&transform_key) - member_types.keys
|
173
|
-
end
|
174
|
-
|
175
|
-
# @param [Hash] hash
|
176
|
-
# @return [Hash{Symbol => Object}]
|
177
|
-
def try_coerce(hash)
|
178
|
-
resolve(hash) do |type, key, value|
|
179
|
-
yield(key, type.try(value))
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
# @param [Hash] hash
|
184
|
-
# @return [Hash{Symbol => Object}]
|
185
|
-
def coerce(hash)
|
186
|
-
resolve(hash) do |type, key, value|
|
187
|
-
begin
|
188
|
-
type.call(value)
|
189
|
-
rescue ConstraintError => e
|
190
|
-
raise SchemaError.new(key, value, e.result)
|
191
|
-
rescue TypeError, ArgumentError => e
|
192
|
-
raise SchemaError.new(key, value, e.message)
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
require 'dry/types/hash/schema'
|
2
|
-
require 'dry/types/fn_container'
|
3
|
-
|
4
|
-
module Dry
|
5
|
-
module Types
|
6
|
-
class Hash < Definition
|
7
|
-
# A bulder for legacy schemas
|
8
|
-
# @api private
|
9
|
-
class SchemaBuilder
|
10
|
-
NIL_TO_UNDEFINED = -> v { v.nil? ? Undefined : v }
|
11
|
-
OMITTABLE_KEYS = %i(schema weak symbolized).freeze
|
12
|
-
STRICT = %i(strict strict_with_defaults).freeze
|
13
|
-
|
14
|
-
# @param primitive [Type]
|
15
|
-
# @option options [Hash{Symbol => Definition}] :member_types
|
16
|
-
# @option options [Symbol] :hash_type
|
17
|
-
def call(primitive, **options)
|
18
|
-
hash_type = options.fetch(:hash_type)
|
19
|
-
member_types = {}
|
20
|
-
|
21
|
-
options.fetch(:member_types).each do |k, t|
|
22
|
-
member_types[k] = build_type(hash_type, t)
|
23
|
-
end
|
24
|
-
|
25
|
-
instantiate(primitive, **options, member_types: member_types)
|
26
|
-
end
|
27
|
-
|
28
|
-
def instantiate(primitive, hash_type: :base, meta: EMPTY_HASH, **options)
|
29
|
-
meta = meta.dup
|
30
|
-
|
31
|
-
meta[:strict] = true if strict?(hash_type)
|
32
|
-
meta[:key_transform_fn] = Schema::SYMBOLIZE_KEY if hash_type == :symbolized
|
33
|
-
|
34
|
-
Schema.new(primitive, **options, meta: meta)
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
def omittable?(constructor)
|
40
|
-
OMITTABLE_KEYS.include?(constructor)
|
41
|
-
end
|
42
|
-
|
43
|
-
def strict?(constructor)
|
44
|
-
STRICT.include?(constructor)
|
45
|
-
end
|
46
|
-
|
47
|
-
def build_type(constructor, type)
|
48
|
-
type = safe(constructor, type)
|
49
|
-
type = default(constructor, type) if type.default?
|
50
|
-
type = type.meta(omittable: true) if omittable?(constructor)
|
51
|
-
type
|
52
|
-
end
|
53
|
-
|
54
|
-
def safe(constructor, type)
|
55
|
-
if constructor == :weak || constructor == :symbolized
|
56
|
-
type.safe
|
57
|
-
else
|
58
|
-
type
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def default(constructor, type)
|
63
|
-
case constructor
|
64
|
-
when :strict_with_defaults
|
65
|
-
type
|
66
|
-
when :strict
|
67
|
-
type.type
|
68
|
-
else
|
69
|
-
type.constructor(NIL_TO_UNDEFINED)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
data/lib/dry/types/safe.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require 'dry/types/decorator'
|
2
|
-
|
3
|
-
module Dry
|
4
|
-
module Types
|
5
|
-
class Safe
|
6
|
-
include Type
|
7
|
-
include Dry::Equalizer(:type)
|
8
|
-
include Decorator
|
9
|
-
include Builder
|
10
|
-
private :options, :meta
|
11
|
-
|
12
|
-
# @param [Object] input
|
13
|
-
# @return [Object]
|
14
|
-
def call(input)
|
15
|
-
result = try(input)
|
16
|
-
|
17
|
-
if result.respond_to?(:input)
|
18
|
-
result.input
|
19
|
-
else
|
20
|
-
input
|
21
|
-
end
|
22
|
-
end
|
23
|
-
alias_method :[], :call
|
24
|
-
|
25
|
-
# @param [Object] input
|
26
|
-
# @param [#call,nil] block
|
27
|
-
# @yieldparam [Failure] failure
|
28
|
-
# @yieldreturn [Result]
|
29
|
-
# @return [Result,Logic::Result]
|
30
|
-
def try(input, &block)
|
31
|
-
type.try(input, &block)
|
32
|
-
rescue TypeError, ArgumentError => e
|
33
|
-
result = failure(input, e.message)
|
34
|
-
block ? yield(result) : result
|
35
|
-
end
|
36
|
-
|
37
|
-
# @api public
|
38
|
-
#
|
39
|
-
# @see Definition#to_ast
|
40
|
-
def to_ast(meta: true)
|
41
|
-
[:safe, [type.to_ast(meta: meta), EMPTY_HASH]]
|
42
|
-
end
|
43
|
-
|
44
|
-
# @api public
|
45
|
-
# @return [Safe]
|
46
|
-
def safe
|
47
|
-
self
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
# @param [Object, Dry::Types::Constructor] response
|
53
|
-
# @return [Boolean]
|
54
|
-
def decorate?(response)
|
55
|
-
super || response.kind_of?(Constructor)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
data/log/.gitkeep
DELETED
File without changes
|