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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32cb8667c98ff681514f079fed657c8daa835b7c480f2e28c0524892408c81e7
4
- data.tar.gz: 741a2b69c33f10b9ec8fad3c25aeb49d6b7dd6f9178824819d933f34b2b5db38
3
+ metadata.gz: 11b851820d5a4a5558b4b9fca9ed4d473a4c7f41f76296e8304de95f319b4eac
4
+ data.tar.gz: e02cccae0cc5ddf02a7a8fd99d1f509be1148c9d41f39f28d545409da7906e05
5
5
  SHA512:
6
- metadata.gz: 96e77b201ec66ee70f9aa84ff8b7aba988233c210e5cebb1157832c53f3c116f7ecf12f069dc29c4ae3514ed9f9007a0458e1824c2d3b45263ec7487f9bd0057
7
- data.tar.gz: c359b0d6b6782297c3ebebea9e0d241d7646ccb3c44873c8d087567681ed3fb6ff58d827f6d0af9a97516d57e74410d754b47222c6b895440f9b15133b139faa
6
+ metadata.gz: 4b01676a3ec1acaa3541a3e60eeaacd82cfacdc81889bd7073e0824ee987ec89c01415b28ba1a72413a32d78d687d0ac1f0a5521a0933b4a1edae8fe0af6ce46
7
+ data.tar.gz: 66738db3e3571dd6c53982081acf787f634b5f7964a19a58649b513eeb5c3c169ac89bf25aa7fd9aaf951e25c83f9646314eab0d5b7b474f08efe3fe96adbe91
data/CHANGELOG.md CHANGED
@@ -1,4 +1,20 @@
1
- ## [0.1.1]
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.1.1)
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.2)
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.34.0)
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.0, < 2.0)
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
- success.and_tap { puts "it is #{_1}" }.and_then { _1 * 5 }.value_or { :nope }
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
- # Dict with sequence
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 :numerator, 10
42
- d.set :divisor, 2
43
- d.set :answer, d[:numerator] / d[:divisor]
44
- end # => #<OK {:numerator=>10, :divisor=>2, :answer=>5}>
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
@@ -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 @sequence.fetch(key) if args.empty? && @sequence.key?(key)
82
+ return get(key) if args.empty? && @sequence.key?(key)
79
83
 
80
84
  raise NoMethodError, "no method `#{key}' for #{self}"
81
85
  end
@@ -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::Success} or {Dict::Failure}
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 ReadInterface
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 ReadInterface
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) { OK.new to_h.merge(key => value) },
35
- ->(failure, reason, **m) { Err.new to_h.merge(failure_key => failure), reason, **m, key: failure_key }
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 ReadInterface
46
+ include Read
46
47
 
47
48
  def set(_key, _val) = raise(Error, "cannot #set on #{self}")
48
49
 
@@ -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.freeze
11
- @reason = reason
12
- @meta = 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 and_then(&) = self
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
- alias inspect to_s
24
+ # @dynamic to_s
25
+ alias to_s inspect
46
26
  end
47
27
  end
48
28
  end
@@ -7,6 +7,7 @@ module Mona
7
7
 
8
8
  # raised when Result::Match does not match the result
9
9
  class NoMatchError < Error
10
+ # @dynamic result
10
11
  attr_reader :result
11
12
 
12
13
  def initialize(result)
@@ -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 { |value| ... }
9
- # r.err(error, **meta) { |failure, reason, **meta| ... }
10
- # r.err(error) { |failure, reason, **meta| ... }
11
- # r.err { |failure, reason, **meta| ... }
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
@@ -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.freeze
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 and_then(&) = Result[yield @value]
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
- alias inspect to_s
20
+ # @dynamic to_s
21
+ alias to_s inspect
40
22
  end
41
23
  end
42
24
  end
@@ -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::ReadInterface
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.respond_to?(:to_result) ? obj.to_result : OK.new(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.1.1
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-09 00:00:00.000000000 Z
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/result/version.rb
37
- - sig/mona/result.rbs
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:
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mona
4
- module Result
5
- VERSION = "0.1.1"
6
- end
7
- end
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