dry-monads 1.3.5 → 1.4.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 +140 -80
- data/LICENSE +1 -1
- data/README.md +5 -4
- data/dry-monads.gemspec +30 -30
- data/lib/dry-monads.rb +1 -1
- data/lib/dry/monads.rb +2 -2
- data/lib/dry/monads/all.rb +2 -2
- data/lib/dry/monads/constants.rb +1 -1
- data/lib/dry/monads/do.rb +52 -18
- data/lib/dry/monads/do/all.rb +36 -17
- data/lib/dry/monads/either.rb +7 -7
- data/lib/dry/monads/errors.rb +5 -2
- data/lib/dry/monads/lazy.rb +15 -4
- data/lib/dry/monads/list.rb +28 -28
- data/lib/dry/monads/maybe.rb +87 -19
- data/lib/dry/monads/registry.rb +10 -10
- data/lib/dry/monads/result.rb +38 -12
- data/lib/dry/monads/result/fixed.rb +33 -24
- data/lib/dry/monads/right_biased.rb +35 -16
- data/lib/dry/monads/task.rb +20 -20
- data/lib/dry/monads/transformer.rb +2 -1
- data/lib/dry/monads/traverse.rb +7 -1
- data/lib/dry/monads/try.rb +45 -12
- data/lib/dry/monads/unit.rb +6 -2
- data/lib/dry/monads/validated.rb +20 -16
- data/lib/dry/monads/version.rb +1 -1
- data/lib/json/add/dry/monads/maybe.rb +3 -3
- metadata +18 -69
- 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 -30
- data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
- data/.github/workflows/ci.yml +0 -52
- data/.github/workflows/docsite.yml +0 -34
- data/.github/workflows/sync_configs.yml +0 -56
- data/.gitignore +0 -10
- data/.rspec +0 -4
- data/.rubocop.yml +0 -101
- data/.yardopts +0 -4
- data/CODE_OF_CONDUCT.md +0 -13
- data/CONTRIBUTING.md +0 -29
- data/Gemfile +0 -19
- data/Gemfile.devtools +0 -14
- data/Rakefile +0 -8
- data/bin/.gitkeep +0 -0
- data/bin/console +0 -17
- data/bin/setup +0 -7
- data/docsite/source/case-equality.html.md +0 -42
- data/docsite/source/do-notation.html.md +0 -207
- data/docsite/source/getting-started.html.md +0 -142
- data/docsite/source/index.html.md +0 -179
- data/docsite/source/list.html.md +0 -87
- data/docsite/source/maybe.html.md +0 -146
- data/docsite/source/pattern-matching.html.md +0 -68
- data/docsite/source/result.html.md +0 -190
- data/docsite/source/task.html.md +0 -126
- data/docsite/source/tracing-failures.html.md +0 -32
- data/docsite/source/try.html.md +0 -76
- data/docsite/source/unit.html.md +0 -36
- data/docsite/source/validated.html.md +0 -88
- data/log/.gitkeep +0 -0
- data/project.yml +0 -2
data/lib/dry/monads/list.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/core/equalizer"
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
5
|
+
require "dry/monads/maybe"
|
6
|
+
require "dry/monads/task"
|
7
|
+
require "dry/monads/result"
|
8
|
+
require "dry/monads/try"
|
9
|
+
require "dry/monads/validated"
|
10
|
+
require "dry/monads/transformer"
|
11
|
+
require "dry/monads/curry"
|
12
12
|
|
13
13
|
module Dry
|
14
14
|
module Monads
|
@@ -83,7 +83,7 @@ module Dry
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
-
extend Dry::Core::Deprecations[:
|
86
|
+
extend Dry::Core::Deprecations[:"dry-monads"]
|
87
87
|
|
88
88
|
include Dry::Equalizer(:value, :type)
|
89
89
|
include Transformer
|
@@ -136,14 +136,14 @@ module Dry
|
|
136
136
|
end
|
137
137
|
|
138
138
|
# Maps a block over the list. Acts as `Array#map`.
|
139
|
-
#
|
139
|
+
# If called without a block, this method returns an enumerator, not a List
|
140
140
|
#
|
141
141
|
# @return [List,Enumerator]
|
142
142
|
def map(&block)
|
143
|
-
if
|
143
|
+
if block_given?
|
144
144
|
fmap(block)
|
145
145
|
else
|
146
|
-
value.map
|
146
|
+
value.map
|
147
147
|
end
|
148
148
|
end
|
149
149
|
|
@@ -165,7 +165,7 @@ module Dry
|
|
165
165
|
#
|
166
166
|
# @return [String]
|
167
167
|
def inspect
|
168
|
-
type_ann = typed? ? "<#{type.name.split(
|
168
|
+
type_ann = typed? ? "<#{type.name.split("::").last}>" : ""
|
169
169
|
"List#{type_ann}#{value.inspect}"
|
170
170
|
end
|
171
171
|
alias_method :to_s, :inspect
|
@@ -192,8 +192,8 @@ module Dry
|
|
192
192
|
#
|
193
193
|
# @param initial [Object] Initial value
|
194
194
|
# @return [Object]
|
195
|
-
def fold_left(initial)
|
196
|
-
value.reduce(initial
|
195
|
+
def fold_left(initial, &block)
|
196
|
+
value.reduce(initial, &block)
|
197
197
|
end
|
198
198
|
alias_method :foldl, :fold_left
|
199
199
|
alias_method :reduce, :fold_left
|
@@ -224,8 +224,8 @@ module Dry
|
|
224
224
|
# Filters elements with a block
|
225
225
|
#
|
226
226
|
# @return [List]
|
227
|
-
def filter
|
228
|
-
coerce(value.select
|
227
|
+
def filter(&block)
|
228
|
+
coerce(value.select(&block))
|
229
229
|
end
|
230
230
|
alias_method :select, :filter
|
231
231
|
|
@@ -265,10 +265,10 @@ module Dry
|
|
265
265
|
def typed(type = nil)
|
266
266
|
if type.nil?
|
267
267
|
if size.zero?
|
268
|
-
raise ArgumentError,
|
268
|
+
raise ArgumentError, "Cannot infer a monad for an empty list"
|
269
269
|
else
|
270
270
|
self.class.warn(
|
271
|
-
|
271
|
+
"Automatic monad inference is deprecated, pass a type explicitly "\
|
272
272
|
"or use a predefined constant, e.g. List::Result\n"\
|
273
273
|
"#{caller.find { |l| l !~ %r{(lib/dry/monads)|(gems)} }}"
|
274
274
|
)
|
@@ -298,7 +298,7 @@ module Dry
|
|
298
298
|
# @return [Monad] Result is a monadic value
|
299
299
|
def traverse(proc = nil, &block)
|
300
300
|
unless typed?
|
301
|
-
raise StandardError,
|
301
|
+
raise StandardError, "Cannot traverse an untyped list"
|
302
302
|
end
|
303
303
|
|
304
304
|
cons = type.pure { |list, i| list + List.pure(i) }
|
@@ -315,8 +315,8 @@ module Dry
|
|
315
315
|
#
|
316
316
|
# @param list [List]
|
317
317
|
# @return [List]
|
318
|
-
def apply(list = Undefined)
|
319
|
-
v = Undefined.default(list)
|
318
|
+
def apply(list = Undefined, &block)
|
319
|
+
v = Undefined.default(list, &block)
|
320
320
|
fmap(Curry).bind { |f| v.fmap { |x| f.(x) } }
|
321
321
|
end
|
322
322
|
|
@@ -329,7 +329,7 @@ module Dry
|
|
329
329
|
|
330
330
|
# Returns self.
|
331
331
|
#
|
332
|
-
# @return [
|
332
|
+
# @return [List]
|
333
333
|
def to_monad
|
334
334
|
self
|
335
335
|
end
|
@@ -345,7 +345,7 @@ module Dry
|
|
345
345
|
# Some(n / divisor)
|
346
346
|
# end
|
347
347
|
# end
|
348
|
-
# # => List[
|
348
|
+
# # => List[2, 4]
|
349
349
|
#
|
350
350
|
# @example without block
|
351
351
|
# List[Some(5), None(), Some(3)].collect.map { |x| x * 2 }
|
@@ -422,10 +422,10 @@ module Dry
|
|
422
422
|
# List of results
|
423
423
|
Result = ListBuilder[Result]
|
424
424
|
|
425
|
-
# List of
|
425
|
+
# List of maybes
|
426
426
|
Maybe = ListBuilder[Maybe]
|
427
427
|
|
428
|
-
# List of
|
428
|
+
# List of tries
|
429
429
|
Try = ListBuilder[Try]
|
430
430
|
|
431
431
|
# List of validation results
|
@@ -449,9 +449,9 @@ module Dry
|
|
449
449
|
end
|
450
450
|
end
|
451
451
|
|
452
|
-
require
|
452
|
+
require "dry/monads/registry"
|
453
453
|
register_mixin(:list, List::Mixin)
|
454
454
|
end
|
455
455
|
end
|
456
456
|
|
457
|
-
require
|
457
|
+
require "dry/monads/traverse"
|
data/lib/dry/monads/maybe.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "dry/core/equalizer"
|
4
|
+
require "dry/core/deprecations"
|
5
|
+
require "dry/core/class_attributes"
|
5
6
|
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
7
|
+
require "dry/monads/right_biased"
|
8
|
+
require "dry/monads/transformer"
|
9
|
+
require "dry/monads/unit"
|
10
|
+
require "dry/monads/constants"
|
10
11
|
|
11
12
|
module Dry
|
12
13
|
module Monads
|
@@ -15,9 +16,13 @@ module Dry
|
|
15
16
|
# @api public
|
16
17
|
class Maybe
|
17
18
|
include Transformer
|
19
|
+
extend Core::ClassAttributes
|
20
|
+
|
21
|
+
defines :warn_on_implicit_nil_coercion
|
22
|
+
warn_on_implicit_nil_coercion true
|
18
23
|
|
19
24
|
class << self
|
20
|
-
extend Core::Deprecations[:
|
25
|
+
extend Core::Deprecations[:"dry-monads"]
|
21
26
|
|
22
27
|
# Wraps the given value with into a Maybe object.
|
23
28
|
#
|
@@ -105,7 +110,9 @@ module Dry
|
|
105
110
|
end
|
106
111
|
|
107
112
|
def initialize(value = Undefined)
|
108
|
-
raise ArgumentError,
|
113
|
+
raise ArgumentError, "nil cannot be some" if value.nil?
|
114
|
+
|
115
|
+
super()
|
109
116
|
|
110
117
|
@value = Undefined.default(value, Unit)
|
111
118
|
end
|
@@ -121,14 +128,65 @@ module Dry
|
|
121
128
|
# @return [Maybe::Some, Maybe::None] Wrapped result, i.e. nil will be mapped to None,
|
122
129
|
# other values will be wrapped with Some
|
123
130
|
def fmap(*args, &block)
|
131
|
+
next_value = bind(*args, &block)
|
132
|
+
|
133
|
+
if next_value.nil?
|
134
|
+
if self.class.warn_on_implicit_nil_coercion
|
135
|
+
Core::Deprecations.warn(
|
136
|
+
"Block passed to Some#fmap returned `nil` and was chained to None. "\
|
137
|
+
"This is literally an unlawful behavior and it will not be supported in "\
|
138
|
+
"dry-monads 2. \nPlease, replace `.fmap` with `.maybe` in places where you "\
|
139
|
+
"expect `nil` as block result.\n"\
|
140
|
+
"You can opt out of these warnings with\n"\
|
141
|
+
"Dry::Monads::Maybe.warn_on_implicit_nil_coercion false",
|
142
|
+
uplevel: 0,
|
143
|
+
tag: :'dry-monads'
|
144
|
+
)
|
145
|
+
end
|
146
|
+
Monads.None()
|
147
|
+
else
|
148
|
+
Some.new(next_value)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Does the same thing as #bind except it also wraps the value
|
153
|
+
# in an instance of the Maybe monad. This allows for easier
|
154
|
+
# chaining of calls.
|
155
|
+
#
|
156
|
+
# @example
|
157
|
+
# Dry::Monads.Some(4).maybe(&:succ).maybe(->(n) { n**2 }) # => Some(25)
|
158
|
+
# Dry::Monads.Some(4).maybe(&:succ).maybe(->(_) { nil }) # => None()
|
159
|
+
#
|
160
|
+
# @param args [Array<Object>] arguments will be transparently passed through to #bind
|
161
|
+
# @return [Maybe::Some, Maybe::None] Wrapped result, i.e. nil will be mapped to None,
|
162
|
+
# other values will be wrapped with Some
|
163
|
+
def maybe(*args, &block)
|
124
164
|
Maybe.coerce(bind(*args, &block))
|
125
165
|
end
|
126
|
-
|
166
|
+
|
167
|
+
# Accepts a block and runs it against the wrapped value.
|
168
|
+
# If the block returns a trurhy value the result is self,
|
169
|
+
# otherwise None. If no block is given, the value serves
|
170
|
+
# and its result.
|
171
|
+
#
|
172
|
+
# @param with [#call] positional block
|
173
|
+
# @param block [Proc] block
|
174
|
+
#
|
175
|
+
# @return [Maybe::None, Maybe::Some]
|
176
|
+
def filter(with = Undefined, &block)
|
177
|
+
block = Undefined.default(with, block || IDENTITY)
|
178
|
+
|
179
|
+
if block.(@value)
|
180
|
+
self
|
181
|
+
else
|
182
|
+
Monads.None()
|
183
|
+
end
|
184
|
+
end
|
127
185
|
|
128
186
|
# @return [String]
|
129
187
|
def to_s
|
130
188
|
if Unit.equal?(@value)
|
131
|
-
|
189
|
+
"Some()"
|
132
190
|
else
|
133
191
|
"Some(#{@value.inspect})"
|
134
192
|
end
|
@@ -146,7 +204,7 @@ module Dry
|
|
146
204
|
singleton_class.send(:attr_reader, :instance)
|
147
205
|
|
148
206
|
# @api private
|
149
|
-
def self.method_missing(m, *)
|
207
|
+
def self.method_missing(m, *) # rubocop:disable Style/MissingRespondToMissing
|
150
208
|
if (instance.methods(true) - methods(true)).include?(m)
|
151
209
|
raise ConstructorNotAppliedError.new(m, :None)
|
152
210
|
else
|
@@ -161,6 +219,7 @@ module Dry
|
|
161
219
|
attr_reader :trace
|
162
220
|
|
163
221
|
def initialize(trace = RightBiased::Left.trace_caller)
|
222
|
+
super()
|
164
223
|
@trace = trace
|
165
224
|
end
|
166
225
|
|
@@ -202,7 +261,7 @@ module Dry
|
|
202
261
|
|
203
262
|
# @return [String]
|
204
263
|
def to_s
|
205
|
-
|
264
|
+
"None"
|
206
265
|
end
|
207
266
|
alias_method :inspect, :to_s
|
208
267
|
|
@@ -230,6 +289,13 @@ module Dry
|
|
230
289
|
def deconstruct
|
231
290
|
EMPTY_ARRAY
|
232
291
|
end
|
292
|
+
|
293
|
+
# @see Maybe::Some#filter
|
294
|
+
#
|
295
|
+
# @return [Maybe::None]
|
296
|
+
def filter(_ = Undefined)
|
297
|
+
self
|
298
|
+
end
|
233
299
|
end
|
234
300
|
|
235
301
|
# A module that can be included for easier access to Maybe monads.
|
@@ -301,9 +367,9 @@ module Dry
|
|
301
367
|
# None values are removed
|
302
368
|
#
|
303
369
|
# @example
|
304
|
-
# Maybe::Hash.filter(foo: Some(1), bar: Some(2)) # =>
|
305
|
-
# Maybe::Hash.filter(foo: Some(1), bar: None()) # =>
|
306
|
-
# Maybe::Hash.filter(foo: None(), bar: Some(2)) # =>
|
370
|
+
# Maybe::Hash.filter(foo: Some(1), bar: Some(2)) # => { foo: 1, bar: 2 }
|
371
|
+
# Maybe::Hash.filter(foo: Some(1), bar: None()) # => { foo: 1 }
|
372
|
+
# Maybe::Hash.filter(foo: None(), bar: Some(2)) # => { bar: 2 }
|
307
373
|
#
|
308
374
|
# @param hash [::Hash<Object,Maybe>]
|
309
375
|
# @return [::Hash]
|
@@ -325,10 +391,12 @@ module Dry
|
|
325
391
|
|
326
392
|
class Result
|
327
393
|
class Success < Result
|
328
|
-
|
394
|
+
extend Core::Deprecations[:"dry-monads"]
|
395
|
+
|
396
|
+
# @return [Maybe]
|
329
397
|
def to_maybe
|
330
|
-
|
331
|
-
Dry::Monads::Maybe(@value)
|
398
|
+
warn "Success(nil) transformed to None" if @value.nil?
|
399
|
+
::Dry::Monads::Maybe(@value)
|
332
400
|
end
|
333
401
|
end
|
334
402
|
|
@@ -389,7 +457,7 @@ module Dry
|
|
389
457
|
end
|
390
458
|
end
|
391
459
|
|
392
|
-
require
|
460
|
+
require "dry/monads/registry"
|
393
461
|
register_mixin(:maybe, Maybe::Mixin)
|
394
462
|
end
|
395
463
|
end
|
data/lib/dry/monads/registry.rb
CHANGED
@@ -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
|
# Common, idiomatic monads for Ruby
|
@@ -10,16 +10,16 @@ module Dry
|
|
10
10
|
@registry = {}
|
11
11
|
@constructors = nil
|
12
12
|
@paths = {
|
13
|
-
do:
|
14
|
-
lazy:
|
15
|
-
list:
|
16
|
-
maybe:
|
17
|
-
task:
|
18
|
-
try:
|
19
|
-
validated:
|
13
|
+
do: "dry/monads/do/all",
|
14
|
+
lazy: "dry/monads/lazy",
|
15
|
+
list: "dry/monads/list",
|
16
|
+
maybe: "dry/monads/maybe",
|
17
|
+
task: "dry/monads/task",
|
18
|
+
try: "dry/monads/try",
|
19
|
+
validated: "dry/monads/validated",
|
20
20
|
result: [
|
21
|
-
|
22
|
-
|
21
|
+
"dry/monads/result",
|
22
|
+
"dry/monads/result/fixed"
|
23
23
|
]
|
24
24
|
}.freeze
|
25
25
|
@mixins = Concurrent::Map.new
|
data/lib/dry/monads/result.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/core/equalizer"
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
5
|
+
require "dry/monads/constants"
|
6
|
+
require "dry/monads/right_biased"
|
7
|
+
require "dry/monads/transformer"
|
8
|
+
require "dry/monads/conversion_stubs"
|
9
|
+
require "dry/monads/unit"
|
10
10
|
|
11
11
|
module Dry
|
12
12
|
module Monads
|
@@ -86,6 +86,7 @@ module Dry
|
|
86
86
|
|
87
87
|
# @param value [Object] a value of a successful operation
|
88
88
|
def initialize(value)
|
89
|
+
super()
|
89
90
|
@value = value
|
90
91
|
end
|
91
92
|
|
@@ -134,7 +135,7 @@ module Dry
|
|
134
135
|
# @return [String]
|
135
136
|
def to_s
|
136
137
|
if Unit.equal?(@value)
|
137
|
-
|
138
|
+
"Success()"
|
138
139
|
else
|
139
140
|
"Success(#{@value.inspect})"
|
140
141
|
end
|
@@ -147,6 +148,13 @@ module Dry
|
|
147
148
|
def flip
|
148
149
|
Failure.new(@value, RightBiased::Left.trace_caller)
|
149
150
|
end
|
151
|
+
|
152
|
+
# Ignores values and returns self, see {Failure#alt_map}
|
153
|
+
#
|
154
|
+
# @return [Result::Success]
|
155
|
+
def alt_map(_ = nil)
|
156
|
+
self
|
157
|
+
end
|
150
158
|
end
|
151
159
|
|
152
160
|
# Represents a value of a failed operation.
|
@@ -188,6 +196,7 @@ module Dry
|
|
188
196
|
# @param value [Object] failure value
|
189
197
|
# @param trace [String] caller line
|
190
198
|
def initialize(value, trace = RightBiased::Left.trace_caller)
|
199
|
+
super()
|
191
200
|
@value = value
|
192
201
|
@trace = trace
|
193
202
|
end
|
@@ -218,7 +227,8 @@ module Dry
|
|
218
227
|
# otherwise simply returns the first argument.
|
219
228
|
#
|
220
229
|
# @example
|
221
|
-
# Dry::Monads.Failure(ArgumentError.new('error message')).or(&:message)
|
230
|
+
# Dry::Monads.Failure(ArgumentError.new('error message')).or(&:message)
|
231
|
+
# # => "error message"
|
222
232
|
#
|
223
233
|
# @param args [Array<Object>] arguments that will be passed to a block
|
224
234
|
# if one was given, otherwise the first
|
@@ -232,7 +242,8 @@ module Dry
|
|
232
242
|
end
|
233
243
|
end
|
234
244
|
|
235
|
-
# A lifted version of `#or`. Wraps the passed value or the block
|
245
|
+
# A lifted version of `#or`. Wraps the passed value or the block
|
246
|
+
# result with Result::Success.
|
236
247
|
#
|
237
248
|
# @example
|
238
249
|
# Dry::Monads.Failure.new('no value').or_fmap('value') # => Success("value")
|
@@ -247,7 +258,7 @@ module Dry
|
|
247
258
|
# @return [String]
|
248
259
|
def to_s
|
249
260
|
if Unit.equal?(@value)
|
250
|
-
|
261
|
+
"Failure()"
|
251
262
|
else
|
252
263
|
"Failure(#{@value.inspect})"
|
253
264
|
end
|
@@ -287,6 +298,21 @@ module Dry
|
|
287
298
|
def either(_, g)
|
288
299
|
g.(failure)
|
289
300
|
end
|
301
|
+
|
302
|
+
# Lifts a block/proc over Failure
|
303
|
+
#
|
304
|
+
# @overload alt_map(proc)
|
305
|
+
# @param proc [#call]
|
306
|
+
# @return [Result::Failure]
|
307
|
+
#
|
308
|
+
# @overload alt_map
|
309
|
+
# @param block [Proc]
|
310
|
+
# @return [Result::Failure]
|
311
|
+
#
|
312
|
+
def alt_map(proc = Undefined, &block)
|
313
|
+
f = Undefined.default(proc, block)
|
314
|
+
self.class.new(f.(failure), RightBiased::Left.trace_caller)
|
315
|
+
end
|
290
316
|
end
|
291
317
|
|
292
318
|
# A module that can be included for easier access to Result monads.
|
@@ -448,7 +474,7 @@ module Dry
|
|
448
474
|
end
|
449
475
|
|
450
476
|
class Invalid < Validated
|
451
|
-
#
|
477
|
+
# Converts to Result::Failure
|
452
478
|
#
|
453
479
|
# @return [Result::Failure]
|
454
480
|
def to_result
|
@@ -457,7 +483,7 @@ module Dry
|
|
457
483
|
end
|
458
484
|
end
|
459
485
|
|
460
|
-
require
|
486
|
+
require "dry/monads/registry"
|
461
487
|
register_mixin(:result, Result::Mixin)
|
462
488
|
end
|
463
489
|
end
|