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
@@ -1,37 +1,46 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
class
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
require "dry/monads/constants"
|
4
|
+
|
5
|
+
module Dry
|
6
|
+
module Monads
|
7
|
+
class Result
|
8
|
+
# @see Monads#Result
|
9
|
+
# @private
|
10
|
+
class Fixed < ::Module
|
11
|
+
def self.[](error, **options)
|
12
|
+
new(error, **options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(error, **_options)
|
16
|
+
super()
|
11
17
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
@mod = ::Module.new do
|
19
|
+
define_method(:Failure) do |value|
|
20
|
+
if error === value
|
21
|
+
Failure.new(value, RightBiased::Left.trace_caller)
|
22
|
+
else
|
23
|
+
# rubocop:disable Style/RaiseArgs
|
24
|
+
# per https://github.com/dry-rb/dry-monads/pull/142
|
25
|
+
raise InvalidFailureTypeError.new(value)
|
26
|
+
# rubocop:enable Style/RaiseArgs
|
27
|
+
end
|
19
28
|
end
|
20
|
-
end
|
21
29
|
|
22
|
-
|
23
|
-
|
24
|
-
|
30
|
+
def Success(value = Undefined, &block)
|
31
|
+
v = Undefined.default(value, block || Unit)
|
32
|
+
Success.new(v)
|
33
|
+
end
|
25
34
|
end
|
26
35
|
end
|
27
|
-
end
|
28
36
|
|
29
|
-
|
37
|
+
private
|
30
38
|
|
31
|
-
|
32
|
-
|
39
|
+
def included(base)
|
40
|
+
super
|
33
41
|
|
34
|
-
|
42
|
+
base.include(@mod)
|
43
|
+
end
|
35
44
|
end
|
36
45
|
end
|
37
46
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
3
|
+
require "dry/monads/constants"
|
4
|
+
require "dry/monads/unit"
|
5
|
+
require "dry/monads/curry"
|
6
|
+
require "dry/monads/errors"
|
7
7
|
|
8
8
|
module Dry
|
9
9
|
module Monads
|
@@ -12,7 +12,7 @@ module Dry
|
|
12
12
|
# Right part
|
13
13
|
#
|
14
14
|
# @api public
|
15
|
-
module Right
|
15
|
+
module Right # rubocop:disable Metrics/ModuleLength
|
16
16
|
# @private
|
17
17
|
def self.included(m)
|
18
18
|
super
|
@@ -90,6 +90,16 @@ module Dry
|
|
90
90
|
self
|
91
91
|
end
|
92
92
|
|
93
|
+
# Ignores arguments and returns self. It exists to keep the interface
|
94
|
+
# identical to that of {RightBiased::Left}.
|
95
|
+
#
|
96
|
+
# @param _alt [RightBiased::Right, RightBiased::Left]
|
97
|
+
#
|
98
|
+
# @return [RightBiased::Right]
|
99
|
+
def |(_alt)
|
100
|
+
self
|
101
|
+
end
|
102
|
+
|
93
103
|
# A lifted version of `#or`. For {RightBiased::Right} acts in the same way as `#or`,
|
94
104
|
# that is returns itselt.
|
95
105
|
#
|
@@ -118,18 +128,18 @@ module Dry
|
|
118
128
|
# create_user.apply(name) # => Failure(:name_missing)
|
119
129
|
#
|
120
130
|
# @return [RightBiased::Left,RightBiased::Right]
|
121
|
-
def apply(val = Undefined)
|
131
|
+
def apply(val = Undefined, &block)
|
122
132
|
unless @value.respond_to?(:call)
|
123
133
|
raise TypeError, "Cannot apply #{val.inspect} to #{@value.inspect}"
|
124
134
|
end
|
125
135
|
|
126
|
-
Undefined.default(val)
|
136
|
+
Undefined.default(val, &block).fmap { |unwrapped| curry.(unwrapped) }
|
127
137
|
end
|
128
138
|
|
129
139
|
# @param other [Object]
|
130
140
|
# @return [Boolean]
|
131
141
|
def ===(other)
|
132
|
-
self.class
|
142
|
+
other.instance_of?(self.class) && value! === other.value!
|
133
143
|
end
|
134
144
|
|
135
145
|
# Maps the value to Dry::Monads::Unit, useful when you don't care
|
@@ -197,11 +207,11 @@ module Dry
|
|
197
207
|
# @api private
|
198
208
|
def deconstruct
|
199
209
|
if Unit.equal?(@value)
|
200
|
-
|
201
|
-
elsif
|
202
|
-
@value
|
203
|
-
else
|
210
|
+
EMPTY_ARRAY
|
211
|
+
elsif !@value.is_a?(::Array)
|
204
212
|
[@value]
|
213
|
+
else
|
214
|
+
@value
|
205
215
|
end
|
206
216
|
end
|
207
217
|
|
@@ -226,7 +236,7 @@ module Dry
|
|
226
236
|
|
227
237
|
private
|
228
238
|
|
229
|
-
if RUBY_VERSION >=
|
239
|
+
if RUBY_VERSION >= "2.7"
|
230
240
|
# @api private
|
231
241
|
def destructure(value)
|
232
242
|
if value.is_a?(::Hash)
|
@@ -255,7 +265,7 @@ module Dry
|
|
255
265
|
# @private
|
256
266
|
# @return [String] Caller location
|
257
267
|
def self.trace_caller
|
258
|
-
caller_locations(2,
|
268
|
+
caller_locations(2, 1)[0].to_s
|
259
269
|
end
|
260
270
|
|
261
271
|
# Raises an error on accessing internal value
|
@@ -299,11 +309,20 @@ module Dry
|
|
299
309
|
raise NotImplementedError
|
300
310
|
end
|
301
311
|
|
312
|
+
# Returns the passed value. Works in pair with {RightBiased::Right#|}.
|
313
|
+
#
|
314
|
+
# @param alt [RightBiased::Right, RightBiased::Left]
|
315
|
+
#
|
316
|
+
# @return [RightBiased::Right, RightBiased::Left]
|
317
|
+
def |(alt)
|
318
|
+
self.or(alt)
|
319
|
+
end
|
320
|
+
|
302
321
|
# A lifted version of `#or`. This is basically `#or` + `#fmap`.
|
303
322
|
#
|
304
323
|
# @example
|
305
|
-
# Dry::Monads.None.
|
306
|
-
# Dry::Monads.None.
|
324
|
+
# Dry::Monads.None.or_fmap('no value') # => Some("no value")
|
325
|
+
# Dry::Monads.None.or_fmap { Time.now } # => Some(current time)
|
307
326
|
#
|
308
327
|
# @return [RightBiased::Left, RightBiased::Right]
|
309
328
|
def or_fmap(*)
|
data/lib/dry/monads/task.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "concurrent/promise"
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
5
|
+
require "dry/monads/unit"
|
6
|
+
require "dry/monads/curry"
|
7
|
+
require "dry/monads/conversion_stubs"
|
8
8
|
|
9
9
|
module Dry
|
10
10
|
module Monads
|
@@ -48,9 +48,11 @@ module Dry
|
|
48
48
|
# @example using a predefined executor
|
49
49
|
# Task[:fast] { do_quick_task }
|
50
50
|
#
|
51
|
-
# @param executor [Concurrent::AbstractExecutorService,Symbol]
|
52
|
-
#
|
53
|
-
#
|
51
|
+
# @param executor [Concurrent::AbstractExecutorService,Symbol]
|
52
|
+
# Either an executor instance
|
53
|
+
# or a name of predefined global
|
54
|
+
# from concurrent-ruby
|
55
|
+
#
|
54
56
|
# @return [Task]
|
55
57
|
def [](executor, &block)
|
56
58
|
new(Promise.execute(executor: executor, &block))
|
@@ -131,14 +133,14 @@ module Dry
|
|
131
133
|
state = case promise.state
|
132
134
|
when :fulfilled
|
133
135
|
if Unit.equal?(value!)
|
134
|
-
|
136
|
+
"value=()"
|
135
137
|
else
|
136
138
|
"value=#{value!.inspect}"
|
137
139
|
end
|
138
140
|
when :rejected
|
139
141
|
"error=#{promise.reason.inspect}"
|
140
142
|
else
|
141
|
-
|
143
|
+
"?"
|
142
144
|
end
|
143
145
|
|
144
146
|
"Task(#{state})"
|
@@ -164,14 +166,12 @@ module Dry
|
|
164
166
|
)
|
165
167
|
|
166
168
|
promise.on_error do |v|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
child.on_reject(e)
|
174
|
-
end
|
169
|
+
inner = block.(v).promise
|
170
|
+
inner.execute
|
171
|
+
inner.on_success { |r| child.on_fulfill(r) }
|
172
|
+
inner.on_error { |e| child.on_reject(e) }
|
173
|
+
rescue StandardError => e
|
174
|
+
child.on_reject(e)
|
175
175
|
end
|
176
176
|
promise.on_success { |v| child.on_fulfill(v) }
|
177
177
|
|
@@ -236,8 +236,8 @@ module Dry
|
|
236
236
|
#
|
237
237
|
# @param val [Task]
|
238
238
|
# @return [Task]
|
239
|
-
def apply(val = Undefined)
|
240
|
-
arg = Undefined.default(val)
|
239
|
+
def apply(val = Undefined, &block)
|
240
|
+
arg = Undefined.default(val, &block)
|
241
241
|
bind { |f| arg.fmap { |v| curry(f).(v) } }
|
242
242
|
end
|
243
243
|
|
@@ -314,7 +314,7 @@ module Dry
|
|
314
314
|
end
|
315
315
|
end
|
316
316
|
|
317
|
-
require
|
317
|
+
require "dry/monads/registry"
|
318
318
|
register_mixin(:task, Task::Mixin)
|
319
319
|
end
|
320
320
|
end
|
@@ -27,7 +27,8 @@ module Dry
|
|
27
27
|
# Lifts a block/proc over the 3-level nested structure.
|
28
28
|
#
|
29
29
|
# @example
|
30
|
-
# List[Right(Some(1)), Left(Some(1))].fmap3 { |x| x + 1 }
|
30
|
+
# List[Right(Some(1)), Left(Some(1))].fmap3 { |x| x + 1 }
|
31
|
+
# # => List[Right(Some(2)), Left(Some(1))]
|
31
32
|
# Right(None).fmap3 { |x| x + 1 } # => Right(None)
|
32
33
|
#
|
33
34
|
# @param args [Array<Object>] arguments will be passed to the block or the proc
|
data/lib/dry/monads/traverse.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
# rubocop:disable Naming/ConstantName
|
4
|
+
# rubocop:disable Style/MutableConstant
|
5
|
+
|
6
|
+
require "dry/monads/validated"
|
4
7
|
|
5
8
|
module Dry
|
6
9
|
module Monads
|
@@ -20,3 +23,6 @@ module Dry
|
|
20
23
|
Traverse.freeze
|
21
24
|
end
|
22
25
|
end
|
26
|
+
|
27
|
+
# rubocop:enable Style/MutableConstant
|
28
|
+
# rubocop:enable Naming/ConstantName
|
data/lib/dry/monads/try.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "dry/core/equalizer"
|
4
|
+
require "dry/core/deprecations"
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
6
|
+
require "dry/monads/right_biased"
|
7
|
+
require "dry/monads/conversion_stubs"
|
8
8
|
|
9
9
|
module Dry
|
10
10
|
module Monads
|
@@ -22,7 +22,7 @@ module Dry
|
|
22
22
|
attr_reader :exception
|
23
23
|
|
24
24
|
class << self
|
25
|
-
extend Core::Deprecations[:
|
25
|
+
extend Core::Deprecations[:"dry-monads"]
|
26
26
|
|
27
27
|
# Invokes a callable and if successful stores the result in the
|
28
28
|
# {Try::Value} type, but if one of the specified exceptions was raised it stores
|
@@ -72,7 +72,7 @@ module Dry
|
|
72
72
|
# @param exceptions [Array<Exception>]
|
73
73
|
# @return [Try::Value,Try::Error]
|
74
74
|
def [](*exceptions, &block)
|
75
|
-
raise ArgumentError,
|
75
|
+
raise ArgumentError, "At least one exception type required" if exceptions.empty?
|
76
76
|
|
77
77
|
run(exceptions, block)
|
78
78
|
end
|
@@ -92,7 +92,7 @@ module Dry
|
|
92
92
|
|
93
93
|
# Returns self.
|
94
94
|
#
|
95
|
-
# @return [
|
95
|
+
# @return [Try::Value, Try::Error]
|
96
96
|
def to_monad
|
97
97
|
self
|
98
98
|
end
|
@@ -110,6 +110,8 @@ module Dry
|
|
110
110
|
# @param exceptions [Array<Exception>] list of exceptions to be rescued
|
111
111
|
# @param value [Object] the value to be stored in the monad
|
112
112
|
def initialize(exceptions, value)
|
113
|
+
super()
|
114
|
+
|
113
115
|
@catchable = exceptions
|
114
116
|
@value = value
|
115
117
|
end
|
@@ -160,12 +162,21 @@ module Dry
|
|
160
162
|
# @return [String]
|
161
163
|
def to_s
|
162
164
|
if Unit.equal?(@value)
|
163
|
-
|
165
|
+
"Try::Value()"
|
164
166
|
else
|
165
167
|
"Try::Value(#{@value.inspect})"
|
166
168
|
end
|
167
169
|
end
|
168
170
|
alias_method :inspect, :to_s
|
171
|
+
|
172
|
+
# Ignores values and returns self, see {Try::Error#recover}
|
173
|
+
#
|
174
|
+
# @param errors [Class] List of Exception subclasses
|
175
|
+
#
|
176
|
+
# @return [Try::Value]
|
177
|
+
def recover(*_errors)
|
178
|
+
self
|
179
|
+
end
|
169
180
|
end
|
170
181
|
|
171
182
|
# Represents a result of a failed execution.
|
@@ -179,6 +190,8 @@ module Dry
|
|
179
190
|
|
180
191
|
# @param exception [Exception]
|
181
192
|
def initialize(exception)
|
193
|
+
super()
|
194
|
+
|
182
195
|
@exception = exception
|
183
196
|
end
|
184
197
|
|
@@ -211,6 +224,26 @@ module Dry
|
|
211
224
|
def ===(other)
|
212
225
|
Error === other && exception === other.exception
|
213
226
|
end
|
227
|
+
|
228
|
+
# Acts in a similar way to `rescue`. It checks if
|
229
|
+
# {exception} is one of {errors} and yields the block if so.
|
230
|
+
#
|
231
|
+
# @param errors [Class] List of Exception subclasses
|
232
|
+
#
|
233
|
+
# @return [Try::Value]
|
234
|
+
def recover(*errors)
|
235
|
+
if errors.empty?
|
236
|
+
classes = DEFAULT_EXCEPTIONS
|
237
|
+
else
|
238
|
+
classes = errors
|
239
|
+
end
|
240
|
+
|
241
|
+
if classes.any? { |c| c === exception }
|
242
|
+
Value.new([exception.class], yield(exception))
|
243
|
+
else
|
244
|
+
self
|
245
|
+
end
|
246
|
+
end
|
214
247
|
end
|
215
248
|
|
216
249
|
# A module that can be included for easier access to Try monads.
|
@@ -261,9 +294,9 @@ module Dry
|
|
261
294
|
#
|
262
295
|
def Value(value = Undefined, exceptions = DEFAULT_EXCEPTIONS, &block)
|
263
296
|
v = Undefined.default(value, block)
|
264
|
-
raise ArgumentError,
|
297
|
+
raise ArgumentError, "No value given" if !value.nil? && v.nil?
|
265
298
|
|
266
|
-
Value.new(exceptions, v)
|
299
|
+
Try::Value.new(exceptions, v)
|
267
300
|
end
|
268
301
|
|
269
302
|
# Error constructor
|
@@ -278,14 +311,14 @@ module Dry
|
|
278
311
|
#
|
279
312
|
def Error(error = Undefined, &block)
|
280
313
|
v = Undefined.default(error, block)
|
281
|
-
raise ArgumentError,
|
314
|
+
raise ArgumentError, "No value given" if v.nil?
|
282
315
|
|
283
316
|
Try::Error.new(v)
|
284
317
|
end
|
285
318
|
end
|
286
319
|
end
|
287
320
|
|
288
|
-
require
|
321
|
+
require "dry/monads/registry"
|
289
322
|
register_mixin(:try, Try::Mixin)
|
290
323
|
end
|
291
324
|
end
|
data/lib/dry/monads/unit.rb
CHANGED