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
@@ -1,12 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dry
|
2
4
|
module Types
|
3
5
|
class Constrained
|
6
|
+
# Common coercion-related API for constrained types
|
7
|
+
#
|
8
|
+
# @api public
|
4
9
|
class Coercible < Constrained
|
5
|
-
# @
|
6
|
-
#
|
7
|
-
# @
|
8
|
-
|
9
|
-
|
10
|
+
# @return [Object]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
def call_unsafe(input)
|
14
|
+
coerced = type.call_unsafe(input)
|
15
|
+
result = rule.(coerced)
|
16
|
+
|
17
|
+
if result.success?
|
18
|
+
coerced
|
19
|
+
else
|
20
|
+
raise ConstraintError.new(result, input)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Object]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
def call_safe(input)
|
28
|
+
coerced = type.call_safe(input) { return yield }
|
29
|
+
|
30
|
+
if rule[coerced]
|
31
|
+
coerced
|
32
|
+
else
|
33
|
+
yield(coerced)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @see Dry::Types::Constrained#try
|
38
|
+
#
|
39
|
+
# @api public
|
10
40
|
def try(input, &block)
|
11
41
|
result = type.try(input)
|
12
42
|
|
@@ -16,7 +46,7 @@ module Dry
|
|
16
46
|
if validation.success?
|
17
47
|
result
|
18
48
|
else
|
19
|
-
failure = failure(result.input, validation)
|
49
|
+
failure = failure(result.input, ConstraintError.new(validation, input))
|
20
50
|
block ? yield(failure) : failure
|
21
51
|
end
|
22
52
|
else
|
@@ -1,94 +1,142 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/equalizer"
|
4
|
+
require "dry/types/decorator"
|
5
|
+
require "dry/types/constraints"
|
6
|
+
require "dry/types/constrained/coercible"
|
4
7
|
|
5
8
|
module Dry
|
6
9
|
module Types
|
10
|
+
# Constrained types apply rules to the input
|
11
|
+
#
|
12
|
+
# @api public
|
7
13
|
class Constrained
|
8
14
|
include Type
|
9
15
|
include Decorator
|
10
16
|
include Builder
|
11
17
|
include Printable
|
12
|
-
include Dry::Equalizer(:type, :
|
18
|
+
include Dry::Equalizer(:type, :rule, inspect: false, immutable: true)
|
13
19
|
|
14
20
|
# @return [Dry::Logic::Rule]
|
15
21
|
attr_reader :rule
|
16
22
|
|
17
23
|
# @param [Type] type
|
24
|
+
#
|
18
25
|
# @param [Hash] options
|
19
|
-
|
26
|
+
#
|
27
|
+
# @api public
|
28
|
+
def initialize(type, **options)
|
20
29
|
super
|
21
30
|
@rule = options.fetch(:rule)
|
22
31
|
end
|
23
32
|
|
24
|
-
# @param [Object] input
|
25
33
|
# @return [Object]
|
26
|
-
#
|
27
|
-
|
28
|
-
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
def call_unsafe(input)
|
37
|
+
result = rule.(input)
|
38
|
+
|
39
|
+
if result.success?
|
40
|
+
type.call_unsafe(input)
|
41
|
+
else
|
29
42
|
raise ConstraintError.new(result, input)
|
30
|
-
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return [Object]
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
def call_safe(input, &block)
|
50
|
+
if rule[input]
|
51
|
+
type.call_safe(input, &block)
|
52
|
+
else
|
53
|
+
yield
|
54
|
+
end
|
31
55
|
end
|
32
|
-
|
33
|
-
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
# @
|
38
|
-
#
|
39
|
-
#
|
56
|
+
|
57
|
+
# Safe coercion attempt. It is similar to #call with a
|
58
|
+
# block given but returns a Result instance with metadata
|
59
|
+
# about errors (if any).
|
60
|
+
#
|
61
|
+
# @overload try(input)
|
62
|
+
# @param [Object] input
|
63
|
+
# @return [Logic::Result]
|
64
|
+
#
|
65
|
+
# @overload try(input)
|
66
|
+
# @param [Object] input
|
67
|
+
# @yieldparam [Failure] failure
|
68
|
+
# @yieldreturn [Object]
|
69
|
+
# @return [Object]
|
70
|
+
#
|
71
|
+
# @api public
|
40
72
|
def try(input, &block)
|
41
73
|
result = rule.(input)
|
42
74
|
|
43
75
|
if result.success?
|
44
76
|
type.try(input, &block)
|
45
77
|
else
|
46
|
-
failure = failure(input, result)
|
47
|
-
|
78
|
+
failure = failure(input, ConstraintError.new(result, input))
|
79
|
+
block_given? ? yield(failure) : failure
|
48
80
|
end
|
49
81
|
end
|
50
82
|
|
51
|
-
# @param [Object] value
|
52
|
-
# @return [Boolean]
|
53
|
-
def valid?(value)
|
54
|
-
rule.(value).success? && type.valid?(value)
|
55
|
-
end
|
56
|
-
|
57
83
|
# @param [Hash] options
|
58
84
|
# The options hash provided to {Types.Rule} and combined
|
59
85
|
# using {&} with previous {#rule}
|
86
|
+
#
|
60
87
|
# @return [Constrained]
|
88
|
+
#
|
61
89
|
# @see Dry::Logic::Operators#and
|
90
|
+
#
|
91
|
+
# @api public
|
62
92
|
def constrained(options)
|
63
93
|
with(rule: rule & Types.Rule(options))
|
64
94
|
end
|
65
95
|
|
66
96
|
# @return [true]
|
97
|
+
#
|
98
|
+
# @api public
|
67
99
|
def constrained?
|
68
100
|
true
|
69
101
|
end
|
70
102
|
|
71
103
|
# @param [Object] value
|
104
|
+
#
|
72
105
|
# @return [Boolean]
|
106
|
+
#
|
107
|
+
# @api public
|
73
108
|
def ===(value)
|
74
109
|
valid?(value)
|
75
110
|
end
|
76
111
|
|
77
|
-
#
|
112
|
+
# Build lax type. Constraints are not applicable to lax types hence unwrapping
|
78
113
|
#
|
114
|
+
# @return [Lax]
|
115
|
+
# @api public
|
116
|
+
def lax
|
117
|
+
type.lax
|
118
|
+
end
|
119
|
+
|
79
120
|
# @see Nominal#to_ast
|
121
|
+
# @api public
|
80
122
|
def to_ast(meta: true)
|
81
|
-
[:constrained, [type.to_ast(meta: meta),
|
82
|
-
|
83
|
-
|
123
|
+
[:constrained, [type.to_ast(meta: meta), rule.to_ast]]
|
124
|
+
end
|
125
|
+
|
126
|
+
# @api private
|
127
|
+
def constructor_type
|
128
|
+
type.constructor_type
|
84
129
|
end
|
85
130
|
|
86
131
|
private
|
87
132
|
|
88
133
|
# @param [Object] response
|
134
|
+
#
|
89
135
|
# @return [Boolean]
|
136
|
+
#
|
137
|
+
# @api private
|
90
138
|
def decorate?(response)
|
91
|
-
super || response.
|
139
|
+
super || response.is_a?(Constructor)
|
92
140
|
end
|
93
141
|
end
|
94
142
|
end
|
@@ -1,18 +1,32 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/logic/rule_compiler"
|
4
|
+
require "dry/logic/predicates"
|
5
|
+
require "dry/logic/rule/predicate"
|
4
6
|
|
5
7
|
module Dry
|
8
|
+
# Helper methods for constraint types
|
9
|
+
#
|
10
|
+
# @api public
|
6
11
|
module Types
|
7
12
|
# @param [Hash] options
|
13
|
+
#
|
8
14
|
# @return [Dry::Logic::Rule]
|
15
|
+
#
|
16
|
+
# @api public
|
9
17
|
def self.Rule(options)
|
10
18
|
rule_compiler.(
|
11
|
-
options.map { |key, val|
|
19
|
+
options.map { |key, val|
|
20
|
+
Logic::Rule::Predicate.build(
|
21
|
+
Logic::Predicates[:"#{key}?"]
|
22
|
+
).curry(val).to_ast
|
23
|
+
}
|
12
24
|
).reduce(:and)
|
13
25
|
end
|
14
26
|
|
15
27
|
# @return [Dry::Logic::RuleCompiler]
|
28
|
+
#
|
29
|
+
# @api private
|
16
30
|
def self.rule_compiler
|
17
31
|
@rule_compiler ||= Logic::RuleCompiler.new(Logic::Predicates)
|
18
32
|
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/equalizer"
|
4
|
+
require "concurrent/map"
|
5
|
+
|
6
|
+
module Dry
|
7
|
+
module Types
|
8
|
+
class Constructor < Nominal
|
9
|
+
# Function is used internally by Constructor types
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
class Function
|
13
|
+
# Wrapper for unsafe coercion functions
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
class Safe < Function
|
17
|
+
def call(input, &block)
|
18
|
+
@fn.(input, &block)
|
19
|
+
rescue ::NoMethodError, ::TypeError, ::ArgumentError => e
|
20
|
+
CoercionError.handle(e, &block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Coercion via a method call on a known object
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
class MethodCall < Function
|
28
|
+
@cache = ::Concurrent::Map.new
|
29
|
+
|
30
|
+
# Choose or build the base class
|
31
|
+
#
|
32
|
+
# @return [Function]
|
33
|
+
def self.call_class(method, public, safe)
|
34
|
+
@cache.fetch_or_store([method, public, safe]) do
|
35
|
+
if public
|
36
|
+
::Class.new(PublicCall) do
|
37
|
+
include PublicCall.call_interface(method, safe)
|
38
|
+
|
39
|
+
define_method(:__to_s__) do
|
40
|
+
"#<PublicCall for :#{method}>"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
elsif safe
|
44
|
+
PrivateCall
|
45
|
+
else
|
46
|
+
PrivateSafeCall
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Coercion with a publicly accessible method call
|
52
|
+
#
|
53
|
+
# @api private
|
54
|
+
class PublicCall < MethodCall
|
55
|
+
@interfaces = ::Concurrent::Map.new
|
56
|
+
|
57
|
+
# Choose or build the interface
|
58
|
+
#
|
59
|
+
# @return [::Module]
|
60
|
+
def self.call_interface(method, safe)
|
61
|
+
@interfaces.fetch_or_store([method, safe]) do
|
62
|
+
::Module.new do
|
63
|
+
if safe
|
64
|
+
module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
65
|
+
def call(input, &block)
|
66
|
+
@target.#{method}(input, &block)
|
67
|
+
end
|
68
|
+
RUBY
|
69
|
+
else
|
70
|
+
module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
71
|
+
def call(input, &block)
|
72
|
+
@target.#{method}(input)
|
73
|
+
rescue ::NoMethodError, ::TypeError, ::ArgumentError => error
|
74
|
+
CoercionError.handle(error, &block)
|
75
|
+
end
|
76
|
+
RUBY
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Coercion via a private method call
|
84
|
+
#
|
85
|
+
# @api private
|
86
|
+
class PrivateCall < MethodCall
|
87
|
+
def call(input, &block)
|
88
|
+
@target.send(@name, input, &block)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Coercion via an unsafe private method call
|
93
|
+
#
|
94
|
+
# @api private
|
95
|
+
class PrivateSafeCall < PrivateCall
|
96
|
+
def call(input, &block)
|
97
|
+
@target.send(@name, input)
|
98
|
+
rescue ::NoMethodError, ::TypeError, ::ArgumentError => e
|
99
|
+
CoercionError.handle(e, &block)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# @api private
|
104
|
+
#
|
105
|
+
# @return [MethodCall]
|
106
|
+
def self.[](fn, safe)
|
107
|
+
public = fn.receiver.respond_to?(fn.name)
|
108
|
+
MethodCall.call_class(fn.name, public, safe).new(fn)
|
109
|
+
end
|
110
|
+
|
111
|
+
attr_reader :target, :name
|
112
|
+
|
113
|
+
def initialize(fn)
|
114
|
+
super
|
115
|
+
@target = fn.receiver
|
116
|
+
@name = fn.name
|
117
|
+
end
|
118
|
+
|
119
|
+
def to_ast
|
120
|
+
[:method, target, name]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class Wrapper < Function
|
125
|
+
# @return [Object]
|
126
|
+
def call(input, type, &block)
|
127
|
+
@fn.(input, type, &block)
|
128
|
+
rescue ::NoMethodError, ::TypeError, ::ArgumentError => e
|
129
|
+
CoercionError.handle(e, &block)
|
130
|
+
end
|
131
|
+
alias_method :[], :call
|
132
|
+
|
133
|
+
def arity
|
134
|
+
2
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Choose or build specialized invokation code for a callable
|
139
|
+
#
|
140
|
+
# @param [#call] fn
|
141
|
+
# @return [Function]
|
142
|
+
def self.[](fn)
|
143
|
+
raise ::ArgumentError, "Missing constructor block" if fn.nil?
|
144
|
+
|
145
|
+
if fn.is_a?(Function)
|
146
|
+
fn
|
147
|
+
elsif fn.respond_to?(:arity) && fn.arity.equal?(2)
|
148
|
+
Wrapper.new(fn)
|
149
|
+
elsif fn.is_a?(::Method)
|
150
|
+
MethodCall[fn, yields_block?(fn)]
|
151
|
+
elsif yields_block?(fn)
|
152
|
+
new(fn)
|
153
|
+
else
|
154
|
+
Safe.new(fn)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# @return [Boolean]
|
159
|
+
def self.yields_block?(fn)
|
160
|
+
*, (last_arg,) =
|
161
|
+
if fn.respond_to?(:parameters)
|
162
|
+
fn.parameters
|
163
|
+
else
|
164
|
+
fn.method(:call).parameters
|
165
|
+
end
|
166
|
+
|
167
|
+
last_arg.equal?(:block)
|
168
|
+
end
|
169
|
+
|
170
|
+
include ::Dry::Equalizer(:fn, immutable: true)
|
171
|
+
|
172
|
+
attr_reader :fn
|
173
|
+
|
174
|
+
def initialize(fn)
|
175
|
+
@fn = fn
|
176
|
+
end
|
177
|
+
|
178
|
+
# @return [Object]
|
179
|
+
def call(input, &block)
|
180
|
+
@fn.(input, &block)
|
181
|
+
end
|
182
|
+
alias_method :[], :call
|
183
|
+
|
184
|
+
# @return [Integer]
|
185
|
+
def arity
|
186
|
+
1
|
187
|
+
end
|
188
|
+
|
189
|
+
def wrapper?
|
190
|
+
arity.equal?(2)
|
191
|
+
end
|
192
|
+
|
193
|
+
# @return [Array]
|
194
|
+
def to_ast
|
195
|
+
if fn.is_a?(::Proc)
|
196
|
+
[:id, FnContainer.register(fn)]
|
197
|
+
else
|
198
|
+
[:callable, fn]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# @return [Function]
|
203
|
+
def >>(other)
|
204
|
+
f = Function[other]
|
205
|
+
Function[-> x, &b { f.(self.(x, &b), &b) }]
|
206
|
+
end
|
207
|
+
|
208
|
+
# @return [Function]
|
209
|
+
def <<(other)
|
210
|
+
f = Function[other]
|
211
|
+
Function[-> x, &b { self.(f.(x, &b), &b) }]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
@@ -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
|