dry-types 0.15.0 → 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 +547 -161
- data/LICENSE +17 -17
- data/README.md +15 -13
- data/dry-types.gemspec +27 -30
- data/lib/dry/types/any.rb +23 -12
- data/lib/dry/types/array/constructor.rb +32 -0
- data/lib/dry/types/array/member.rb +74 -15
- data/lib/dry/types/array.rb +18 -2
- data/lib/dry/types/builder.rb +118 -22
- data/lib/dry/types/builder_methods.rb +46 -16
- data/lib/dry/types/coercions/json.rb +43 -7
- data/lib/dry/types/coercions/params.rb +117 -32
- data/lib/dry/types/coercions.rb +76 -22
- data/lib/dry/types/compiler.rb +44 -21
- data/lib/dry/types/constrained/coercible.rb +36 -6
- data/lib/dry/types/constrained.rb +79 -31
- 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 +110 -61
- data/lib/dry/types/container.rb +6 -1
- data/lib/dry/types/core.rb +34 -11
- data/lib/dry/types/decorator.rb +38 -17
- data/lib/dry/types/default.rb +61 -16
- data/lib/dry/types/enum.rb +36 -20
- data/lib/dry/types/errors.rb +74 -8
- data/lib/dry/types/extensions/maybe.rb +65 -17
- 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 +17 -4
- data/lib/dry/types/hash.rb +32 -20
- 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 +70 -32
- data/lib/dry/types/meta.rb +51 -0
- data/lib/dry/types/module.rb +16 -11
- data/lib/dry/types/nominal.rb +113 -22
- data/lib/dry/types/options.rb +12 -25
- 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 +5 -1
- data/lib/dry/types/printer.rb +63 -57
- data/lib/dry/types/result.rb +29 -3
- data/lib/dry/types/schema/key.rb +62 -36
- data/lib/dry/types/schema.rb +201 -91
- data/lib/dry/types/spec/types.rb +99 -37
- data/lib/dry/types/sum.rb +75 -25
- data/lib/dry/types/type.rb +49 -0
- data/lib/dry/types/version.rb +3 -1
- data/lib/dry/types.rb +106 -48
- data/lib/dry-types.rb +3 -1
- metadata +55 -78
- data/.codeclimate.yml +0 -15
- data/.gitignore +0 -10
- data/.rspec +0 -2
- data/.rubocop.yml +0 -43
- data/.travis.yml +0 -28
- data/.yardopts +0 -5
- data/CONTRIBUTING.md +0 -29
- data/Gemfile +0 -23
- data/Rakefile +0 -20
- data/benchmarks/hash_schemas.rb +0 -51
- data/lib/dry/types/safe.rb +0 -61
- data/log/.gitkeep +0 -0
data/LICENSE
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
-
|
1
|
+
The MIT License (MIT)
|
2
2
|
|
3
|
-
|
4
|
-
a copy of this software and associated documentation files (the
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
9
|
-
the following conditions:
|
3
|
+
Copyright (c) 2015-2021 dry-rb team
|
10
4
|
|
11
|
-
|
12
|
-
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,27 +1,29 @@
|
|
1
1
|
[gem]: https://rubygems.org/gems/dry-types
|
2
|
-
[
|
3
|
-
[
|
4
|
-
[
|
2
|
+
[actions]: https://github.com/dry-rb/dry-types/actions
|
3
|
+
[codacy]: https://www.codacy.com/gh/dry-rb/dry-types
|
4
|
+
[chat]: https://dry-rb.zulipchat.com
|
5
5
|
[inchpages]: http://inch-ci.org/github/dry-rb/dry-types
|
6
6
|
|
7
|
-
# dry-types [][chat]
|
8
8
|
|
9
9
|
[][gem]
|
10
|
-
[][actions]
|
11
|
+
[][codacy]
|
12
|
+
[][codacy]
|
13
13
|
[][inchpages]
|
14
14
|
|
15
15
|
## Links
|
16
16
|
|
17
|
-
* [
|
17
|
+
* [User documentation](http://dry-rb.org/gems/dry-types)
|
18
|
+
* [API documentation](http://rubydoc.info/gems/dry-types)
|
18
19
|
|
19
|
-
##
|
20
|
+
## Supported Ruby versions
|
20
21
|
|
21
|
-
|
22
|
+
This library officially supports the following Ruby versions:
|
22
23
|
|
23
|
-
|
24
|
+
* MRI >= `2.5`
|
25
|
+
* jruby >= `9.2`
|
24
26
|
|
25
|
-
##
|
27
|
+
## License
|
26
28
|
|
27
|
-
|
29
|
+
See `LICENSE` file.
|
data/dry-types.gemspec
CHANGED
@@ -1,45 +1,42 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# this file is managed by dry-rb/devtools project
|
3
|
+
|
4
|
+
lib = File.expand_path('lib', __dir__)
|
2
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
6
|
require 'dry/types/version'
|
4
7
|
|
5
8
|
Gem::Specification.new do |spec|
|
6
|
-
spec.name =
|
7
|
-
spec.version = Dry::Types::VERSION.dup
|
9
|
+
spec.name = 'dry-types'
|
8
10
|
spec.authors = ["Piotr Solnica"]
|
9
11
|
spec.email = ["piotr.solnica@gmail.com"]
|
10
12
|
spec.license = 'MIT'
|
13
|
+
spec.version = Dry::Types::VERSION.dup
|
11
14
|
|
12
|
-
spec.summary =
|
15
|
+
spec.summary = "Type system for Ruby supporting coercions, constraints and complex types like structs, value objects, enums etc"
|
13
16
|
spec.description = spec.summary
|
14
|
-
spec.homepage =
|
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']
|
15
22
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
spec.metadata['changelog_uri'] = "https://github.com/dry-rb/dry-types/blob/master/CHANGELOG.md"
|
21
|
-
spec.metadata['source_code_uri'] = "https://github.com/dry-rb/dry-types"
|
22
|
-
spec.metadata['bug_tracker_uri'] = "https://github.com/dry-rb/dry-types/issues"
|
23
|
-
else
|
24
|
-
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
25
|
-
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'
|
26
27
|
|
27
|
-
spec.
|
28
|
-
spec.bindir = "exe"
|
29
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
30
|
-
spec.require_paths = ["lib"]
|
31
|
-
spec.required_ruby_version = ">= 2.3.0"
|
28
|
+
spec.required_ruby_version = ">= 2.5.0"
|
32
29
|
|
33
|
-
|
34
|
-
spec.add_runtime_dependency
|
35
|
-
spec.add_runtime_dependency
|
36
|
-
spec.add_runtime_dependency
|
37
|
-
spec.add_runtime_dependency
|
38
|
-
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"
|
39
36
|
|
40
37
|
spec.add_development_dependency "bundler"
|
41
|
-
spec.add_development_dependency "
|
42
|
-
spec.add_development_dependency "
|
43
|
-
spec.add_development_dependency
|
44
|
-
spec.add_development_dependency
|
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"
|
45
42
|
end
|
data/lib/dry/types/any.rb
CHANGED
@@ -1,36 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dry
|
2
4
|
module Types
|
3
|
-
Any
|
5
|
+
# Any is a nominal type that defines Object as the primitive class
|
6
|
+
#
|
7
|
+
# This type is useful in places where you can't be specific about the type
|
8
|
+
# and anything is acceptable.
|
9
|
+
#
|
10
|
+
# @api public
|
11
|
+
class AnyClass < Nominal
|
4
12
|
def self.name
|
5
|
-
|
13
|
+
"Any"
|
6
14
|
end
|
7
15
|
|
16
|
+
# @api private
|
8
17
|
def initialize(**options)
|
9
|
-
super(::Object, options)
|
18
|
+
super(::Object, **options)
|
10
19
|
end
|
11
20
|
|
12
21
|
# @return [String]
|
22
|
+
#
|
23
|
+
# @api public
|
13
24
|
def name
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
# @param [Object] any input is valid
|
18
|
-
# @return [true]
|
19
|
-
def valid?(_)
|
20
|
-
true
|
25
|
+
"Any"
|
21
26
|
end
|
22
|
-
alias_method :===, :valid?
|
23
27
|
|
24
28
|
# @param [Hash] new_options
|
29
|
+
#
|
25
30
|
# @return [Type]
|
31
|
+
#
|
32
|
+
# @api public
|
26
33
|
def with(**new_options)
|
27
34
|
self.class.new(**options, meta: @meta, **new_options)
|
28
35
|
end
|
29
36
|
|
30
37
|
# @return [Array]
|
38
|
+
#
|
39
|
+
# @api public
|
31
40
|
def to_ast(meta: true)
|
32
41
|
[:any, meta ? self.meta : EMPTY_HASH]
|
33
42
|
end
|
34
|
-
end
|
43
|
+
end
|
44
|
+
|
45
|
+
Any = AnyClass.new
|
35
46
|
end
|
36
47
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/types/constructor"
|
4
|
+
|
5
|
+
module Dry
|
6
|
+
module Types
|
7
|
+
# @api public
|
8
|
+
class Array < Nominal
|
9
|
+
# @api private
|
10
|
+
class Constructor < ::Dry::Types::Constructor
|
11
|
+
# @api private
|
12
|
+
def constructor_type
|
13
|
+
::Dry::Types::Array::Constructor
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [Lax]
|
17
|
+
#
|
18
|
+
# @api public
|
19
|
+
def lax
|
20
|
+
Lax.new(type.lax.constructor(fn, meta: meta))
|
21
|
+
end
|
22
|
+
|
23
|
+
# @see Dry::Types::Array#of
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
def of(member)
|
27
|
+
type.of(member).constructor(fn, meta: meta)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -1,57 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/types/array/constructor"
|
4
|
+
|
1
5
|
module Dry
|
2
6
|
module Types
|
3
7
|
class Array < Nominal
|
8
|
+
# Member arrays define their member type that is applied to each element
|
9
|
+
#
|
10
|
+
# @api public
|
4
11
|
class Member < Array
|
5
12
|
# @return [Type]
|
6
13
|
attr_reader :member
|
7
14
|
|
8
15
|
# @param [Class] primitive
|
9
16
|
# @param [Hash] options
|
17
|
+
#
|
10
18
|
# @option options [Type] :member
|
11
|
-
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
def initialize(primitive, **options)
|
12
22
|
@member = options.fetch(:member)
|
13
23
|
super
|
14
24
|
end
|
15
25
|
|
16
26
|
# @param [Object] input
|
17
|
-
#
|
27
|
+
#
|
18
28
|
# @return [Array]
|
19
|
-
|
20
|
-
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
def call_unsafe(input)
|
32
|
+
if primitive?(input)
|
33
|
+
input.each_with_object([]) do |el, output|
|
34
|
+
coerced = member.call_unsafe(el)
|
35
|
+
|
36
|
+
output << coerced unless Undefined.equal?(coerced)
|
37
|
+
end
|
38
|
+
else
|
39
|
+
super
|
40
|
+
end
|
21
41
|
end
|
22
|
-
alias_method :[], :call
|
23
42
|
|
24
|
-
# @param [
|
25
|
-
# @return [
|
26
|
-
|
27
|
-
|
43
|
+
# @param [Object] input
|
44
|
+
# @return [Array]
|
45
|
+
#
|
46
|
+
# @api private
|
47
|
+
def call_safe(input)
|
48
|
+
if primitive?(input)
|
49
|
+
failed = false
|
50
|
+
|
51
|
+
result = input.each_with_object([]) do |el, output|
|
52
|
+
coerced = member.call_safe(el) { |out = el|
|
53
|
+
failed = true
|
54
|
+
out
|
55
|
+
}
|
56
|
+
|
57
|
+
output << coerced unless Undefined.equal?(coerced)
|
58
|
+
end
|
59
|
+
|
60
|
+
failed ? yield(result) : result
|
61
|
+
else
|
62
|
+
yield
|
63
|
+
end
|
28
64
|
end
|
29
65
|
|
30
66
|
# @param [Array, Object] input
|
31
67
|
# @param [#call,nil] block
|
68
|
+
#
|
32
69
|
# @yieldparam [Failure] failure
|
33
70
|
# @yieldreturn [Result]
|
71
|
+
#
|
34
72
|
# @return [Result,Logic::Result]
|
73
|
+
#
|
74
|
+
# @api public
|
35
75
|
def try(input, &block)
|
36
|
-
if
|
37
|
-
|
38
|
-
|
76
|
+
if primitive?(input)
|
77
|
+
output = []
|
78
|
+
|
79
|
+
result = input.map { |el| member.try(el) }
|
80
|
+
result.each do |r|
|
81
|
+
output << r.input unless Undefined.equal?(r.input)
|
82
|
+
end
|
39
83
|
|
40
84
|
if result.all?(&:success?)
|
41
85
|
success(output)
|
42
86
|
else
|
43
|
-
|
87
|
+
error = result.find(&:failure?).error
|
88
|
+
failure = failure(output, error)
|
44
89
|
block ? yield(failure) : failure
|
45
90
|
end
|
46
91
|
else
|
47
|
-
failure = failure(input, "#{input} is not an array")
|
92
|
+
failure = failure(input, CoercionError.new("#{input} is not an array"))
|
48
93
|
block ? yield(failure) : failure
|
49
94
|
end
|
50
95
|
end
|
51
96
|
|
52
|
-
#
|
97
|
+
# Build a lax type
|
53
98
|
#
|
99
|
+
# @return [Lax]
|
100
|
+
#
|
101
|
+
# @api public
|
102
|
+
def lax
|
103
|
+
Lax.new(Member.new(primitive, **options, member: member.lax, meta: meta))
|
104
|
+
end
|
105
|
+
|
54
106
|
# @see Nominal#to_ast
|
107
|
+
#
|
108
|
+
# @api public
|
55
109
|
def to_ast(meta: true)
|
56
110
|
if member.respond_to?(:to_ast)
|
57
111
|
[:array, [member.to_ast(meta: meta), meta ? self.meta : EMPTY_HASH]]
|
@@ -59,6 +113,11 @@ module Dry
|
|
59
113
|
[:array, [member, meta ? self.meta : EMPTY_HASH]]
|
60
114
|
end
|
61
115
|
end
|
116
|
+
|
117
|
+
# @api private
|
118
|
+
def constructor_type
|
119
|
+
::Dry::Types::Array::Constructor
|
120
|
+
end
|
62
121
|
end
|
63
122
|
end
|
64
123
|
end
|
data/lib/dry/types/array.rb
CHANGED
@@ -1,10 +1,21 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/types/array/member"
|
4
|
+
require "dry/types/array/constructor"
|
2
5
|
|
3
6
|
module Dry
|
4
7
|
module Types
|
8
|
+
# Array type can be used to define an array with optional member type
|
9
|
+
#
|
10
|
+
# @api public
|
5
11
|
class Array < Nominal
|
6
|
-
#
|
12
|
+
# Build an array type with a member type
|
13
|
+
#
|
14
|
+
# @param [Type,#call] type
|
15
|
+
#
|
7
16
|
# @return [Array::Member]
|
17
|
+
#
|
18
|
+
# @api public
|
8
19
|
def of(type)
|
9
20
|
member =
|
10
21
|
case type
|
@@ -14,6 +25,11 @@ module Dry
|
|
14
25
|
|
15
26
|
Array::Member.new(primitive, **options, member: member)
|
16
27
|
end
|
28
|
+
|
29
|
+
# @api private
|
30
|
+
def constructor_type
|
31
|
+
::Dry::Types::Array::Constructor
|
32
|
+
end
|
17
33
|
end
|
18
34
|
end
|
19
35
|
end
|
data/lib/dry/types/builder.rb
CHANGED
@@ -1,67 +1,105 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/deprecations"
|
2
4
|
|
3
5
|
module Dry
|
4
6
|
module Types
|
7
|
+
# Common API for building types and composition
|
8
|
+
#
|
9
|
+
# @api public
|
5
10
|
module Builder
|
6
11
|
include Dry::Core::Constants
|
7
12
|
|
8
13
|
# @return [Class]
|
14
|
+
#
|
15
|
+
# @api private
|
9
16
|
def constrained_type
|
10
17
|
Constrained
|
11
18
|
end
|
12
19
|
|
13
20
|
# @return [Class]
|
21
|
+
#
|
22
|
+
# @api private
|
14
23
|
def constructor_type
|
15
24
|
Constructor
|
16
25
|
end
|
17
26
|
|
27
|
+
# Compose two types into a Sum type
|
28
|
+
#
|
18
29
|
# @param [Type] other
|
30
|
+
#
|
19
31
|
# @return [Sum, Sum::Constrained]
|
32
|
+
#
|
33
|
+
# @api private
|
20
34
|
def |(other)
|
21
35
|
klass = constrained? && other.constrained? ? Sum::Constrained : Sum
|
22
36
|
klass.new(self, other)
|
23
37
|
end
|
24
38
|
|
39
|
+
# Turn a type into an optional type
|
40
|
+
#
|
25
41
|
# @return [Sum]
|
42
|
+
#
|
43
|
+
# @api public
|
26
44
|
def optional
|
27
|
-
Types[
|
45
|
+
Types["nil"] | self
|
28
46
|
end
|
29
47
|
|
48
|
+
# Turn a type into a constrained type
|
49
|
+
#
|
30
50
|
# @param [Hash] options constraining rule (see {Types.Rule})
|
51
|
+
#
|
31
52
|
# @return [Constrained]
|
53
|
+
#
|
54
|
+
# @api public
|
32
55
|
def constrained(options)
|
33
56
|
constrained_type.new(self, rule: Types.Rule(options))
|
34
57
|
end
|
35
58
|
|
59
|
+
# Turn a type into a type with a default value
|
60
|
+
#
|
36
61
|
# @param [Object] input
|
37
|
-
# @
|
62
|
+
# @option [Boolean] shared Whether it's safe to share the value across type applications
|
38
63
|
# @param [#call,nil] block
|
64
|
+
#
|
39
65
|
# @raise [ConstraintError]
|
66
|
+
#
|
40
67
|
# @return [Default]
|
68
|
+
#
|
69
|
+
# @api public
|
41
70
|
def default(input = Undefined, options = EMPTY_HASH, &block)
|
42
71
|
unless input.frozen? || options[:shared]
|
43
|
-
where =
|
44
|
-
|
72
|
+
where = Core::Deprecations::STACK.()
|
73
|
+
Core::Deprecations.warn(
|
45
74
|
"#{input.inspect} is mutable."\
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
"\n#{
|
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
|
+
"\n#{where}",
|
50
79
|
tag: :'dry-types'
|
51
80
|
)
|
52
81
|
end
|
53
82
|
|
54
|
-
value =
|
83
|
+
value = Undefined.default(input, block)
|
84
|
+
type = Default[value].new(self, value)
|
55
85
|
|
56
|
-
if
|
57
|
-
|
86
|
+
if !type.callable? && !valid?(value)
|
87
|
+
raise ConstraintError.new(
|
88
|
+
"default value #{value.inspect} violates constraints",
|
89
|
+
value
|
90
|
+
)
|
58
91
|
else
|
59
|
-
|
92
|
+
type
|
60
93
|
end
|
61
94
|
end
|
62
95
|
|
96
|
+
# Define an enum on top of the existing type
|
97
|
+
#
|
63
98
|
# @param [Array] values
|
99
|
+
#
|
64
100
|
# @return [Enum]
|
101
|
+
#
|
102
|
+
# @api public
|
65
103
|
def enum(*values)
|
66
104
|
mapping =
|
67
105
|
if values.length == 1 && values[0].is_a?(::Hash)
|
@@ -73,24 +111,82 @@ module Dry
|
|
73
111
|
Enum.new(constrained(included_in: mapping.keys), mapping: mapping)
|
74
112
|
end
|
75
113
|
|
76
|
-
#
|
77
|
-
|
78
|
-
|
114
|
+
# Turn a type into a lax type that will rescue from type-errors and
|
115
|
+
# return the original input
|
116
|
+
#
|
117
|
+
# @return [Lax]
|
118
|
+
#
|
119
|
+
# @api public
|
120
|
+
def lax
|
121
|
+
Lax.new(self)
|
79
122
|
end
|
80
123
|
|
124
|
+
# Define a constructor for the type
|
125
|
+
#
|
81
126
|
# @param [#call,nil] constructor
|
82
127
|
# @param [Hash] options
|
83
128
|
# @param [#call,nil] block
|
129
|
+
#
|
84
130
|
# @return [Constructor]
|
131
|
+
#
|
132
|
+
# @api public
|
85
133
|
def constructor(constructor = nil, **options, &block)
|
86
|
-
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
|
87
183
|
end
|
88
184
|
end
|
89
185
|
end
|
90
186
|
end
|
91
187
|
|
92
|
-
require
|
93
|
-
require
|
94
|
-
require
|
95
|
-
require
|
96
|
-
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"
|