dry-types 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +68 -0
- data/LICENSE +1 -1
- data/README.md +1 -1
- data/dry-types.gemspec +2 -3
- data/lib/dry-types.rb +1 -1
- data/lib/dry/types.rb +55 -31
- data/lib/dry/types/any.rb +2 -2
- data/lib/dry/types/array.rb +2 -2
- data/lib/dry/types/array/constructor.rb +1 -1
- data/lib/dry/types/array/member.rb +1 -1
- data/lib/dry/types/builder.rb +66 -18
- data/lib/dry/types/builder_methods.rb +1 -2
- data/lib/dry/types/coercions/json.rb +5 -5
- data/lib/dry/types/coercions/params.rb +3 -3
- data/lib/dry/types/compiler.rb +10 -10
- data/lib/dry/types/constrained.rb +5 -9
- data/lib/dry/types/constraints.rb +3 -3
- data/lib/dry/types/constructor.rb +39 -6
- data/lib/dry/types/constructor/function.rb +31 -2
- data/lib/dry/types/constructor/wrapper.rb +94 -0
- data/lib/dry/types/container.rb +1 -1
- data/lib/dry/types/core.rb +12 -12
- data/lib/dry/types/decorator.rb +2 -2
- data/lib/dry/types/default.rb +13 -1
- data/lib/dry/types/enum.rb +3 -3
- data/lib/dry/types/errors.rb +1 -1
- data/lib/dry/types/extensions.rb +2 -2
- data/lib/dry/types/extensions/maybe.rb +4 -4
- data/lib/dry/types/extensions/monads.rb +1 -1
- data/lib/dry/types/fn_container.rb +1 -1
- data/lib/dry/types/hash.rb +9 -15
- data/lib/dry/types/hash/constructor.rb +1 -1
- data/lib/dry/types/inflector.rb +1 -1
- data/lib/dry/types/json.rb +15 -15
- data/lib/dry/types/lax.rb +2 -2
- data/lib/dry/types/map.rb +2 -2
- data/lib/dry/types/meta.rb +1 -1
- data/lib/dry/types/module.rb +6 -6
- data/lib/dry/types/nominal.rb +10 -11
- data/lib/dry/types/params.rb +30 -28
- data/lib/dry/types/predicate_inferrer.rb +51 -11
- data/lib/dry/types/predicate_registry.rb +1 -1
- data/lib/dry/types/primitive_inferrer.rb +1 -1
- data/lib/dry/types/printer.rb +25 -25
- data/lib/dry/types/result.rb +1 -1
- data/lib/dry/types/schema.rb +5 -13
- data/lib/dry/types/schema/key.rb +4 -4
- data/lib/dry/types/spec/types.rb +57 -45
- data/lib/dry/types/sum.rb +3 -3
- data/lib/dry/types/type.rb +1 -1
- data/lib/dry/types/version.rb +1 -1
- metadata +9 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8ffbb2a3ad9a5c532228eccc2c56690e1e7ea8808b579a140f804a46a5263d69
|
4
|
+
data.tar.gz: 04e2f92495290236be6daf9be2963649f5350c38f69c16a992649610986bbe5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 53f6b6604552a3dacfbfdb64713e8cfdbc47e51b0b0061b6ab186c948ec207b7159c2a076dd17dead3f4d55e4cc300d2133831590f6b56105ac0754bbfd36e99
|
7
|
+
data.tar.gz: d7050f2070155e72c560f35392121d0de222da270495cbf7f65f0b7c9dcb91f9d9c3db20b119b9a9f1a62c8fae58e49474beaebf81b7df47095cf518607df25c
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,71 @@
|
|
1
|
+
<!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
|
2
|
+
|
3
|
+
## 1.5.0 2020-01-21
|
4
|
+
|
5
|
+
|
6
|
+
### Added
|
7
|
+
|
8
|
+
- Wrapping constructor types :tada: (@flash-gordon)
|
9
|
+
|
10
|
+
Constructor blocks can have a second argument.
|
11
|
+
The second argument is the underlying type itself:
|
12
|
+
```ruby
|
13
|
+
age_from_year = Dry::Types['coercible.integer'].constructor do |input, type|
|
14
|
+
Date.today.year - type.(input)
|
15
|
+
end
|
16
|
+
age_from_year.('2000') # => 21
|
17
|
+
```
|
18
|
+
With wrapping constructors you have control over "type application". You can even
|
19
|
+
run it more than once:
|
20
|
+
```ruby
|
21
|
+
inc = Dry::Types['integer'].constructor(&:succ)
|
22
|
+
inc2x = inc.constructor { _2.(_2.(_2.(_1))) }
|
23
|
+
inc2x.(10) # => 13
|
24
|
+
```
|
25
|
+
- Fallbacks :tada: (@flash-gordon)
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
age = Dry::Types['coercible.ineger'].fallback(18)
|
29
|
+
age.('10') # => 10
|
30
|
+
age.('20') # => 20
|
31
|
+
age.('abc') # => 18
|
32
|
+
```
|
33
|
+
|
34
|
+
Fallbacks are different from default values: the later will be evaluated
|
35
|
+
only when *no input* provided.
|
36
|
+
|
37
|
+
Under the hood, `.fallback` creates a wrapping constructor.
|
38
|
+
- `params.string` as an alias for `strict.string`. This addition should be non-breaking (@flash-gordon)
|
39
|
+
- API for defining custom type builders similar to `.default`, `.constructor`, or `.optional` (@flash-gordon)
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
# Making an alias for `.fallback`
|
43
|
+
Dry::Types.define_builder(:or) { |type, v| type.fallback(v) }
|
44
|
+
|
45
|
+
# Using new builder
|
46
|
+
type = Dry::Types['integer'].or(-273)
|
47
|
+
type.(:invalid) # => -273
|
48
|
+
```
|
49
|
+
|
50
|
+
### Changed
|
51
|
+
|
52
|
+
- Inferring predicates from class names is deprecated. It's very unlikely your code depends on it,
|
53
|
+
however, if it does, you'll get an exception with instructions. (@flash-gordon)
|
54
|
+
|
55
|
+
If you don't rely on inferring, just disable it with:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
Dry::Types::PredicateInferrer::Compiler.infer_predicate_by_class_name false
|
59
|
+
```
|
60
|
+
|
61
|
+
Otherwise, enable it explicitly:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
Dry::Types::PredicateInferrer::Compiler.infer_predicate_by_class_name true
|
65
|
+
```
|
66
|
+
|
67
|
+
[Compare v1.4.0...v1.5.0](https://github.com/dry-rb/dry-types/compare/v1.4.0...v1.5.0)
|
68
|
+
|
1
69
|
## 1.4.0 2020-03-09
|
2
70
|
|
3
71
|
|
data/LICENSE
CHANGED
data/README.md
CHANGED
data/dry-types.gemspec
CHANGED
@@ -25,13 +25,12 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-types'
|
26
26
|
spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-types/issues'
|
27
27
|
|
28
|
-
spec.required_ruby_version = ">= 2.
|
28
|
+
spec.required_ruby_version = ">= 2.5.0"
|
29
29
|
|
30
30
|
# to update dependencies edit project.yml
|
31
31
|
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
32
32
|
spec.add_runtime_dependency "dry-container", "~> 0.3"
|
33
|
-
spec.add_runtime_dependency "dry-core", "~> 0.
|
34
|
-
spec.add_runtime_dependency "dry-equalizer", "~> 0.3"
|
33
|
+
spec.add_runtime_dependency "dry-core", "~> 0.5", ">= 0.5"
|
35
34
|
spec.add_runtime_dependency "dry-inflector", "~> 0.1", ">= 0.1.2"
|
36
35
|
spec.add_runtime_dependency "dry-logic", "~> 1.0", ">= 1.0.2"
|
37
36
|
|
data/lib/dry-types.rb
CHANGED
data/lib/dry/types.rb
CHANGED
@@ -1,27 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "bigdecimal"
|
4
|
+
require "date"
|
5
|
+
require "set"
|
6
6
|
|
7
|
-
require
|
7
|
+
require "concurrent/map"
|
8
8
|
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require 'dry/core/class_attributes'
|
9
|
+
require "dry/container"
|
10
|
+
require "dry/core/extensions"
|
11
|
+
require "dry/core/constants"
|
12
|
+
require "dry/core/class_attributes"
|
14
13
|
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
19
|
-
require
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
14
|
+
require "dry/types/version"
|
15
|
+
require "dry/types/container"
|
16
|
+
require "dry/types/inflector"
|
17
|
+
require "dry/types/type"
|
18
|
+
require "dry/types/printable"
|
19
|
+
require "dry/types/nominal"
|
20
|
+
require "dry/types/constructor"
|
21
|
+
require "dry/types/module"
|
23
22
|
|
24
|
-
require
|
23
|
+
require "dry/types/errors"
|
25
24
|
|
26
25
|
module Dry
|
27
26
|
# Main library namespace
|
@@ -37,7 +36,7 @@ module Dry
|
|
37
36
|
|
38
37
|
# @see Dry.Types
|
39
38
|
def self.module(*namespaces, default: :nominal, **aliases)
|
40
|
-
Module.new(container, *namespaces, default: default, **aliases)
|
39
|
+
::Module.new(container, *namespaces, default: default, **aliases)
|
41
40
|
end
|
42
41
|
deprecate_class_method :module, message: <<~DEPRECATION
|
43
42
|
Use Dry.Types() instead. Beware, it exports strict types by default, for old behavior use Dry.Types(default: :nominal). See more options in the changelog
|
@@ -45,7 +44,7 @@ module Dry
|
|
45
44
|
|
46
45
|
# @api private
|
47
46
|
def self.included(*)
|
48
|
-
raise
|
47
|
+
raise "Import Dry.Types, not Dry::Types"
|
49
48
|
end
|
50
49
|
|
51
50
|
# Return container with registered built-in type objects
|
@@ -121,7 +120,7 @@ module Dry
|
|
121
120
|
#
|
122
121
|
# @return [String]
|
123
122
|
def self.identifier(klass)
|
124
|
-
Inflector.underscore(klass).tr(
|
123
|
+
Inflector.underscore(klass).tr("/", ".")
|
125
124
|
end
|
126
125
|
|
127
126
|
# Cached type map
|
@@ -130,22 +129,49 @@ module Dry
|
|
130
129
|
#
|
131
130
|
# @api private
|
132
131
|
def self.type_map
|
133
|
-
@type_map ||= Concurrent::Map.new
|
132
|
+
@type_map ||= ::Concurrent::Map.new
|
134
133
|
end
|
135
134
|
|
136
135
|
# @api private
|
137
136
|
def self.const_missing(const)
|
138
137
|
underscored = Inflector.underscore(const)
|
139
138
|
|
140
|
-
if container.keys.any? { |key| key.split(
|
141
|
-
raise NameError,
|
142
|
-
|
139
|
+
if container.keys.any? { |key| key.split(".")[0] == underscored }
|
140
|
+
raise ::NameError,
|
141
|
+
"dry-types does not define constants for default types. "\
|
143
142
|
'You can access the predefined types with [], e.g. Dry::Types["integer"] '\
|
144
|
-
|
143
|
+
"or generate a module with types using Dry.Types()"
|
145
144
|
else
|
146
145
|
super
|
147
146
|
end
|
148
147
|
end
|
148
|
+
|
149
|
+
# Add a new type builder method. This is a public API for defining custom
|
150
|
+
# type constructors
|
151
|
+
#
|
152
|
+
# @example simple custom type constructor
|
153
|
+
# Dry::Types.define_builder(:or_nil) do |type|
|
154
|
+
# type.optional.fallback(nil)
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# Dry::Types["integer"].or_nil.("foo") # => nil
|
158
|
+
#
|
159
|
+
# @example fallback alias
|
160
|
+
# Dry::Types.define_builder(:or) do |type, fallback|
|
161
|
+
# type.fallback(fallback)
|
162
|
+
# end
|
163
|
+
#
|
164
|
+
# Dry::Types["integer"].or(100).("foo") # => 100
|
165
|
+
#
|
166
|
+
# @param [Symbol] method
|
167
|
+
# @param [#call] block
|
168
|
+
#
|
169
|
+
# @api public
|
170
|
+
def self.define_builder(method, &block)
|
171
|
+
Builder.define_method(method) do |*args|
|
172
|
+
block.(self, *args)
|
173
|
+
end
|
174
|
+
end
|
149
175
|
end
|
150
176
|
|
151
177
|
# Export registered types as a module with constants
|
@@ -197,13 +223,11 @@ module Dry
|
|
197
223
|
#
|
198
224
|
# @api public
|
199
225
|
#
|
200
|
-
# rubocop:disable Naming/MethodName
|
201
226
|
def self.Types(*namespaces, default: Types::Undefined, **aliases)
|
202
227
|
Types::Module.new(Types.container, *namespaces, default: default, **aliases)
|
203
228
|
end
|
204
|
-
# rubocop:enable Naming/MethodName
|
205
229
|
end
|
206
230
|
|
207
|
-
require
|
208
|
-
require
|
209
|
-
require
|
231
|
+
require "dry/types/core" # load built-in types
|
232
|
+
require "dry/types/extensions"
|
233
|
+
require "dry/types/printer"
|
data/lib/dry/types/any.rb
CHANGED
@@ -10,7 +10,7 @@ module Dry
|
|
10
10
|
# @api public
|
11
11
|
class AnyClass < Nominal
|
12
12
|
def self.name
|
13
|
-
|
13
|
+
"Any"
|
14
14
|
end
|
15
15
|
|
16
16
|
# @api private
|
@@ -22,7 +22,7 @@ module Dry
|
|
22
22
|
#
|
23
23
|
# @api public
|
24
24
|
def name
|
25
|
-
|
25
|
+
"Any"
|
26
26
|
end
|
27
27
|
|
28
28
|
# @param [Hash] new_options
|
data/lib/dry/types/array.rb
CHANGED
data/lib/dry/types/builder.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/core/deprecations"
|
4
4
|
|
5
5
|
module Dry
|
6
6
|
module Types
|
@@ -42,7 +42,7 @@ module Dry
|
|
42
42
|
#
|
43
43
|
# @api public
|
44
44
|
def optional
|
45
|
-
Types[
|
45
|
+
Types["nil"] | self
|
46
46
|
end
|
47
47
|
|
48
48
|
# Turn a type into a constrained type
|
@@ -59,7 +59,7 @@ module Dry
|
|
59
59
|
# Turn a type into a type with a default value
|
60
60
|
#
|
61
61
|
# @param [Object] input
|
62
|
-
# @
|
62
|
+
# @option [Boolean] shared Whether it's safe to share the value across type applications
|
63
63
|
# @param [#call,nil] block
|
64
64
|
#
|
65
65
|
# @raise [ConstraintError]
|
@@ -69,23 +69,27 @@ module Dry
|
|
69
69
|
# @api public
|
70
70
|
def default(input = Undefined, options = EMPTY_HASH, &block)
|
71
71
|
unless input.frozen? || options[:shared]
|
72
|
-
where =
|
73
|
-
|
72
|
+
where = Core::Deprecations::STACK.()
|
73
|
+
Core::Deprecations.warn(
|
74
74
|
"#{input.inspect} is mutable."\
|
75
|
-
|
76
|
-
|
77
|
-
|
75
|
+
" Be careful: types will return the same instance of the default"\
|
76
|
+
" value every time. Call `.freeze` when setting the default"\
|
77
|
+
" or pass `shared: true` to discard this warning."\
|
78
78
|
"\n#{where}",
|
79
79
|
tag: :'dry-types'
|
80
80
|
)
|
81
81
|
end
|
82
82
|
|
83
|
-
value =
|
83
|
+
value = Undefined.default(input, block)
|
84
|
+
type = Default[value].new(self, value)
|
84
85
|
|
85
|
-
if
|
86
|
-
|
86
|
+
if !type.callable? && !valid?(value)
|
87
|
+
raise ConstraintError.new(
|
88
|
+
"default value #{value.inspect} violates constraints",
|
89
|
+
value
|
90
|
+
)
|
87
91
|
else
|
88
|
-
|
92
|
+
type
|
89
93
|
end
|
90
94
|
end
|
91
95
|
|
@@ -127,18 +131,62 @@ module Dry
|
|
127
131
|
#
|
128
132
|
# @api public
|
129
133
|
def constructor(constructor = nil, **options, &block)
|
130
|
-
constructor_type
|
134
|
+
constructor_type[with(**options), fn: constructor || block]
|
131
135
|
end
|
132
136
|
alias_method :append, :constructor
|
133
137
|
alias_method :prepend, :constructor
|
134
138
|
alias_method :>>, :constructor
|
135
139
|
alias_method :<<, :constructor
|
140
|
+
|
141
|
+
# Use the given value on type mismatch
|
142
|
+
#
|
143
|
+
# @param [Object] value
|
144
|
+
# @option [Boolean] shared Whether it's safe to share the value across type applications
|
145
|
+
# @param [#call,nil] fallback
|
146
|
+
#
|
147
|
+
# @return [Constructor]
|
148
|
+
#
|
149
|
+
# @api public
|
150
|
+
def fallback(value = Undefined, shared: false, &_fallback)
|
151
|
+
if Undefined.equal?(value) && !block_given?
|
152
|
+
raise ::ArgumentError, "fallback value or a block must be given"
|
153
|
+
end
|
154
|
+
|
155
|
+
if !block_given? && !valid?(value)
|
156
|
+
raise ConstraintError.new(
|
157
|
+
"fallback value #{value.inspect} violates constraints",
|
158
|
+
value
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
unless value.frozen? || shared
|
163
|
+
where = Core::Deprecations::STACK.()
|
164
|
+
Core::Deprecations.warn(
|
165
|
+
"#{value.inspect} is mutable."\
|
166
|
+
" Be careful: types will return the same instance of the fallback"\
|
167
|
+
" value every time. Call `.freeze` when setting the fallback"\
|
168
|
+
" or pass `shared: true` to discard this warning."\
|
169
|
+
"\n#{where}",
|
170
|
+
tag: :'dry-types'
|
171
|
+
)
|
172
|
+
end
|
173
|
+
|
174
|
+
constructor do |input, type, &_block|
|
175
|
+
type.(input) do |output = input|
|
176
|
+
if block_given?
|
177
|
+
yield(output)
|
178
|
+
else
|
179
|
+
value
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
136
184
|
end
|
137
185
|
end
|
138
186
|
end
|
139
187
|
|
140
|
-
require
|
141
|
-
require
|
142
|
-
require
|
143
|
-
require
|
144
|
-
require
|
188
|
+
require "dry/types/default"
|
189
|
+
require "dry/types/constrained"
|
190
|
+
require "dry/types/enum"
|
191
|
+
require "dry/types/lax"
|
192
|
+
require "dry/types/sum"
|
@@ -4,7 +4,6 @@ module Dry
|
|
4
4
|
module Types
|
5
5
|
# Common API for building type objects in a convenient way
|
6
6
|
#
|
7
|
-
# rubocop:disable Naming/MethodName
|
8
7
|
#
|
9
8
|
# @api public
|
10
9
|
module BuilderMethods
|
@@ -133,7 +132,7 @@ module Dry
|
|
133
132
|
#
|
134
133
|
# @return [Dry::Types::Contrained]
|
135
134
|
def Interface(*methods)
|
136
|
-
methods.reduce(Types[
|
135
|
+
methods.reduce(Types["nominal.any"]) do |type, method|
|
137
136
|
type.constrained(respond_to: method)
|
138
137
|
end
|
139
138
|
end
|