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 # raises RuntimeError
#unwrap_err returns an Array with the description and value of an Err, but raises a RuntimeError for an Ok
Ok(42).unwrap # raises RuntimeError
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)