dry-types 1.2.1 → 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 +405 -221
- data/LICENSE +1 -1
- data/README.md +14 -13
- data/dry-types.gemspec +26 -31
- data/lib/dry-types.rb +1 -1
- data/lib/dry/types.rb +55 -40
- 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 +70 -18
- data/lib/dry/types/builder_methods.rb +6 -3
- data/lib/dry/types/coercions.rb +6 -17
- data/lib/dry/types/coercions/json.rb +22 -5
- data/lib/dry/types/coercions/params.rb +21 -4
- data/lib/dry/types/compiler.rb +10 -10
- data/lib/dry/types/constrained.rb +6 -10
- data/lib/dry/types/constraints.rb +3 -3
- data/lib/dry/types/constructor.rb +40 -7
- data/lib/dry/types/constructor/function.rb +47 -32
- data/lib/dry/types/constructor/wrapper.rb +94 -0
- data/lib/dry/types/container.rb +1 -1
- data/lib/dry/types/core.rb +15 -13
- data/lib/dry/types/decorator.rb +2 -9
- data/lib/dry/types/default.rb +15 -3
- data/lib/dry/types/enum.rb +4 -4
- data/lib/dry/types/errors.rb +6 -6
- data/lib/dry/types/extensions.rb +2 -2
- data/lib/dry/types/extensions/maybe.rb +17 -17
- 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 +4 -7
- data/lib/dry/types/map.rb +2 -2
- data/lib/dry/types/meta.rb +3 -3
- data/lib/dry/types/module.rb +6 -6
- data/lib/dry/types/nominal.rb +11 -12
- data/lib/dry/types/params.rb +31 -28
- data/lib/dry/types/predicate_inferrer.rb +52 -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 +3 -3
- data/lib/dry/types/schema.rb +26 -13
- data/lib/dry/types/schema/key.rb +20 -7
- data/lib/dry/types/spec/types.rb +65 -42
- data/lib/dry/types/sum.rb +6 -6
- data/lib/dry/types/type.rb +1 -1
- data/lib/dry/types/version.rb +1 -1
- metadata +27 -84
- data/.codeclimate.yml +0 -12
- data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
- data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -34
- data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
- data/.github/workflows/custom_ci.yml +0 -76
- data/.github/workflows/docsite.yml +0 -34
- data/.github/workflows/sync_configs.yml +0 -34
- data/.gitignore +0 -11
- data/.rspec +0 -4
- data/.rubocop.yml +0 -89
- data/.yardopts +0 -9
- data/CODE_OF_CONDUCT.md +0 -13
- data/CONTRIBUTING.md +0 -29
- data/Gemfile +0 -32
- data/Rakefile +0 -22
- data/benchmarks/hash_schemas.rb +0 -55
- data/benchmarks/lax_schema.rb +0 -15
- data/benchmarks/profile_invalid_input.rb +0 -15
- data/benchmarks/profile_lax_schema_valid.rb +0 -16
- data/benchmarks/profile_valid_input.rb +0 -15
- data/benchmarks/schema_valid_vs_invalid.rb +0 -21
- data/benchmarks/setup.rb +0 -17
- data/docsite/source/array-with-member.html.md +0 -13
- data/docsite/source/built-in-types.html.md +0 -116
- data/docsite/source/constraints.html.md +0 -31
- data/docsite/source/custom-types.html.md +0 -93
- data/docsite/source/default-values.html.md +0 -91
- data/docsite/source/enum.html.md +0 -69
- data/docsite/source/extensions.html.md +0 -15
- data/docsite/source/extensions/maybe.html.md +0 -57
- data/docsite/source/extensions/monads.html.md +0 -61
- data/docsite/source/getting-started.html.md +0 -57
- data/docsite/source/hash-schemas.html.md +0 -169
- data/docsite/source/index.html.md +0 -156
- data/docsite/source/map.html.md +0 -17
- data/docsite/source/optional-values.html.md +0 -35
- data/docsite/source/sum.html.md +0 -21
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,28 +1,29 @@
|
|
1
1
|
[gem]: https://rubygems.org/gems/dry-types
|
2
|
-
[
|
3
|
-
[
|
4
|
-
[coveralls]: https://coveralls.io/r/dry-rb/dry-types
|
5
|
-
[inchpages]: http://inch-ci.org/github/dry-rb/dry-types
|
2
|
+
[actions]: https://github.com/dry-rb/dry-types/actions
|
3
|
+
[codacy]: https://www.codacy.com/gh/dry-rb/dry-types
|
6
4
|
[chat]: https://dry-rb.zulipchat.com
|
5
|
+
[inchpages]: http://inch-ci.org/github/dry-rb/dry-types
|
7
6
|
|
8
7
|
# dry-types [][chat]
|
9
8
|
|
10
9
|
[][gem]
|
11
|
-
[][actions]
|
11
|
+
[][codacy]
|
12
|
+
[][codacy]
|
14
13
|
[][inchpages]
|
15
14
|
|
16
15
|
## Links
|
17
16
|
|
18
|
-
* [
|
17
|
+
* [User documentation](http://dry-rb.org/gems/dry-types)
|
18
|
+
* [API documentation](http://rubydoc.info/gems/dry-types)
|
19
19
|
|
20
|
-
##
|
20
|
+
## Supported Ruby versions
|
21
21
|
|
22
|
-
|
22
|
+
This library officially supports the following Ruby versions:
|
23
23
|
|
24
|
-
|
24
|
+
* MRI >= `2.5`
|
25
|
+
* jruby >= `9.2`
|
25
26
|
|
26
|
-
##
|
27
|
+
## License
|
27
28
|
|
28
|
-
|
29
|
+
See `LICENSE` file.
|
data/dry-types.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
# this file is managed by dry-rb/devtools project
|
2
3
|
|
3
4
|
lib = File.expand_path('lib', __dir__)
|
4
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
@@ -6,42 +7,36 @@ require 'dry/types/version'
|
|
6
7
|
|
7
8
|
Gem::Specification.new do |spec|
|
8
9
|
spec.name = 'dry-types'
|
9
|
-
spec.
|
10
|
-
spec.
|
11
|
-
spec.email = ['piotr.solnica@gmail.com']
|
10
|
+
spec.authors = ["Piotr Solnica"]
|
11
|
+
spec.email = ["piotr.solnica@gmail.com"]
|
12
12
|
spec.license = 'MIT'
|
13
|
+
spec.version = Dry::Types::VERSION.dup
|
13
14
|
|
14
|
-
spec.summary =
|
15
|
+
spec.summary = "Type system for Ruby supporting coercions, constraints and complex types like structs, value objects, enums etc"
|
15
16
|
spec.description = spec.summary
|
16
|
-
spec.homepage = 'https://
|
17
|
+
spec.homepage = 'https://dry-rb.org/gems/dry-types'
|
18
|
+
spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-types.gemspec", "lib/**/*"]
|
19
|
+
spec.bindir = 'bin'
|
20
|
+
spec.executables = []
|
21
|
+
spec.require_paths = ['lib']
|
17
22
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
spec.metadata['changelog_uri'] = 'https://github.com/dry-rb/dry-types/blob/master/CHANGELOG.md'
|
23
|
-
spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-types'
|
24
|
-
spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-types/issues'
|
25
|
-
else
|
26
|
-
raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
|
27
|
-
end
|
23
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
24
|
+
spec.metadata['changelog_uri'] = 'https://github.com/dry-rb/dry-types/blob/master/CHANGELOG.md'
|
25
|
+
spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-types'
|
26
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-types/issues'
|
28
27
|
|
29
|
-
spec.
|
30
|
-
spec.bindir = 'exe'
|
31
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
32
|
-
spec.require_paths = ['lib']
|
33
|
-
spec.required_ruby_version = '>= 2.4.0'
|
28
|
+
spec.required_ruby_version = ">= 2.5.0"
|
34
29
|
|
35
|
-
|
36
|
-
spec.add_runtime_dependency
|
37
|
-
spec.add_runtime_dependency
|
38
|
-
spec.add_runtime_dependency
|
39
|
-
spec.add_runtime_dependency
|
40
|
-
spec.add_runtime_dependency
|
30
|
+
# to update dependencies edit project.yml
|
31
|
+
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
32
|
+
spec.add_runtime_dependency "dry-container", "~> 0.3"
|
33
|
+
spec.add_runtime_dependency "dry-core", "~> 0.5", ">= 0.5"
|
34
|
+
spec.add_runtime_dependency "dry-inflector", "~> 0.1", ">= 0.1.2"
|
35
|
+
spec.add_runtime_dependency "dry-logic", "~> 1.0", ">= 1.0.2"
|
41
36
|
|
42
|
-
spec.add_development_dependency
|
43
|
-
spec.add_development_dependency
|
44
|
-
spec.add_development_dependency
|
45
|
-
spec.add_development_dependency
|
46
|
-
spec.add_development_dependency
|
37
|
+
spec.add_development_dependency "bundler"
|
38
|
+
spec.add_development_dependency "dry-monads", "~> 1.0"
|
39
|
+
spec.add_development_dependency "rake"
|
40
|
+
spec.add_development_dependency "rspec"
|
41
|
+
spec.add_development_dependency "yard"
|
47
42
|
end
|
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,31 +129,49 @@ module Dry
|
|
130
129
|
#
|
131
130
|
# @api private
|
132
131
|
def self.type_map
|
133
|
-
@type_map ||= Concurrent::Map.new
|
134
|
-
end
|
135
|
-
|
136
|
-
# List of type keys defined in {Dry::Types.container}
|
137
|
-
#
|
138
|
-
# @return [String]
|
139
|
-
#
|
140
|
-
# @api private
|
141
|
-
def self.type_keys
|
142
|
-
container.keys
|
132
|
+
@type_map ||= ::Concurrent::Map.new
|
143
133
|
end
|
144
134
|
|
145
135
|
# @api private
|
146
136
|
def self.const_missing(const)
|
147
137
|
underscored = Inflector.underscore(const)
|
148
138
|
|
149
|
-
if container.keys.any? { |key| key.split(
|
150
|
-
raise NameError,
|
151
|
-
|
139
|
+
if container.keys.any? { |key| key.split(".")[0] == underscored }
|
140
|
+
raise ::NameError,
|
141
|
+
"dry-types does not define constants for default types. "\
|
152
142
|
'You can access the predefined types with [], e.g. Dry::Types["integer"] '\
|
153
|
-
|
143
|
+
"or generate a module with types using Dry.Types()"
|
154
144
|
else
|
155
145
|
super
|
156
146
|
end
|
157
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
|
158
175
|
end
|
159
176
|
|
160
177
|
# Export registered types as a module with constants
|
@@ -206,13 +223,11 @@ module Dry
|
|
206
223
|
#
|
207
224
|
# @api public
|
208
225
|
#
|
209
|
-
# rubocop:disable Naming/MethodName
|
210
226
|
def self.Types(*namespaces, default: Types::Undefined, **aliases)
|
211
227
|
Types::Module.new(Types.container, *namespaces, default: default, **aliases)
|
212
228
|
end
|
213
|
-
# rubocop:enable Naming/MethodName
|
214
229
|
end
|
215
230
|
|
216
|
-
require
|
217
|
-
require
|
218
|
-
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,14 +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]
|
135
|
+
end
|
136
|
+
alias_method :append, :constructor
|
137
|
+
alias_method :prepend, :constructor
|
138
|
+
alias_method :>>, :constructor
|
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
|
131
183
|
end
|
132
184
|
end
|
133
185
|
end
|
134
186
|
end
|
135
187
|
|
136
|
-
require
|
137
|
-
require
|
138
|
-
require
|
139
|
-
require
|
140
|
-
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"
|