mona-result 0.1.1 → 0.2.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 +17 -1
- data/Gemfile.lock +4 -4
- data/README.md +33 -7
- data/Steepfile +1 -4
- data/lib/mona/result/action.rb +5 -1
- data/lib/mona/result/dict.rb +7 -6
- data/lib/mona/result/err.rb +10 -30
- data/lib/mona/result/error.rb +1 -0
- data/lib/mona/result/match.rb +6 -4
- data/lib/mona/result/ok.rb +7 -25
- data/lib/mona/result/sequence.rb +1 -1
- data/lib/mona/result.rb +6 -2
- data/lib/mona/resultable.rb +63 -0
- data/sig/mona.rbs +157 -0
- metadata +8 -8
- data/lib/mona/result/version.rb +0 -7
- data/sig/mona/result.rbs +0 -177
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11b851820d5a4a5558b4b9fca9ed4d473a4c7f41f76296e8304de95f319b4eac
|
4
|
+
data.tar.gz: e02cccae0cc5ddf02a7a8fd99d1f509be1148c9d41f39f28d545409da7906e05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b01676a3ec1acaa3541a3e60eeaacd82cfacdc81889bd7073e0824ee987ec89c01415b28ba1a72413a32d78d687d0ac1f0a5521a0933b4a1edae8fe0af6ce46
|
7
|
+
data.tar.gz: 66738db3e3571dd6c53982081acf787f634b5f7964a19a58649b513eeb5c3c169ac89bf25aa7fd9aaf951e25c83f9646314eab0d5b7b474f08efe3fe96adbe91
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,20 @@
|
|
1
|
-
## [0.
|
1
|
+
## [0.2.0] - 2022-08-23
|
2
|
+
|
3
|
+
- Adds Mona::Resultable module which implements the Result interface
|
4
|
+
- Simplify and improve RBS
|
5
|
+
- Steep checks tests in a stricter fashion
|
6
|
+
- Improve docs, tests, and rubocop
|
7
|
+
|
8
|
+
## [0.1.3] - 2022-08-09
|
9
|
+
|
10
|
+
- Fix CHANGELOG rubygems link
|
11
|
+
|
12
|
+
## [0.1.2] - 2022-08-09
|
13
|
+
|
14
|
+
- Fix gemspec links
|
15
|
+
- Improve documentation
|
16
|
+
|
17
|
+
## [0.1.1] - 2022-08-09
|
2
18
|
|
3
19
|
- Adds basic documentation
|
4
20
|
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
mona-result (0.
|
4
|
+
mona-result (0.2.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -21,7 +21,7 @@ GEM
|
|
21
21
|
listen (3.7.1)
|
22
22
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
23
23
|
rb-inotify (~> 0.9, >= 0.9.10)
|
24
|
-
minitest (5.16.
|
24
|
+
minitest (5.16.3)
|
25
25
|
parallel (1.22.1)
|
26
26
|
parser (3.1.2.1)
|
27
27
|
ast (~> 2.4.1)
|
@@ -33,14 +33,14 @@ GEM
|
|
33
33
|
rbs (2.6.0)
|
34
34
|
regexp_parser (2.5.0)
|
35
35
|
rexml (3.2.5)
|
36
|
-
rubocop (1.
|
36
|
+
rubocop (1.35.1)
|
37
37
|
json (~> 2.3)
|
38
38
|
parallel (~> 1.10)
|
39
39
|
parser (>= 3.1.2.1)
|
40
40
|
rainbow (>= 2.2.2, < 4.0)
|
41
41
|
regexp_parser (>= 1.8, < 3.0)
|
42
42
|
rexml (>= 3.2.5, < 4.0)
|
43
|
-
rubocop-ast (>= 1.20.
|
43
|
+
rubocop-ast (>= 1.20.1, < 2.0)
|
44
44
|
ruby-progressbar (~> 1.7)
|
45
45
|
unicode-display_width (>= 1.4.0, < 3.0)
|
46
46
|
rubocop-ast (1.21.0)
|
data/README.md
CHANGED
@@ -24,7 +24,10 @@ success = Result.ok(1) # => #<OK 1>
|
|
24
24
|
success.ok? # => true
|
25
25
|
success.err? # => false
|
26
26
|
success.value # => 1
|
27
|
-
|
27
|
+
|
28
|
+
success.and_tap { puts "it is #{_1}" }
|
29
|
+
.and_then { _1 * 5 }
|
30
|
+
.value_or { :nope }
|
28
31
|
# OUT: it is 1
|
29
32
|
# => 5
|
30
33
|
|
@@ -34,14 +37,23 @@ failure.ok? # => false
|
|
34
37
|
failure.err? # => true
|
35
38
|
failure.failure # => 4
|
36
39
|
failure.reason # => :not_prime
|
37
|
-
failure.and_tap { puts "it is #{_1}" }.and_then { _1 * 5 }.value_or { :nope } # => :nope
|
38
40
|
|
39
|
-
|
41
|
+
failure.and_tap { puts "it is #{_1}" }
|
42
|
+
.and_then { _1 * 5 }
|
43
|
+
.value_or { :nope }
|
44
|
+
# => :nope
|
45
|
+
|
46
|
+
# Dict with sequence, example using a fictional repository.
|
47
|
+
# #set can take a [Symbol, Symbol] key argument where left is OK key, right is Err key
|
40
48
|
result = Result.dict do |d|
|
41
|
-
d.set :
|
42
|
-
d.set :
|
43
|
-
d.set :
|
44
|
-
end
|
49
|
+
d.set :user, UserRepo.find user_id
|
50
|
+
d.set :input, PostInput.valid(attributes)
|
51
|
+
d.set [:post, :input], PostRepo.create user_id: user_id, **d[:input]
|
52
|
+
end
|
53
|
+
# if find user fails: # => #<Err {:user=>NotFoundError} reason: :not_found, key: :user>
|
54
|
+
# if validation fails: # => #<Err {:user=>User, :input=>PostInput(invalid)} reason: :invalid, key: :input>
|
55
|
+
# if create fails: # => #<Err {:user=>User, :input=>PostInput(db err)} reason: :db_err, key: :input>
|
56
|
+
# if all ok: # => #<OK: {:user=>User, :post=>Post}>
|
45
57
|
|
46
58
|
# Action - a callable sequence
|
47
59
|
divide = Result.action do |x, y|
|
@@ -78,6 +90,20 @@ in err:, reason:, **meta
|
|
78
90
|
end
|
79
91
|
```
|
80
92
|
|
93
|
+
You can also match a result, using similar semantics, the difference from using case/pattern-match is that a
|
94
|
+
`Mona::Result::NoMatchError` is raised, which keeps a reference to the result (which is useful for differentially
|
95
|
+
handling errors in an enclosing scope - not currently possible with ruby's `NoMatchingPatternError` which does not
|
96
|
+
contain any information about the failed match)
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
Mona::Result.match(result) do |on|
|
100
|
+
on.ok { |value| puts "ok" }
|
101
|
+
on.err(key: :x) { |failure, reason, **meta| puts "error with meta :key => :x" }
|
102
|
+
on.err(:invalid) { |failure, reason, **meta| puts "error with reason :invalid" }
|
103
|
+
on.err { |failure, reason, **meta| puts "error" }
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
81
107
|
## Development
|
82
108
|
|
83
109
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/Steepfile
CHANGED
@@ -6,18 +6,15 @@ target :lib do
|
|
6
6
|
signature "sig"
|
7
7
|
|
8
8
|
check "lib"
|
9
|
-
|
10
|
-
configure_code_diagnostics(D::Ruby.default)
|
11
9
|
end
|
12
10
|
|
13
11
|
target :test do
|
14
|
-
signature "sig"
|
12
|
+
signature "sig", "test/sig"
|
15
13
|
|
16
14
|
check "test"
|
17
15
|
|
18
16
|
library "minitest", "mutex_m"
|
19
17
|
|
20
|
-
configure_code_diagnostics(D::Ruby.strict)
|
21
18
|
configure_code_diagnostics do |h|
|
22
19
|
h[D::Ruby::UnsupportedSyntax] = :information
|
23
20
|
end
|
data/lib/mona/result/action.rb
CHANGED
@@ -68,14 +68,18 @@ module Mona
|
|
68
68
|
remove_instance_variable :@sequence
|
69
69
|
end
|
70
70
|
|
71
|
+
def perform(*args, **kwargs) = raise(NotImplementedError, "implement `perform'")
|
72
|
+
|
71
73
|
private
|
72
74
|
|
75
|
+
def get(key) = @sequence.fetch(key)
|
76
|
+
|
73
77
|
def set(key, value) = @sequence.set(key, value)
|
74
78
|
|
75
79
|
def respond_to_missing?(key, _include_private = false) = @sequence.key?(key)
|
76
80
|
|
77
81
|
def method_missing(key, *args)
|
78
|
-
return
|
82
|
+
return get(key) if args.empty? && @sequence.key?(key)
|
79
83
|
|
80
84
|
raise NoMethodError, "no method `#{key}' for #{self}"
|
81
85
|
end
|
data/lib/mona/result/dict.rb
CHANGED
@@ -5,7 +5,7 @@ module Mona
|
|
5
5
|
# Represents a dictionary of results, it is successful if all results are successful, and a failure if one
|
6
6
|
# is a failure. A Result::Dict can only contain one failure.
|
7
7
|
class Dict
|
8
|
-
# factory method that returns {Dict::
|
8
|
+
# factory method that returns {Dict::OK} or {Dict::Err}
|
9
9
|
def self.new(initial = {}, &block)
|
10
10
|
result = Dict::EMPTY
|
11
11
|
initial.each { |k, v| result = result.set(k, v) }
|
@@ -14,7 +14,7 @@ module Mona
|
|
14
14
|
end
|
15
15
|
|
16
16
|
# Dict read interface
|
17
|
-
module
|
17
|
+
module Read
|
18
18
|
def [](key) = to_h[key]
|
19
19
|
|
20
20
|
def key?(key) = to_h.key?(key)
|
@@ -24,15 +24,16 @@ module Mona
|
|
24
24
|
|
25
25
|
# OK dict result
|
26
26
|
class OK < Result::OK
|
27
|
-
include
|
27
|
+
include Read
|
28
28
|
|
29
29
|
def set(key, to_result)
|
30
30
|
key, failure_key = key if key.is_a?(Array)
|
31
31
|
failure_key ||= key
|
32
32
|
|
33
33
|
Result[to_result].either \
|
34
|
-
->(value)
|
35
|
-
|
34
|
+
->(value) { OK.new to_h.merge(key => value) },
|
35
|
+
# @type var meta: Hash[Symbol, untyped]
|
36
|
+
->(failure, reason, **meta) { Err.new to_h.merge(failure_key => failure), reason, **meta, key: failure_key }
|
36
37
|
end
|
37
38
|
|
38
39
|
def sequence(&) = Sequence.new(self).call(&)
|
@@ -42,7 +43,7 @@ module Mona
|
|
42
43
|
|
43
44
|
# Err dict result
|
44
45
|
class Err < Result::Err
|
45
|
-
include
|
46
|
+
include Read
|
46
47
|
|
47
48
|
def set(_key, _val) = raise(Error, "cannot #set on #{self}")
|
48
49
|
|
data/lib/mona/result/err.rb
CHANGED
@@ -4,45 +4,25 @@ module Mona
|
|
4
4
|
module Result
|
5
5
|
# A Error or failure result, with optional reason, and metadata
|
6
6
|
class Err
|
7
|
+
include Resultable
|
8
|
+
|
7
9
|
def initialize(failure, reason = nil, **meta)
|
8
|
-
raise ArgumentError, "meta can't contain :reason key" if meta.key?(:reason)
|
10
|
+
raise ArgumentError, "meta can't contain :reason or err: key" if meta.key?(:reason) || meta.key?(:err)
|
9
11
|
|
10
|
-
@failure = failure
|
11
|
-
@reason
|
12
|
-
@meta
|
12
|
+
@failure = failure
|
13
|
+
@reason = reason
|
14
|
+
@meta = meta
|
13
15
|
end
|
14
16
|
|
17
|
+
# @dynamic failure, reason, meta
|
15
18
|
attr_reader :failure, :reason, :meta
|
16
19
|
|
17
|
-
def ok? = false
|
18
|
-
|
19
|
-
def err? = true
|
20
|
-
|
21
|
-
def value_or(&) = yield
|
22
|
-
|
23
|
-
def ok(&) = nil
|
24
|
-
|
25
|
-
def err(&) = yield @failure, @reason, **@meta
|
26
|
-
|
27
20
|
def either(_ok, err) = err.call(@failure, @reason, **@meta)
|
28
21
|
|
29
|
-
def
|
30
|
-
|
31
|
-
def and_tap(&) = self
|
32
|
-
|
33
|
-
def or_else(&) = Result[yield @failure, @reason, **@meta]
|
34
|
-
|
35
|
-
def deconstruct = [:err, @failure, @reason, @meta]
|
36
|
-
|
37
|
-
def deconstruct_keys(_keys = nil) = { err: @failure, reason: @reason, **@meta }
|
38
|
-
|
39
|
-
def to_result = self
|
40
|
-
|
41
|
-
def to_s
|
42
|
-
"#<Err #{@failure.inspect} #{{ reason: @reason, **@meta }.map{ "#{_1}: #{_2.inspect}" }.join(", ")}>"
|
43
|
-
end
|
22
|
+
def inspect = "#<Err #{@failure} #{{ reason: @reason, **@meta }.map { "#{_1}: #{_2}" }.join(", ")}>"
|
44
23
|
|
45
|
-
|
24
|
+
# @dynamic to_s
|
25
|
+
alias to_s inspect
|
46
26
|
end
|
47
27
|
end
|
48
28
|
end
|
data/lib/mona/result/error.rb
CHANGED
data/lib/mona/result/match.rb
CHANGED
@@ -5,10 +5,11 @@ module Mona
|
|
5
5
|
# Use Match.call to respond to result success or failure
|
6
6
|
#
|
7
7
|
# Result::Match.call(result) do |r|
|
8
|
-
# r.ok
|
9
|
-
# r.err(
|
10
|
-
# r.err(
|
11
|
-
# r.err
|
8
|
+
# r.ok { |value| ... }
|
9
|
+
# r.err(reason, **meta) { |failure, reason, **meta| ... }
|
10
|
+
# r.err(**meta) { |failure, reason, **meta| ... }
|
11
|
+
# r.err(reason) { |failure, reason, **meta| ... }
|
12
|
+
# r.err { |failure, reason, **meta| ... }
|
12
13
|
# end
|
13
14
|
class Match
|
14
15
|
def self.call(result, &) = new(result).call(&)
|
@@ -33,6 +34,7 @@ module Mona
|
|
33
34
|
|
34
35
|
def err(match_reason = nil, **match_meta)
|
35
36
|
@result.or_else do |failure, reason, **meta|
|
37
|
+
# @type var meta: Hash[Symbol, untyped]
|
36
38
|
if match_reason?(match_reason, reason) && match_meta?(match_meta, meta)
|
37
39
|
throw @throw, yield(failure, reason, **meta)
|
38
40
|
end
|
data/lib/mona/result/ok.rb
CHANGED
@@ -4,39 +4,21 @@ module Mona
|
|
4
4
|
module Result
|
5
5
|
# A Successful (OK) result
|
6
6
|
class OK
|
7
|
+
include Resultable
|
8
|
+
|
7
9
|
def initialize(value)
|
8
|
-
@value = value
|
10
|
+
@value = value
|
9
11
|
end
|
10
12
|
|
13
|
+
# @dynamic value
|
11
14
|
attr_reader :value
|
12
15
|
|
13
|
-
def value_or(&) = @value
|
14
|
-
|
15
|
-
def ok? = true
|
16
|
-
|
17
|
-
def err? = false
|
18
|
-
|
19
|
-
def ok(&) = yield @value
|
20
|
-
|
21
|
-
def err(&) = nil
|
22
|
-
|
23
16
|
def either(ok, _err) = ok.call(@value)
|
24
17
|
|
25
|
-
def
|
26
|
-
|
27
|
-
def and_tap(&) = tap { yield @value }
|
28
|
-
|
29
|
-
def or_else(&) = self
|
30
|
-
|
31
|
-
def deconstruct = [:ok, @value]
|
32
|
-
|
33
|
-
def deconstruct_keys(_keys = nil) = { ok: @value }
|
34
|
-
|
35
|
-
def to_result = self
|
36
|
-
|
37
|
-
def to_s = "#<OK #{@value.inspect}>"
|
18
|
+
def inspect = "#<OK #{@value}>"
|
38
19
|
|
39
|
-
|
20
|
+
# @dynamic to_s
|
21
|
+
alias to_s inspect
|
40
22
|
end
|
41
23
|
end
|
42
24
|
end
|
data/lib/mona/result/sequence.rb
CHANGED
@@ -5,7 +5,7 @@ module Mona
|
|
5
5
|
# Sequence.call { ... } allows monadic 'do' notation for Result::Dict, where #set-ing the first failure skips the
|
6
6
|
# remainder of the block and returns the Result::Dict
|
7
7
|
class Sequence
|
8
|
-
include Dict::
|
8
|
+
include Dict::Read
|
9
9
|
|
10
10
|
def self.call(result = Dict::EMPTY, &) = new(result).call(&)
|
11
11
|
|
data/lib/mona/result.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "result/version"
|
4
3
|
require_relative "result/error"
|
4
|
+
require_relative "resultable"
|
5
5
|
|
6
6
|
module Mona
|
7
7
|
# Monadic result
|
@@ -9,6 +9,8 @@ module Mona
|
|
9
9
|
# @author Ian White
|
10
10
|
# @since 0.1.0
|
11
11
|
module Result
|
12
|
+
VERSION = "0.2.0"
|
13
|
+
|
12
14
|
autoload :OK, "mona/result/ok.rb"
|
13
15
|
autoload :Err, "mona/result/err.rb"
|
14
16
|
autoload :Match, "mona/result/match.rb"
|
@@ -16,10 +18,12 @@ module Mona
|
|
16
18
|
autoload :Sequence, "mona/result/sequence.rb"
|
17
19
|
autoload :Action, "mona/result/action.rb"
|
18
20
|
|
19
|
-
def self.[](obj) = obj.
|
21
|
+
def self.[](obj) = obj.is_a?(Resultable) ? obj : OK.new(obj)
|
20
22
|
|
21
23
|
module_function
|
22
24
|
|
25
|
+
# @dynamic self.to_result, self.ok, self.err, self.on_result, self.on_ok, self.dict, self.action
|
26
|
+
|
23
27
|
def to_result(obj) = Result[obj]
|
24
28
|
|
25
29
|
def ok(value) = OK.new(value)
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mona
|
4
|
+
# Provides the result interface
|
5
|
+
# The including class must implement #either(ok, err)
|
6
|
+
module Resultable
|
7
|
+
def value_or(&block)
|
8
|
+
either ->(value) { value },
|
9
|
+
->(_failure, _reason = nil, **_meta) { block.call }
|
10
|
+
end
|
11
|
+
|
12
|
+
def ok?
|
13
|
+
either ->(_value) { true },
|
14
|
+
->(_failure, _reason = nil, **_meta) { false }
|
15
|
+
end
|
16
|
+
|
17
|
+
def err?
|
18
|
+
either ->(_value) { false },
|
19
|
+
->(_failure, _reason = nil, **_meta) { true }
|
20
|
+
end
|
21
|
+
|
22
|
+
def ok(&block)
|
23
|
+
either ->(value) { block.call(value) },
|
24
|
+
->(_failure, _reason = nil, **_meta) {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def err(&block)
|
28
|
+
either ->(_value) {},
|
29
|
+
# @type var meta: Hash[Symbol, untyped]
|
30
|
+
->(failure, reason = nil, **meta) { block.call(failure, reason, **meta) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def and_tap(&block)
|
34
|
+
tap do
|
35
|
+
either ->(value) { block.call(value) },
|
36
|
+
->(_failure, _reason = nil, **_meta) {}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def and_then(&block)
|
41
|
+
either ->(value) { Result[block.call(value)] },
|
42
|
+
->(_failure, _reason, **_meta) { self }
|
43
|
+
end
|
44
|
+
|
45
|
+
def or_else(&block)
|
46
|
+
either ->(_value) { self },
|
47
|
+
# @type var meta: Hash[Symbol, untyped]
|
48
|
+
->(failure, reason, **meta) { Result[block.call(failure, reason, **meta)] }
|
49
|
+
end
|
50
|
+
|
51
|
+
def deconstruct
|
52
|
+
either ->(value) { [:ok, value] },
|
53
|
+
# @type var meta: Hash[Symbol, untyped]
|
54
|
+
->(failure, reason, **meta) { [:err, failure, reason, meta] }
|
55
|
+
end
|
56
|
+
|
57
|
+
def deconstruct_keys(_keys = nil)
|
58
|
+
either ->(value) { { ok: value } },
|
59
|
+
# @type var meta: Hash[Symbol, untyped]
|
60
|
+
->(failure, reason, **meta) { { err: failure, reason:, **meta } }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/sig/mona.rbs
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
module Mona
|
2
|
+
type dict = Hash[Symbol, untyped]
|
3
|
+
type result[T] = Resultable[T]
|
4
|
+
type dict_result = (Result::Dict::OK | Result::Dict::Err)
|
5
|
+
|
6
|
+
module Resultable[T] : _Either[T]
|
7
|
+
interface _Either[T]
|
8
|
+
def either: [OKR, ErrR] (^(T) -> OKR, ^(T, ?untyped, **untyped) -> ErrR) -> (OKR | ErrR)
|
9
|
+
end
|
10
|
+
|
11
|
+
def ok?: -> bool
|
12
|
+
def err?: -> bool
|
13
|
+
def ok: [R] () { (T) -> R } -> (R | nil)
|
14
|
+
def err: [R] () { (T, ?untyped, **untyped) -> R } -> (R | nil)
|
15
|
+
def value_or: [R] { () -> R } -> (R | T)
|
16
|
+
def and_then: [R] () { (T) -> R } -> result[untyped]
|
17
|
+
def and_tap: () { (T) -> void } -> self
|
18
|
+
def or_else: [R] () { (T, ?untyped, **untyped) -> R } -> result[untyped]
|
19
|
+
def deconstruct: -> Array[untyped]
|
20
|
+
def deconstruct_keys: (?Array[Symbol]?) -> dict
|
21
|
+
end
|
22
|
+
|
23
|
+
module Result
|
24
|
+
VERSION: String
|
25
|
+
|
26
|
+
def self.[]: (untyped) -> result[untyped]
|
27
|
+
def self?.to_result: (untyped) -> result[untyped]
|
28
|
+
def self?.ok: [ValueT] (ValueT) -> OK[ValueT]
|
29
|
+
def self?.err: [FailureT] (FailureT, ?untyped, **untyped) -> Err[FailureT]
|
30
|
+
def self?.dict: (?dict) ?{ (Sequence) -> void } -> dict_result
|
31
|
+
def self?.on_result: (result[untyped]) { (Match) -> void } -> untyped
|
32
|
+
def self?.on_ok: (result[untyped]) { (untyped) -> void } -> untyped
|
33
|
+
def self?.action: () { (*untyped) -> void } -> Action::Ephemeral
|
34
|
+
|
35
|
+
class Error < StandardError
|
36
|
+
end
|
37
|
+
|
38
|
+
class NoMatchError < Error
|
39
|
+
attr_reader result: result[untyped]
|
40
|
+
def initialize: (result[untyped]) -> void
|
41
|
+
end
|
42
|
+
|
43
|
+
class OK[ValueT]
|
44
|
+
include Resultable[ValueT]
|
45
|
+
|
46
|
+
attr_reader value: ValueT
|
47
|
+
|
48
|
+
def initialize: (ValueT) -> void
|
49
|
+
def either: [OKR, ErrR] (^(ValueT) -> OKR, ^(untyped, ?untyped, **untyped) -> ErrR) -> OKR
|
50
|
+
def inspect: -> String
|
51
|
+
alias to_s inspect
|
52
|
+
end
|
53
|
+
|
54
|
+
class Err[FailureT]
|
55
|
+
include Resultable[FailureT]
|
56
|
+
|
57
|
+
attr_reader failure: FailureT
|
58
|
+
attr_reader reason: untyped
|
59
|
+
attr_reader meta: dict
|
60
|
+
|
61
|
+
def initialize: (FailureT, ?untyped, **untyped) -> void
|
62
|
+
def either: [OKR, ErrR] (^(untyped) -> OKR, ^(FailureT, ?untyped, **untyped) -> ErrR) -> ErrR
|
63
|
+
def inspect: -> String
|
64
|
+
alias to_s inspect
|
65
|
+
end
|
66
|
+
|
67
|
+
class Dict
|
68
|
+
EMPTY: dict_result
|
69
|
+
|
70
|
+
module Read : _ToH
|
71
|
+
interface _ToH
|
72
|
+
def to_h: -> dict
|
73
|
+
end
|
74
|
+
|
75
|
+
def key? : (Symbol) -> bool
|
76
|
+
def fetch : (Symbol) -> untyped
|
77
|
+
def [] : (Symbol) -> untyped
|
78
|
+
end
|
79
|
+
|
80
|
+
interface _Interface
|
81
|
+
def set: (Symbol | [Symbol, Symbol], untyped) -> dict_result
|
82
|
+
def sequence: () { (Sequence) -> void } -> dict_result
|
83
|
+
def to_h: -> dict
|
84
|
+
end
|
85
|
+
|
86
|
+
class OK < Result::OK[dict]
|
87
|
+
include Read
|
88
|
+
|
89
|
+
include _Interface
|
90
|
+
|
91
|
+
@value: dict
|
92
|
+
end
|
93
|
+
|
94
|
+
class Err < Result::Err[dict]
|
95
|
+
include Read
|
96
|
+
|
97
|
+
include _Interface
|
98
|
+
|
99
|
+
@failure: dict
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.new: (?dict) ?{ (Sequence) -> void } -> dict_result
|
103
|
+
end
|
104
|
+
|
105
|
+
class Match
|
106
|
+
@throw: Object
|
107
|
+
@result: result[untyped]
|
108
|
+
|
109
|
+
def self.call: (result[untyped]) { (Match) -> void } -> untyped
|
110
|
+
def initialize: (result[untyped]) -> void
|
111
|
+
def call: () { (Match) -> void } -> untyped
|
112
|
+
def ok: () { (untyped) -> void } -> void
|
113
|
+
def err: (?untyped, **untyped) { (untyped, ?untyped, **untyped) -> void } -> void
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def match_reason?: (untyped, untyped) -> bool
|
118
|
+
def match_meta?: (untyped, untyped) -> bool
|
119
|
+
end
|
120
|
+
|
121
|
+
class Sequence
|
122
|
+
include Dict::Read
|
123
|
+
|
124
|
+
@throw: Object
|
125
|
+
@result: dict_result
|
126
|
+
|
127
|
+
def self.call: (?dict_result) { (Sequence) -> void } -> dict_result
|
128
|
+
def initialize: (?dict_result) -> void
|
129
|
+
def call: () { (Sequence) -> void } -> dict_result
|
130
|
+
def set: (Symbol | [Symbol,Symbol], untyped) -> void
|
131
|
+
def to_h: -> dict
|
132
|
+
end
|
133
|
+
|
134
|
+
module Action
|
135
|
+
class Ephemeral
|
136
|
+
include Action
|
137
|
+
|
138
|
+
@perform: ^(*untyped, **untyped) -> void
|
139
|
+
|
140
|
+
def initialize: () { (*untyped, **untyped) -> void } -> void
|
141
|
+
def perform: (*untyped, **untyped) -> void
|
142
|
+
end
|
143
|
+
|
144
|
+
@sequence: Sequence
|
145
|
+
|
146
|
+
def call: (*untyped, **untyped) -> dict_result
|
147
|
+
def perform: (*untyped, **untyped) -> void
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
def get: (Symbol) -> untyped
|
152
|
+
def set: (Symbol | [Symbol,Symbol], untyped) -> void
|
153
|
+
def respond_to_missing?: (Symbol, ?bool) -> bool
|
154
|
+
def method_missing: (Symbol, *untyped) -> untyped
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mona-result
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ian White
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-08-
|
11
|
+
date: 2022-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Mona::Result provides a result monad, and dict result monad with do-notation
|
14
14
|
email:
|
@@ -33,16 +33,16 @@ files:
|
|
33
33
|
- lib/mona/result/match.rb
|
34
34
|
- lib/mona/result/ok.rb
|
35
35
|
- lib/mona/result/sequence.rb
|
36
|
-
- lib/mona/
|
37
|
-
- sig/mona
|
38
|
-
homepage: https://github.com/mona/mona-result
|
36
|
+
- lib/mona/resultable.rb
|
37
|
+
- sig/mona.rbs
|
38
|
+
homepage: https://github.com/mona-rb/mona-result
|
39
39
|
licenses:
|
40
40
|
- MIT
|
41
41
|
metadata:
|
42
42
|
rubygems_mfa_required: 'true'
|
43
|
-
homepage_uri: https://github.com/mona/mona-result
|
44
|
-
source_code_uri: https://github.com/mona/mona-result
|
45
|
-
changelog_uri: https://github.com/mona/mona-result/CHANGELOG.md
|
43
|
+
homepage_uri: https://github.com/mona-rb/mona-result
|
44
|
+
source_code_uri: https://github.com/mona-rb/mona-result
|
45
|
+
changelog_uri: https://github.com/mona-rb/mona-result/blob/main/CHANGELOG.md
|
46
46
|
post_install_message:
|
47
47
|
rdoc_options: []
|
48
48
|
require_paths:
|
data/lib/mona/result/version.rb
DELETED
data/sig/mona/result.rbs
DELETED
@@ -1,177 +0,0 @@
|
|
1
|
-
module Mona
|
2
|
-
module Result
|
3
|
-
VERSION: String
|
4
|
-
|
5
|
-
type dict = Hash[Symbol, untyped]
|
6
|
-
type keys = Array[Symbol]
|
7
|
-
type result[T] = (_OK[T] | _Err[T])
|
8
|
-
type dict_result = result[dict] & _Dict
|
9
|
-
type set_key = (Symbol | [Symbol, Symbol])
|
10
|
-
|
11
|
-
def self.[]: (untyped) -> result[untyped]
|
12
|
-
def self?.to_result: (untyped) -> result[untyped]
|
13
|
-
def self?.ok: [T] (T) -> _OK[T]
|
14
|
-
def self?.err: [T] (T, ?untyped, **untyped) -> _Err[T]
|
15
|
-
def self?.dict: (?dict) ?{ (Sequence) -> void } -> dict_result
|
16
|
-
def self?.on_result: (result[untyped]) { (Match) -> void } -> untyped
|
17
|
-
def self?.on_ok: (result[untyped]) { (untyped) -> void } -> untyped
|
18
|
-
def self?.action: () { (*untyped) -> void } -> Action::Ephemeral
|
19
|
-
|
20
|
-
interface _OK[T]
|
21
|
-
def initialize: (T) -> void
|
22
|
-
def value: -> T
|
23
|
-
def ok?: -> true
|
24
|
-
def err?: -> false
|
25
|
-
def ok: [R] () { (T) -> R } -> R
|
26
|
-
def err: () { (T, untyped, **untyped) -> void } -> nil
|
27
|
-
def either: [R] (^(T) -> R, ^(T, untyped, **untyped) -> void) -> R
|
28
|
-
def value_or: () { -> void } -> T
|
29
|
-
def and_then: () { (T) -> untyped } -> result[untyped]
|
30
|
-
def and_tap: () { (T) -> void } -> self
|
31
|
-
def or_else: () { (T, ?untyped, **untyped) -> untyped } -> self
|
32
|
-
def deconstruct: -> [:ok, T]
|
33
|
-
def deconstruct_keys: (?keys?) -> { ok: T }
|
34
|
-
end
|
35
|
-
|
36
|
-
interface _Err[T]
|
37
|
-
def initialize: (T, ?untyped, **untyped) -> void
|
38
|
-
def failure: -> T
|
39
|
-
def reason: -> untyped
|
40
|
-
def meta: -> dict
|
41
|
-
def ok?: -> false
|
42
|
-
def err?: -> true
|
43
|
-
def ok: () { (untyped) -> void } -> nil
|
44
|
-
def err: [R] () { (T, untyped, **untyped) -> R } -> R
|
45
|
-
def either: [R] (^(T) -> void, ^(T, untyped, **untyped) -> R) -> R
|
46
|
-
def value_or: [R] () { -> R } -> R
|
47
|
-
def and_then: () { (T) -> untyped } -> self
|
48
|
-
def and_tap: () { (T) -> void } -> self
|
49
|
-
def or_else: () { (T, ?untyped, **untyped) -> untyped } -> result[untyped]
|
50
|
-
def deconstruct: -> [:err, T, untyped, dict]
|
51
|
-
def deconstruct_keys: (?keys?) -> dict
|
52
|
-
end
|
53
|
-
|
54
|
-
interface _ToH
|
55
|
-
def to_h: -> dict
|
56
|
-
end
|
57
|
-
|
58
|
-
interface _DictRead
|
59
|
-
def key? : (Symbol) -> bool
|
60
|
-
def fetch : (Symbol) -> untyped
|
61
|
-
def [] : (Symbol) -> untyped
|
62
|
-
end
|
63
|
-
|
64
|
-
interface _Dict
|
65
|
-
include _DictRead
|
66
|
-
def set: (set_key, untyped) -> dict_result
|
67
|
-
def sequence: () { (Sequence) -> void } -> dict_result
|
68
|
-
def to_h: -> dict
|
69
|
-
end
|
70
|
-
|
71
|
-
interface _Perform
|
72
|
-
def perform: (*untyped, **untyped) -> void
|
73
|
-
end
|
74
|
-
|
75
|
-
class Error < StandardError
|
76
|
-
end
|
77
|
-
|
78
|
-
class NoMatchError < Error
|
79
|
-
attr_reader result: _Err[untyped]
|
80
|
-
def initialize: (_Err[untyped]) -> void
|
81
|
-
end
|
82
|
-
|
83
|
-
class OK
|
84
|
-
include _OK[untyped]
|
85
|
-
|
86
|
-
@value: untyped
|
87
|
-
end
|
88
|
-
|
89
|
-
class Err
|
90
|
-
include _Err[untyped]
|
91
|
-
|
92
|
-
@failure: untyped
|
93
|
-
@reason: untyped
|
94
|
-
@meta: dict
|
95
|
-
end
|
96
|
-
|
97
|
-
class Dict
|
98
|
-
EMPTY: dict_result
|
99
|
-
|
100
|
-
module ReadInterface : _ToH
|
101
|
-
include _DictRead
|
102
|
-
end
|
103
|
-
|
104
|
-
class OK < Result::OK
|
105
|
-
include ReadInterface
|
106
|
-
|
107
|
-
include _OK[dict]
|
108
|
-
include _Dict
|
109
|
-
|
110
|
-
@value: dict
|
111
|
-
end
|
112
|
-
|
113
|
-
class Err < Result::Err
|
114
|
-
include ReadInterface
|
115
|
-
|
116
|
-
include _Err[dict]
|
117
|
-
include _Dict
|
118
|
-
|
119
|
-
@failure: dict
|
120
|
-
@reason: untyped
|
121
|
-
@meta: dict
|
122
|
-
end
|
123
|
-
|
124
|
-
def self.new: (?dict) ?{ (Sequence) -> void } -> dict_result
|
125
|
-
end
|
126
|
-
|
127
|
-
class Match
|
128
|
-
@throw: Object
|
129
|
-
@result: result[untyped]
|
130
|
-
|
131
|
-
def self.call: (result[untyped]) { (Match) -> void } -> untyped
|
132
|
-
def initialize: (result[untyped]) -> void
|
133
|
-
def call: () { (Match) -> void } -> untyped
|
134
|
-
def ok: () { (untyped) -> void } -> void
|
135
|
-
def err: (?untyped, **untyped) { (untyped, ?untyped, **untyped) -> void } -> void
|
136
|
-
|
137
|
-
private
|
138
|
-
|
139
|
-
def match_reason?: (untyped, untyped) -> bool
|
140
|
-
def match_meta?: (untyped, untyped) -> bool
|
141
|
-
end
|
142
|
-
|
143
|
-
class Sequence
|
144
|
-
include Dict::ReadInterface
|
145
|
-
|
146
|
-
@throw: Object
|
147
|
-
@result: dict_result
|
148
|
-
|
149
|
-
def self.call: (?dict_result) { (Sequence) -> void } -> dict_result
|
150
|
-
def initialize: (?dict_result) -> void
|
151
|
-
def call: () { (Sequence) -> void } -> dict_result
|
152
|
-
def set: (set_key, untyped) -> void
|
153
|
-
def to_h: -> dict
|
154
|
-
end
|
155
|
-
|
156
|
-
module Action : _Perform
|
157
|
-
class Ephemeral
|
158
|
-
include Action
|
159
|
-
|
160
|
-
@perform: ^(*untyped, **untyped) -> void
|
161
|
-
|
162
|
-
def initialize: () { (*untyped, **untyped) -> void } -> void
|
163
|
-
def perform: (*untyped, **untyped) -> void
|
164
|
-
end
|
165
|
-
|
166
|
-
@sequence: Sequence
|
167
|
-
|
168
|
-
def call: (*untyped, **untyped) -> dict_result
|
169
|
-
|
170
|
-
private
|
171
|
-
|
172
|
-
def set: (set_key, untyped) -> void
|
173
|
-
def respond_to_missing?: (Symbol, ?bool) -> bool
|
174
|
-
def method_missing: (Symbol, *untyped) -> untyped
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|