dry-types 1.4.0 → 1.5.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/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
|