dry-types 0.13.2 → 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 +763 -233
- data/LICENSE +17 -17
- data/README.md +15 -13
- data/dry-types.gemspec +28 -28
- data/lib/dry-types.rb +3 -1
- data/lib/dry/types.rb +156 -76
- data/lib/dry/types/any.rb +32 -12
- data/lib/dry/types/array.rb +19 -6
- data/lib/dry/types/array/constructor.rb +32 -0
- data/lib/dry/types/array/member.rb +75 -16
- data/lib/dry/types/builder.rb +131 -15
- data/lib/dry/types/builder_methods.rb +49 -20
- data/lib/dry/types/coercions.rb +76 -22
- data/lib/dry/types/coercions/json.rb +43 -7
- data/lib/dry/types/coercions/params.rb +118 -31
- data/lib/dry/types/compat.rb +0 -2
- data/lib/dry/types/compiler.rb +56 -41
- data/lib/dry/types/constrained.rb +81 -32
- data/lib/dry/types/constrained/coercible.rb +36 -6
- data/lib/dry/types/constraints.rb +18 -4
- data/lib/dry/types/constructor.rb +127 -54
- data/lib/dry/types/constructor/function.rb +216 -0
- data/lib/dry/types/constructor/wrapper.rb +94 -0
- data/lib/dry/types/container.rb +7 -0
- data/lib/dry/types/core.rb +54 -21
- data/lib/dry/types/decorator.rb +38 -17
- data/lib/dry/types/default.rb +61 -16
- data/lib/dry/types/enum.rb +43 -20
- data/lib/dry/types/errors.rb +75 -9
- data/lib/dry/types/extensions.rb +7 -1
- data/lib/dry/types/extensions/maybe.rb +74 -16
- data/lib/dry/types/extensions/monads.rb +29 -0
- data/lib/dry/types/fn_container.rb +6 -1
- data/lib/dry/types/hash.rb +86 -67
- data/lib/dry/types/hash/constructor.rb +33 -0
- 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 +76 -33
- data/lib/dry/types/meta.rb +51 -0
- data/lib/dry/types/module.rb +120 -0
- data/lib/dry/types/nominal.rb +210 -0
- data/lib/dry/types/options.rb +13 -26
- 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 +16 -0
- data/lib/dry/types/printer.rb +315 -0
- data/lib/dry/types/result.rb +29 -3
- data/lib/dry/types/schema.rb +408 -0
- data/lib/dry/types/schema/key.rb +156 -0
- data/lib/dry/types/spec/types.rb +103 -33
- data/lib/dry/types/sum.rb +84 -35
- data/lib/dry/types/type.rb +49 -0
- data/lib/dry/types/version.rb +3 -1
- metadata +68 -79
- data/.gitignore +0 -10
- data/.rspec +0 -2
- data/.travis.yml +0 -29
- data/.yardopts +0 -5
- data/CONTRIBUTING.md +0 -29
- data/Gemfile +0 -24
- data/Rakefile +0 -20
- data/benchmarks/hash_schemas.rb +0 -51
- data/lib/dry/types/compat/form_types.rb +0 -27
- data/lib/dry/types/compat/int.rb +0 -14
- data/lib/dry/types/definition.rb +0 -113
- data/lib/dry/types/hash/schema.rb +0 -199
- data/lib/dry/types/hash/schema_builder.rb +0 -75
- data/lib/dry/types/safe.rb +0 -59
@@ -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
|
data/lib/dry/types/container.rb
CHANGED
data/lib/dry/types/core.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/types/any"
|
2
4
|
|
3
5
|
module Dry
|
4
6
|
module Types
|
5
|
-
|
7
|
+
# Primitives with {Kernel} coercion methods
|
8
|
+
KERNEL_COERCIBLE = {
|
6
9
|
string: String,
|
7
10
|
integer: Integer,
|
8
11
|
float: Float,
|
@@ -11,9 +14,19 @@ module Dry
|
|
11
14
|
hash: ::Hash
|
12
15
|
}.freeze
|
13
16
|
|
17
|
+
# Primitives with coercions through by convention `to_*` methods
|
18
|
+
METHOD_COERCIBLE = {
|
19
|
+
symbol: Symbol
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
# By convention methods to coerce {METHOD_COERCIBLE} primitives
|
23
|
+
METHOD_COERCIBLE_METHODS = {
|
24
|
+
symbol: :to_sym
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
# Primitives that are non-coercible
|
14
28
|
NON_COERCIBLE = {
|
15
29
|
nil: NilClass,
|
16
|
-
symbol: Symbol,
|
17
30
|
class: Class,
|
18
31
|
true: TrueClass,
|
19
32
|
false: FalseClass,
|
@@ -23,44 +36,64 @@ module Dry
|
|
23
36
|
range: Range
|
24
37
|
}.freeze
|
25
38
|
|
26
|
-
|
39
|
+
# All built-in primitives
|
40
|
+
ALL_PRIMITIVES = [KERNEL_COERCIBLE, METHOD_COERCIBLE, NON_COERCIBLE].reduce(&:merge).freeze
|
41
|
+
|
42
|
+
# All coercible types
|
43
|
+
COERCIBLE = KERNEL_COERCIBLE.merge(METHOD_COERCIBLE).freeze
|
27
44
|
|
45
|
+
# All built-in primitives except {NilClass}
|
28
46
|
NON_NIL = ALL_PRIMITIVES.reject { |name, _| name == :nil }.freeze
|
29
47
|
|
30
|
-
# Register
|
48
|
+
# Register generic types for {ALL_PRIMITIVES}
|
31
49
|
ALL_PRIMITIVES.each do |name, primitive|
|
32
|
-
|
50
|
+
type = Nominal[primitive].new(primitive)
|
51
|
+
register("nominal.#{name}", type)
|
33
52
|
end
|
34
53
|
|
35
|
-
# Register strict
|
54
|
+
# Register strict types for {ALL_PRIMITIVES}
|
36
55
|
ALL_PRIMITIVES.each do |name, primitive|
|
37
|
-
|
56
|
+
type = self["nominal.#{name}"].constrained(type: primitive)
|
57
|
+
register(name.to_s, type)
|
58
|
+
register("strict.#{name}", type)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Register {KERNEL_COERCIBLE} types
|
62
|
+
KERNEL_COERCIBLE.each do |name, primitive|
|
63
|
+
register("coercible.#{name}", self["nominal.#{name}"].constructor(Kernel.method(primitive.name)))
|
38
64
|
end
|
39
65
|
|
40
|
-
# Register
|
41
|
-
|
42
|
-
register(
|
66
|
+
# Register {METHOD_COERCIBLE} types
|
67
|
+
METHOD_COERCIBLE.each_key do |name|
|
68
|
+
register(
|
69
|
+
"coercible.#{name}", self["nominal.#{name}"].constructor(&METHOD_COERCIBLE_METHODS[name])
|
70
|
+
)
|
43
71
|
end
|
44
72
|
|
45
|
-
# Register
|
73
|
+
# Register optional strict {NON_NIL} types
|
46
74
|
NON_NIL.each_key do |name|
|
47
|
-
|
75
|
+
type = self[name.to_s].optional
|
76
|
+
register("optional.strict.#{name}", type)
|
77
|
+
register("optional.#{name}", type)
|
48
78
|
end
|
49
79
|
|
50
|
-
# Register
|
80
|
+
# Register optional {COERCIBLE} types
|
51
81
|
COERCIBLE.each_key do |name|
|
52
82
|
register("optional.coercible.#{name}", self["coercible.#{name}"].optional)
|
53
83
|
end
|
54
84
|
|
55
|
-
# Register
|
56
|
-
register("bool", self["true"] | self["false"])
|
57
|
-
|
85
|
+
# Register `:bool` since it's common and not a built-in Ruby type :(
|
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)
|
58
90
|
|
59
91
|
register("any", Any)
|
60
|
-
register("
|
92
|
+
register("nominal.any", Any)
|
93
|
+
register("strict.any", Any)
|
61
94
|
end
|
62
95
|
end
|
63
96
|
|
64
|
-
require
|
65
|
-
require
|
66
|
-
require
|
97
|
+
require "dry/types/coercions"
|
98
|
+
require "dry/types/params"
|
99
|
+
require "dry/types/json"
|
data/lib/dry/types/decorator.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/types/options"
|
2
4
|
|
3
5
|
module Dry
|
4
6
|
module Types
|
7
|
+
# Common API for types
|
8
|
+
#
|
9
|
+
# @api public
|
5
10
|
module Decorator
|
6
11
|
include Options
|
7
12
|
|
@@ -9,63 +14,76 @@ module Dry
|
|
9
14
|
attr_reader :type
|
10
15
|
|
11
16
|
# @param [Type] type
|
12
|
-
def initialize(type,
|
17
|
+
def initialize(type, *, **)
|
13
18
|
super
|
14
19
|
@type = type
|
15
20
|
end
|
16
21
|
|
17
22
|
# @param [Object] input
|
18
23
|
# @param [#call, nil] block
|
24
|
+
#
|
19
25
|
# @return [Result,Logic::Result]
|
20
26
|
# @return [Object] if block given and try fails
|
27
|
+
#
|
28
|
+
# @api public
|
21
29
|
def try(input, &block)
|
22
30
|
type.try(input, &block)
|
23
31
|
end
|
24
32
|
|
25
|
-
# @param [Object] value
|
26
|
-
# @return [Boolean]
|
27
|
-
def valid?(value)
|
28
|
-
type.valid?(value)
|
29
|
-
end
|
30
|
-
alias_method :===, :valid?
|
31
|
-
|
32
33
|
# @return [Boolean]
|
34
|
+
#
|
35
|
+
# @api public
|
33
36
|
def default?
|
34
37
|
type.default?
|
35
38
|
end
|
36
39
|
|
37
40
|
# @return [Boolean]
|
41
|
+
#
|
42
|
+
# @api public
|
38
43
|
def constrained?
|
39
44
|
type.constrained?
|
40
45
|
end
|
41
46
|
|
42
|
-
# @return [Sum]
|
43
|
-
def optional
|
44
|
-
Types['strict.nil'] | self
|
45
|
-
end
|
46
|
-
|
47
47
|
# @param [Symbol] meth
|
48
48
|
# @param [Boolean] include_private
|
49
|
+
#
|
49
50
|
# @return [Boolean]
|
51
|
+
#
|
52
|
+
# @api public
|
50
53
|
def respond_to_missing?(meth, include_private = false)
|
51
54
|
super || type.respond_to?(meth)
|
52
55
|
end
|
53
56
|
|
57
|
+
# Wrap the type with a proc
|
58
|
+
#
|
59
|
+
# @return [Proc]
|
60
|
+
#
|
61
|
+
# @api public
|
62
|
+
def to_proc
|
63
|
+
proc { |value| self.(value) }
|
64
|
+
end
|
65
|
+
|
54
66
|
private
|
55
67
|
|
56
68
|
# @param [Object] response
|
69
|
+
#
|
57
70
|
# @return [Boolean]
|
71
|
+
#
|
72
|
+
# @api private
|
58
73
|
def decorate?(response)
|
59
|
-
response.
|
74
|
+
response.is_a?(type.class)
|
60
75
|
end
|
61
76
|
|
62
77
|
# Delegates missing methods to {#type}
|
78
|
+
#
|
63
79
|
# @param [Symbol] meth
|
64
80
|
# @param [Array] args
|
65
81
|
# @param [#call, nil] block
|
82
|
+
#
|
83
|
+
# @api private
|
66
84
|
def method_missing(meth, *args, &block)
|
67
85
|
if type.respond_to?(meth)
|
68
|
-
response = type.
|
86
|
+
response = type.public_send(meth, *args, &block)
|
69
87
|
|
70
88
|
if decorate?(response)
|
71
89
|
__new__(response)
|
@@ -76,10 +94,13 @@ module Dry
|
|
76
94
|
super
|
77
95
|
end
|
78
96
|
end
|
97
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
79
98
|
|
80
99
|
# Replace underlying type
|
100
|
+
#
|
101
|
+
# @api private
|
81
102
|
def __new__(type)
|
82
|
-
self.class.new(type, options)
|
103
|
+
self.class.new(type, *@__args__.drop(1), **@options)
|
83
104
|
end
|
84
105
|
end
|
85
106
|
end
|