Class: Result
- Inherits:
-
Object
- Object
- Result
- Defined in:
- lib/result.rb
Overview
NOTE: This class is intentionally not namespaced to allow for more concise, readable, and explicit usage.
It it a generic reusable implementation of the Result type, and is not specific to any domain
rubocop:disable Gitlab/NamespacedClass
Class Method Summary collapse
-
.err(err_value) ⇒ Result
“self.err” corresponds to Err(E) in Rust: doc.rust-lang.org/std/result/enum.Result.html#variant.Err.
-
.ok(ok_value) ⇒ Result
The .ok and .err factory class methods are the only way to create a Result.
Instance Method Summary collapse
- #==(other) ⇒ Boolean
-
#and_then(lambda_or_singleton_method) ⇒ Result
‘and_then` is a functional way to chain together operations which may succeed or have errors.
-
#deconstruct_keys(keys) ⇒ Hash
‘deconstruct_keys` supports pattern matching on a Result object with a `case` statement.
-
#err? ⇒ Boolean
The ‘err?` attribute will be false if the Result was constructed with .ok, and true if it was constructed with .err “#err?” corresponds to “is_err” in Rust.
-
#map(lambda_or_singleton_method) ⇒ Result
‘map` is similar to `and_then`, but it is used for “single track” methods which always succeed, and have no possibility of returning an error (but they may still raise exceptions, which is unrelated to the Result handling).
-
#ok? ⇒ Boolean
The ‘ok?` attribute will be true if the Result was constructed with .ok, and false if it was constructed with .err.
-
#to_h ⇒ Hash
‘to_h` supports destructuring of a result object, for example: `result => { ok: }; puts ok`.
-
#unwrap ⇒ Object
“#unwrap” corresponds to “unwrap” in Rust.
-
#unwrap_err ⇒ Object
“#unwrap” corresponds to “unwrap” in Rust.
Class Method Details
.err(err_value) ⇒ Result
“self.err” corresponds to Err(E) in Rust: doc.rust-lang.org/std/result/enum.Result.html#variant.Err
34 35 36 |
# File 'lib/result.rb', line 34 def self.err(err_value) new(err_value: err_value) end |
.ok(ok_value) ⇒ Result
The .ok and .err factory class methods are the only way to create a Result
“self.ok” corresponds to Ok(T) in Rust: doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
26 27 28 |
# File 'lib/result.rb', line 26 def self.ok(ok_value) new(ok_value: ok_value) end |
Instance Method Details
#==(other) ⇒ Boolean
168 169 170 171 |
# File 'lib/result.rb', line 168 def ==(other) # NOTE: The underlying `@ok` instance variable is a boolean, so we only need to check `ok?`, not `err?` too self.class == other.class && other.ok? == ok? && other.instance_variable_get(:@value) == value end |
#and_then(lambda_or_singleton_method) ⇒ Result
‘and_then` is a functional way to chain together operations which may succeed or have errors. It is passed a lambda or class (singleton) method object, and must return a Result object representing “ok” or “err”.
If the Result object it is called on is “ok”, then the passed lambda or singleton method is called with the value contained in the Result.
If the Result object it is called on is “err”, then it is returned without calling the passed lambda or method.
It only supports being passed a lambda, or a class (singleton) method object which responds to ‘call` with a single argument (arity of 1). If multiple values are needed, pass a hash or array. Note that passing `Proc` objects is NOT supported, even though the YARD annotation contains `Proc` (because the type of a lambda is also `Proc`).
Passing instance methods to ‘and_then` is not supported, because the methods in the chain should be stateless “pure functions”, and should not be persisting or referencing any instance state anyway.
“#and_then” corresponds to “and_then” in Rust: doc.rust-lang.org/std/result/enum.Result.html#method.and_then
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/result.rb', line 94 def and_then(lambda_or_singleton_method) validate_lambda_or_singleton_method(lambda_or_singleton_method) # Return/passthough the Result itself if it is an err return self if err? # If the Result is ok, call the lambda or singleton method with the contained value result = lambda_or_singleton_method.call(value) unless result.is_a?(Result) err_msg = "'Result##{__method__}' expects a lambda or singleton method object which returns a 'Result' type " \ ", but instead received '#{lambda_or_singleton_method.inspect}' which returned '#{result.class}'. " \ "Check that the previous method calls in the '#and_then' chain are correct." raise(TypeError, err_msg) end result end |
#deconstruct_keys(keys) ⇒ Hash
‘deconstruct_keys` supports pattern matching on a Result object with a `case` statement. See specs for examples.
161 162 163 164 165 |
# File 'lib/result.rb', line 161 def deconstruct_keys(keys) raise(ArgumentError, 'Use either :ok or :err for pattern matching') unless [[:ok], [:err]].include?(keys) to_h end |
#err? ⇒ Boolean
The ‘err?` attribute will be false if the Result was constructed with .ok, and true if it was constructed with .err “#err?” corresponds to “is_err” in Rust.
67 68 69 |
# File 'lib/result.rb', line 67 def err? !ok? end |
#map(lambda_or_singleton_method) ⇒ Result
‘map` is similar to `and_then`, but it is used for “single track” methods which always succeed, and have no possibility of returning an error (but they may still raise exceptions, which is unrelated to the Result handling). The passed lambda or singleton method must return a value, not a Result.
If the Result object it is called on is “ok”, then the passed lambda or singleton method is called with the value contained in the Result.
If the Result object it is called on is “err”, then it is returned without calling the passed lambda or method.
“#map” corresponds to “map” in Rust: doc.rust-lang.org/std/result/enum.Result.html#method.map
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/result.rb', line 129 def map(lambda_or_singleton_method) validate_lambda_or_singleton_method(lambda_or_singleton_method) # Return/passthrough the Result itself if it is an err return self if err? # If the Result is ok, call the lambda or singleton method with the contained value mapped_value = lambda_or_singleton_method.call(value) if mapped_value.is_a?(Result) err_msg = "'Result##{__method__}' expects a lambda or singleton method object which returns an unwrapped " \ "value, not a 'Result', but instead received '#{lambda_or_singleton_method.inspect}' which returned " \ "a 'Result'." raise(TypeError, err_msg) end # wrap the returned mapped_value in an "ok" Result. Result.ok(mapped_value) end |
#ok? ⇒ Boolean
The ‘ok?` attribute will be true if the Result was constructed with .ok, and false if it was constructed with .err
“#ok?” corresponds to “is_ok” in Rust.
58 59 60 61 |
# File 'lib/result.rb', line 58 def ok? # We don't make `@ok` an attr_reader, because we don't want to confusingly shadow the class method `.ok` @ok end |
#to_h ⇒ Hash
‘to_h` supports destructuring of a result object, for example: `result => { ok: }; puts ok`
152 153 154 |
# File 'lib/result.rb', line 152 def to_h ok? ? { ok: value } : { err: value } end |
#unwrap ⇒ Object
“#unwrap” corresponds to “unwrap” in Rust.
42 43 44 |
# File 'lib/result.rb', line 42 def unwrap ok? ? value : raise("Called Result#unwrap on an 'err' Result") end |
#unwrap_err ⇒ Object
“#unwrap” corresponds to “unwrap” in Rust.
50 51 52 |
# File 'lib/result.rb', line 50 def unwrap_err err? ? value : raise("Called Result#unwrap_err on an 'ok' Result") end |