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
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
3
|
+
require "date"
|
4
|
+
require "bigdecimal"
|
5
|
+
require "bigdecimal/util"
|
6
|
+
require "time"
|
7
7
|
|
8
8
|
module Dry
|
9
9
|
module Types
|
@@ -38,7 +38,7 @@ module Dry
|
|
38
38
|
# @raise CoercionError
|
39
39
|
#
|
40
40
|
# @api public
|
41
|
-
def self.to_decimal(input, &
|
41
|
+
def self.to_decimal(input, &_block)
|
42
42
|
if input.is_a?(::Float)
|
43
43
|
input.to_d
|
44
44
|
else
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "bigdecimal"
|
4
|
+
require "bigdecimal/util"
|
5
5
|
|
6
6
|
module Dry
|
7
7
|
module Types
|
@@ -112,7 +112,7 @@ module Dry
|
|
112
112
|
# @raise CoercionError
|
113
113
|
#
|
114
114
|
# @api public
|
115
|
-
def self.to_decimal(input, &
|
115
|
+
def self.to_decimal(input, &_block)
|
116
116
|
to_float(input) do
|
117
117
|
if block_given?
|
118
118
|
return yield
|
data/lib/dry/types/compiler.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
|
@@ -63,37 +63,37 @@ module Dry
|
|
63
63
|
def visit_array(node)
|
64
64
|
member, meta = node
|
65
65
|
member = member.is_a?(Class) ? member : visit(member)
|
66
|
-
registry[
|
66
|
+
registry["nominal.array"].of(member).meta(meta)
|
67
67
|
end
|
68
68
|
|
69
69
|
def visit_hash(node)
|
70
70
|
opts, meta = node
|
71
|
-
registry[
|
71
|
+
registry["nominal.hash"].with(**opts, meta: meta)
|
72
72
|
end
|
73
73
|
|
74
74
|
def visit_schema(node)
|
75
75
|
keys, options, meta = node
|
76
|
-
registry[
|
76
|
+
registry["nominal.hash"].schema(keys.map { |key| visit(key) }).with(**options, meta: meta)
|
77
77
|
end
|
78
78
|
|
79
79
|
def visit_json_hash(node)
|
80
80
|
keys, meta = node
|
81
|
-
registry[
|
81
|
+
registry["json.hash"].schema(keys.map { |key| visit(key) }, meta)
|
82
82
|
end
|
83
83
|
|
84
84
|
def visit_json_array(node)
|
85
85
|
member, meta = node
|
86
|
-
registry[
|
86
|
+
registry["json.array"].of(visit(member)).meta(meta)
|
87
87
|
end
|
88
88
|
|
89
89
|
def visit_params_hash(node)
|
90
90
|
keys, meta = node
|
91
|
-
registry[
|
91
|
+
registry["params.hash"].schema(keys.map { |key| visit(key) }, meta)
|
92
92
|
end
|
93
93
|
|
94
94
|
def visit_params_array(node)
|
95
95
|
member, meta = node
|
96
|
-
registry[
|
96
|
+
registry["params.array"].of(visit(member)).meta(meta)
|
97
97
|
end
|
98
98
|
|
99
99
|
def visit_key(node)
|
@@ -108,11 +108,11 @@ module Dry
|
|
108
108
|
|
109
109
|
def visit_map(node)
|
110
110
|
key_type, value_type, meta = node
|
111
|
-
registry[
|
111
|
+
registry["nominal.hash"].map(visit(key_type), visit(value_type)).meta(meta)
|
112
112
|
end
|
113
113
|
|
114
114
|
def visit_any(meta)
|
115
|
-
registry[
|
115
|
+
registry["any"].meta(meta)
|
116
116
|
end
|
117
117
|
|
118
118
|
def compile_fn(fn)
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "dry/types/decorator"
|
4
|
+
require "dry/types/constraints"
|
5
|
+
require "dry/types/constrained/coercible"
|
6
6
|
|
7
7
|
module Dry
|
8
8
|
module Types
|
@@ -29,11 +29,9 @@ module Dry
|
|
29
29
|
@rule = options.fetch(:rule)
|
30
30
|
end
|
31
31
|
|
32
|
-
# @api private
|
33
|
-
#
|
34
32
|
# @return [Object]
|
35
33
|
#
|
36
|
-
# @api
|
34
|
+
# @api private
|
37
35
|
def call_unsafe(input)
|
38
36
|
result = rule.(input)
|
39
37
|
|
@@ -44,11 +42,9 @@ module Dry
|
|
44
42
|
end
|
45
43
|
end
|
46
44
|
|
47
|
-
# @api private
|
48
|
-
#
|
49
45
|
# @return [Object]
|
50
46
|
#
|
51
|
-
# @api
|
47
|
+
# @api private
|
52
48
|
def call_safe(input, &block)
|
53
49
|
if rule[input]
|
54
50
|
type.call_safe(input, &block)
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "dry/logic/rule_compiler"
|
4
|
+
require "dry/logic/predicates"
|
5
|
+
require "dry/logic/rule/predicate"
|
6
6
|
|
7
7
|
module Dry
|
8
8
|
# Helper methods for constraint types
|
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "dry/types/fn_container"
|
4
|
+
require "dry/types/constructor/function"
|
5
|
+
require "dry/types/constructor/wrapper"
|
5
6
|
|
6
7
|
module Dry
|
7
8
|
module Types
|
@@ -30,6 +31,32 @@ module Dry
|
|
30
31
|
super(type, **options, fn: Function[options.fetch(:fn, block)])
|
31
32
|
end
|
32
33
|
|
34
|
+
# @param [Builder, Object] input
|
35
|
+
# @param [Hash] options
|
36
|
+
# @param [#call, nil] block
|
37
|
+
#
|
38
|
+
# @api public
|
39
|
+
def self.[](type, fn:, **options)
|
40
|
+
function = Function[fn]
|
41
|
+
|
42
|
+
if function.wrapper?
|
43
|
+
wrapper_type.new(type, fn: function, **options)
|
44
|
+
else
|
45
|
+
new(type, fn: function, **options)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @api private
|
50
|
+
def self.wrapper_type
|
51
|
+
@wrapper_type ||= begin
|
52
|
+
if self < Wrapper
|
53
|
+
self
|
54
|
+
else
|
55
|
+
const_set(:Wrapping, ::Class.new(self).include(Wrapper))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
33
60
|
# Instantiate a new constructor type instance
|
34
61
|
#
|
35
62
|
# @param [Type] type
|
@@ -85,7 +112,13 @@ module Dry
|
|
85
112
|
#
|
86
113
|
# @api public
|
87
114
|
def constructor(new_fn = nil, **options, &block)
|
88
|
-
|
115
|
+
next_fn = Function[new_fn || block]
|
116
|
+
|
117
|
+
if next_fn.wrapper?
|
118
|
+
self.class.wrapper_type.new(with(**options), fn: next_fn)
|
119
|
+
else
|
120
|
+
with(**options, fn: fn >> next_fn)
|
121
|
+
end
|
89
122
|
end
|
90
123
|
alias_method :append, :constructor
|
91
124
|
alias_method :>>, :constructor
|
@@ -123,7 +156,7 @@ module Dry
|
|
123
156
|
# @return [Lax]
|
124
157
|
# @api public
|
125
158
|
def lax
|
126
|
-
Lax.new(
|
159
|
+
Lax.new(constructor_type[type.lax, **options])
|
127
160
|
end
|
128
161
|
|
129
162
|
# Wrap the type with a proc
|
@@ -157,8 +190,8 @@ module Dry
|
|
157
190
|
if type.respond_to?(method)
|
158
191
|
response = type.public_send(method, *args, &block)
|
159
192
|
|
160
|
-
if response.is_a?(Type) && type.class
|
161
|
-
response.constructor_type
|
193
|
+
if response.is_a?(Type) && type.class.equal?(response.class)
|
194
|
+
response.constructor_type[response, **options]
|
162
195
|
else
|
163
196
|
response
|
164
197
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "concurrent/map"
|
4
4
|
|
5
5
|
module Dry
|
6
6
|
module Types
|
@@ -34,6 +34,10 @@ module Dry
|
|
34
34
|
if public
|
35
35
|
::Class.new(PublicCall) do
|
36
36
|
include PublicCall.call_interface(method, safe)
|
37
|
+
|
38
|
+
define_method(:__to_s__) do
|
39
|
+
"#<PublicCall for :#{method}>"
|
40
|
+
end
|
37
41
|
end
|
38
42
|
elsif safe
|
39
43
|
PrivateCall
|
@@ -116,15 +120,31 @@ module Dry
|
|
116
120
|
end
|
117
121
|
end
|
118
122
|
|
123
|
+
class Wrapper < Function
|
124
|
+
# @return [Object]
|
125
|
+
def call(input, type, &block)
|
126
|
+
@fn.(input, type, &block)
|
127
|
+
rescue ::NoMethodError, ::TypeError, ::ArgumentError => e
|
128
|
+
CoercionError.handle(e, &block)
|
129
|
+
end
|
130
|
+
alias_method :[], :call
|
131
|
+
|
132
|
+
def arity
|
133
|
+
2
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
119
137
|
# Choose or build specialized invokation code for a callable
|
120
138
|
#
|
121
139
|
# @param [#call] fn
|
122
140
|
# @return [Function]
|
123
141
|
def self.[](fn)
|
124
|
-
raise ::ArgumentError,
|
142
|
+
raise ::ArgumentError, "Missing constructor block" if fn.nil?
|
125
143
|
|
126
144
|
if fn.is_a?(Function)
|
127
145
|
fn
|
146
|
+
elsif fn.respond_to?(:arity) && fn.arity.equal?(2)
|
147
|
+
Wrapper.new(fn)
|
128
148
|
elsif fn.is_a?(::Method)
|
129
149
|
MethodCall[fn, yields_block?(fn)]
|
130
150
|
elsif yields_block?(fn)
|
@@ -160,6 +180,15 @@ module Dry
|
|
160
180
|
end
|
161
181
|
alias_method :[], :call
|
162
182
|
|
183
|
+
# @return [Integer]
|
184
|
+
def arity
|
185
|
+
1
|
186
|
+
end
|
187
|
+
|
188
|
+
def wrapper?
|
189
|
+
arity.equal?(2)
|
190
|
+
end
|
191
|
+
|
163
192
|
# @return [Array]
|
164
193
|
def to_ast
|
165
194
|
if fn.is_a?(::Proc)
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
module Types
|
5
|
+
# @api public
|
6
|
+
class Constructor < Nominal
|
7
|
+
module Wrapper
|
8
|
+
# @return [Object]
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
def call_safe(input, &block)
|
12
|
+
fn.(input, type, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Object]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
def call_unsafe(input)
|
19
|
+
fn.(input, type)
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param [Object] input
|
23
|
+
# @param [#call,nil] block
|
24
|
+
#
|
25
|
+
# @return [Logic::Result, Types::Result]
|
26
|
+
# @return [Object] if block given and try fails
|
27
|
+
#
|
28
|
+
# @api public
|
29
|
+
def try(input, &block)
|
30
|
+
value = fn.(input, type)
|
31
|
+
rescue CoercionError => e
|
32
|
+
failure = failure(input, e)
|
33
|
+
block_given? ? yield(failure) : failure
|
34
|
+
else
|
35
|
+
type.try(value, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Define a constructor for the type
|
39
|
+
#
|
40
|
+
# @param [#call,nil] constructor
|
41
|
+
# @param [Hash] options
|
42
|
+
# @param [#call,nil] block
|
43
|
+
#
|
44
|
+
# @return [Constructor]
|
45
|
+
#
|
46
|
+
# @api public
|
47
|
+
define_method(:constructor, Builder.instance_method(:constructor))
|
48
|
+
alias_method :append, :constructor
|
49
|
+
alias_method :>>, :constructor
|
50
|
+
|
51
|
+
# Build a new constructor by prepending a block to the coercion function
|
52
|
+
#
|
53
|
+
# @param [#call, nil] new_fn
|
54
|
+
# @param [Hash] options
|
55
|
+
# @param [#call, nil] block
|
56
|
+
#
|
57
|
+
# @return [Constructor]
|
58
|
+
#
|
59
|
+
# @api public
|
60
|
+
def prepend(new_fn = nil, **options, &block)
|
61
|
+
prep_fn = Function[new_fn || block]
|
62
|
+
|
63
|
+
decorated =
|
64
|
+
if prep_fn.wrapper?
|
65
|
+
type.constructor(prep_fn, **options)
|
66
|
+
else
|
67
|
+
type.prepend(prep_fn, **options)
|
68
|
+
end
|
69
|
+
|
70
|
+
__new__(decorated)
|
71
|
+
end
|
72
|
+
alias_method :<<, :prepend
|
73
|
+
|
74
|
+
# @return [Constructor]
|
75
|
+
#
|
76
|
+
# @api public
|
77
|
+
def lax
|
78
|
+
# return self back because wrapping function
|
79
|
+
# can handle failed type check
|
80
|
+
self
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
# Replace underlying type
|
86
|
+
#
|
87
|
+
# @api private
|
88
|
+
def __new__(type)
|
89
|
+
self.class.new(type, *@__args__.drop(1), **@options)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/lib/dry/types/container.rb
CHANGED
data/lib/dry/types/core.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/types/any"
|
4
4
|
|
5
5
|
module Dry
|
6
6
|
module Types
|
@@ -83,17 +83,17 @@ module Dry
|
|
83
83
|
end
|
84
84
|
|
85
85
|
# Register `:bool` since it's common and not a built-in Ruby type :(
|
86
|
-
register(
|
87
|
-
bool = self[
|
88
|
-
register(
|
89
|
-
register(
|
90
|
-
|
91
|
-
register(
|
92
|
-
register(
|
93
|
-
register(
|
86
|
+
register("nominal.bool", self["nominal.true"] | self["nominal.false"])
|
87
|
+
bool = self["strict.true"] | self["strict.false"]
|
88
|
+
register("strict.bool", bool)
|
89
|
+
register("bool", bool)
|
90
|
+
|
91
|
+
register("any", Any)
|
92
|
+
register("nominal.any", Any)
|
93
|
+
register("strict.any", Any)
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
|
-
require
|
98
|
-
require
|
99
|
-
require
|
97
|
+
require "dry/types/coercions"
|
98
|
+
require "dry/types/params"
|
99
|
+
require "dry/types/json"
|
data/lib/dry/types/decorator.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/types/options"
|
4
4
|
|
5
5
|
module Dry
|
6
6
|
module Types
|
@@ -100,7 +100,7 @@ module Dry
|
|
100
100
|
#
|
101
101
|
# @api private
|
102
102
|
def __new__(type)
|
103
|
-
self.class.new(type, *@__args__
|
103
|
+
self.class.new(type, *@__args__.drop(1), **@options)
|
104
104
|
end
|
105
105
|
end
|
106
106
|
end
|