Result-rb
A ruby port of the Rust
result-monad Result
.
Installation
Add this line to your application's Gemfile
:
gem 'rresult'
Usage
The Result can be an Ok
, to wrap successfull values, or an Err
, to wrap something that went wrong.
An Err
has a description, this should be a Symbol
, and a value, which can be any Object
Constructors
Regular class-constructors:
ok_result = Result::ok(42)
err_result = Result::err(description: :not_the_answer_to_anything, value: 41)
Object
is monkey-patched to provide convenience-constructors
ok_result = Ok(42)
err_result = Err(:not_the_answer_to_anything, 41)
Some inspectors
Check if the Result
is Ok
or Err
Ok(42).ok? == true
Ok(42).is_ok == true
Err(:not_the_answer_to_anything, 41).err? == true
Err(:not_the_answer_to_anything, 41).is_err == true
Check the wrapped value inside:
Ok(42).contains? 42 == true
Ok(42).contains 42 == true
Err(:not_the_answer_to_anything, 41).contains_err?(:not_the_answer_to_anything, 42) == true
Err(:not_the_answer_to_anything, 41).contains_err(:not_the_answer_to_anything, 42) == true
Accessors
Get the wrapped error elements with #err_description
and #err_value
.
These return nil
for an Ok
.
Ok(42).err_description == nil
Ok(42).err_value == nil
Err(:not_the_answer_to_anything, 41).err_description == :not_the_answer_to_anything
Err(:not_the_answer_to_anything, 41).err_value == 41
Unwrappers
#unwrap
return the wrapped value of an Ok
, but raises a RuntimeError
for an Err
Ok(42).unwrap == 42
Err(:wrong_answer, 41).unwrap
#unwrap_err
returns an Array
with the description and value of an Err
, but raises a RuntimeError
for an Ok
Ok(42).unwrap
Err(:wrong_answer, 41).unwrap_err == [:wrong_answer, 41]
#unwrap_or
unwraps an Ok
or returns the provided default if Err
Ok(42).unwrap_or(-1) == 42
Err(:not_the_answer_to_anything, 41).unwrap_or(-1) == -1
#unwrap_or_else
unwraps an Ok
or returns the provided default if Err
as result of the block.
The block takes the error description and the error value
Ok(42).unwrap_or_else { |descr, val| val / 2 } == 42
Err(:not_the_answer_to_anything, 41).unwrap_or_else{ |descr, val| val / 2 } == 20
Map
#map
allows to apply a block to the wrapped value, if its Ok
. It does not touch an Err
Ok(42).map { |val| val * 2 } == Ok(84)
Err(:not_the_answer_to_anything, 41).map { |val| val * 2 } == Err(:not_the_answer_to_anything, 41)
#map_or
unwraps the Result
and returns a default value, in case of an Err
Ok(42).map_or(-1) { |val| val * 2 } == 84
Err(:not_the_answer_to_anything, 41).map_or(-1) { |val| val * 2 } == -1
#map_or_else
unwraps the Result
like #map_or
, but take 2 lambda's to specify the mapping of both Ok
and Err
map = ->(ok_val) { ok_val * 2 }
or_else = ->(_desc, err_val) { err_val / 2 }
Ok(42).map_or_else(map: map, or_else: or_else) == 84
Err(:not_the_answer_to_anything, 41).map_or_else(map: map, or_else: or_else) == 20
#map_err
maps an Err
with a provided block. That block should return an Array
with the new description and value
Ok(42).map_err { |descr, err_val| val * 2 } == Ok(84)
Err(:not_the_answer_to_anything, 41).map { |val| val * 2 } == Err(:not_the_answer_to_anything, 41)
Logical AND combinator
#and
replaces the value of the Result
by that of that argument, only if the Result
is an Ok
some_ok_res = Ok(-1)
some_err_res = Err(:mistake, 'you did something wrong')
Ok(42).and(some_ok_res) == some_ok_res
Ok(42).and(some_err_res) == some_ok_res
Err(:not_the_answer_to_anything, 41).and(some_ok_res) == Err(:not_the_answer_to_anything, 41)
Err(:not_the_answer_to_anything, 41).and(some_err_res) == Err(:not_the_answer_to_anything, 41)
#and_then
applies a logical AND with the result of a block
Ok(42).and_then { |val| Ok(val * 2) }).to be == Ok(84)
Ok(42).and_then { |val| Err(:wrong_answer, 41) } == Err(:wrong_answer, 41)
Logical OR combinator
#or
replaces the value of the Result
by that of that argument, only if the Result
is an Err
some_ok_res = Ok(-1)
some_err_res = Err(:mistake, 'you did something wrong')
Ok(42).or(some_ok_res) == Ok(42)
Ok(42).and(some_err_res) == Ok(42)
Err(:not_the_answer_to_anything, 41).or(some_ok_res) == some_ok_res
Err(:not_the_answer_to_anything, 41).or(some_err_res) == some_err_res
#or_else
applies a logical OR with the result of a block. The block provides takes the description and value of the Err
Err(:wrong_answer, 41).or_else { |descr, val| Ok(val / 2) }).to be == Ok(20)
Err(:wrong_answer, 41).or_else { |descr, val| Err(:not_corrected, -1) } == Err(:not_corrected, -1)