View Source StdResult (StdResult v0.1.0)
StdResult
provides a way to standardize the return types of Elixir functions.
To help with pattern matching, the API also provides 3 macros:
ok!/1
: same asok/1
but can be used in guards, pattern matching, ...err!/1
: same aserr/1
but can be used in guards, pattern matching, ...unit!/0
: same asunit/0
but can be used in guards, pattern matching, ...
Note
In this library, we will use the term Ok
for :ok tuple
/ :ok Result
and
Err
for :error tuple
/ :error Result
.
Examples
iex> import StdResult
iex> System.fetch_env("PORT")
...> |> normalize_result() # This will transform `:error` into a `:error` tuple
...> |> or_result(err("PORT env required")) # If there is an error, explicit the message
...> |> map(&String.to_integer/1) # If no error, parse the string as an integer
...> |> and_then(&(if &1 >= 0, do: ok(&1), else: err("PORT must be a positive number, got: #{&1}"))) # Test if number is positive
# The result will be either:
# - `{:ok, port}`
# - `{:error, "PORT env required"}`
# - `{:error, "PORT must be a positive number, got: <value>"}`
Summary
Functions
Returns the right operand if the result is Ok
, otherwise returns the
Err
value.
Calls the callback if the result is Ok
, otherwise returns the Err
value.
Wrap any term inside a :error
tuple.
Same as err/1
but can be used in guards, pattern matching, ...
Returns true
if the result is Err
.
Returns true
if the result is Err
and the value inside of it matches
a predicate.
Returns the contained Ok
value.
Returns the contained Err
value.
Calls the provided closure with a reference to the contained value (if Ok
).
Calls the provided closure with a reference to the contained value (if Err
).
Maps a Result into another by applying a function to a contained Ok
value, leaving an Err
value untouched.
Maps a Result into another by applying a function to a contained Err
value, leaving an Ok
value untouched.
Returns the provided default (if Err
), or applies a function to the
contained value (if Ok
).
Maps a Result to a value by applying fallback function default
to a
contained Err
value, or function fun
to a contained Ok
value.
Wrap the input inside a tuple if needed.
Wrap any term inside a :ok
tuple.
Returns true
if the result is Ok
.
Returns true
if the result is Ok
and the value inside of
it matches a predicate.
Calls the callback if the result is Err
, otherwise returns the Ok
value.
Returns the right operand if the result is Err
, otherwise returns the
Ok
value.
Partition a sequence of Results into one list of all the Ok
elements
and another list of all the Err
elements.
The {}
type, also called "unit".
Returns the contained Ok
value.
Returns the contained Err
value.
Returns the contained Ok
value or a provided default.
Returns the contained Ok
value or computes it from a closure.
Types
Functions
Returns the right operand if the result is Ok
, otherwise returns the
Err
value.
Arguments passed to and_result/2
are eagerly evaluated; if you are
passing the result of a function call, it is recommended to use
and_then/2
, which is lazily evaluated.
Examples
iex> StdResult.and_result({:ok, 2}, {:error, "late error"})
{:error, "late error"}
iex> StdResult.and_result({:error, "early error"}, {:error, "foo"})
{:error, "early error"}
iex> StdResult.and_result({:error, "not a 2"}, {:error, "late error"})
{:error, "not a 2"}
iex> StdResult.and_result({:ok, 2}, {:ok, "different result type"})
{:ok, "different result type"}
Calls the callback if the result is Ok
, otherwise returns the Err
value.
This function can be used for control flow based on Result values.
Examples
iex> StdResult.and_then({:ok, 2}, &{:ok, &1 * 2})
{:ok, 4}
iex> StdResult.and_then({:ok, 1_000_000}, fn _ -> {:error, "overflowed"} end)
{:error, "overflowed"}
iex> StdResult.and_then({:error, "not a number"}, &(&1 * 2))
{:error, "not a number"}
Wrap any term inside a :error
tuple.
Examples
iex> StdResult.err("unexpected error")
{:error, "unexpected error"}
Same as err/1
but can be used in guards, pattern matching, ...
Returns true
if the result is Err
.
Examples
iex> StdResult.err?({:ok, -3})
false
iex> StdResult.err?({:error, "Some error message"})
true
Returns true
if the result is Err
and the value inside of it matches
a predicate.
Examples
iex> StdResult.err_and?({:error, :not_found}, &(&1 == :not_found))
true
iex> StdResult.err_and?({:error, :failed}, &(&1 == :not_found))
false
iex> StdResult.err_and?({:ok, 123}, &(&1 == :not_found))
false
Returns the contained Ok
value.
Because this function may raise, its use is generally discouraged.
Instead, prefer to use pattern matching and handle the Err
case
explicitly, or call unwrap_or/2
or unwrap_or_else/2
.
Examples
iex> StdResult.expect({:ok, 21}, "Testing expect")
21
iex> StdResult.expect({:error, "emergency failure"}, "Testing expect")
** (RuntimeError) Testing expect: emergency failure
Recommended Message Style
We recommend that expect/2
messages are used to describe the reason you
expect the Result should be Ok
.
iex> System.fetch_env("IMPORTANT_PATH")
...> |> StdResult.normalize_result()
...> |> StdResult.expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`")
** (RuntimeError) env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: {}
Hint: If you’re having trouble remembering how to phrase expect error messages remember to focus on the word “should” as in “env variable should be set by blah” or “the given binary should be available and executable by the current user”.
Returns the contained Err
value.
For more details, see: expect/2
Examples
iex> StdResult.expect_err({:error, "emergency failure"}, "Testing expect")
"emergency failure"
iex> StdResult.expect_err({:ok, 42}, "Testing expect")
** (RuntimeError) Testing expect: 42
Calls the provided closure with a reference to the contained value (if Ok
).
Examples
iex> import ExUnit.CaptureIO
iex> capture_io(fn -> StdResult.inspect({:ok, 21}, &IO.inspect/1) end)
"21\n"
iex> StdResult.inspect({:ok, 21}, &Function.identity/1)
{:ok, 21}
iex> import ExUnit.CaptureIO
iex> capture_io(fn -> StdResult.inspect({:error, 42}, &IO.inspect/1) end)
""
iex> StdResult.inspect({:error, 42}, &Function.identity/1)
{:error, 42}
Calls the provided closure with a reference to the contained value (if Err
).
Examples
iex> import ExUnit.CaptureIO
iex> capture_io(fn -> StdResult.inspect_err({:ok, 21}, &IO.inspect/1) end)
""
iex> StdResult.inspect_err({:ok, 21}, &Function.identity/1)
{:ok, 21}
iex> import ExUnit.CaptureIO
iex> capture_io(fn -> StdResult.inspect_err({:error, 42}, &IO.inspect/1) end)
"42\n"
iex> StdResult.inspect_err({:error, 42}, &Function.identity/1)
{:error, 42}
Maps a Result into another by applying a function to a contained Ok
value, leaving an Err
value untouched.
This function can be used to compose the results of two functions.
Examples
iex> StdResult.map({:ok, "123"}, &String.to_integer/1)
{:ok, 123}
iex> StdResult.map({:error, :not_found}, &String.to_integer/1)
{:error, :not_found}
Maps a Result into another by applying a function to a contained Err
value, leaving an Ok
value untouched.
This function can be used to pass through a successful result while handling an error.
Examples
iex> StdResult.map_err({:ok, 2}, &"error code: #{&1}")
{:ok, 2}
iex> StdResult.map_err({:error, 13}, &"error code: #{&1}")
{:error, "error code: 13"}
Returns the provided default (if Err
), or applies a function to the
contained value (if Ok
).
Arguments passed to map_or/3
are eagerly evaluated; if you are passing
the result of a function call, it is recommended to use map_or_else/3
,
which is lazily evaluated.
Examples
iex> StdResult.map_or({:ok, "foo"}, 42, &String.length/1)
3
iex> StdResult.map_or({:error, "bar"}, 42, &String.length/1)
42
Maps a Result to a value by applying fallback function default
to a
contained Err
value, or function fun
to a contained Ok
value.
This function can be used to unpack a successful result while handling an error.
Examples
iex> StdResult.map_or_else({:ok, "foo"}, &(&1), &String.length/1)
3
iex> StdResult.map_or_else({:error, "bar"}, &(&1), &String.length/1)
"bar"
Wrap the input inside a tuple if needed.
NOTE: This function does not try to guess the type of Result and needs
to receive an atom :ok
or :error
. If you want to wrap any term, you
can use ok/1
or err/1
.
It is mainly used to manipulate, normalize and chain Elixir functions
such as System.fetch_env/1
or System.delete_env/1
which return
:ok
or :error
without tuple.
Examples
iex> StdResult.normalize_result(:ok)
{:ok, {}}
iex> StdResult.normalize_result(:error)
{:error, {}}
iex> StdResult.normalize_result({:ok, :foo})
{:ok, :foo}
iex> StdResult.normalize_result({:error, :bar})
{:error, :bar}
Wrap any term inside a :ok
tuple.
Examples
iex> StdResult.ok("value")
{:ok, "value"}
Same as ok/1
but can be used in guards, pattern matching, ...
Returns true
if the result is Ok
.
Examples
iex> StdResult.ok?({:ok, -3})
true
iex> StdResult.ok?({:error, "Some error message"})
false
Returns true
if the result is Ok
and the value inside of
it matches a predicate.
Examples
iex> StdResult.ok_and?({:ok, 2}, &(&1 > 1))
true
iex> StdResult.ok_and?({:ok, 0}, &(&1 > 1))
false
iex> StdResult.ok_and?({:error, "hey"}, &(&1 > 1))
false
Calls the callback if the result is Err
, otherwise returns the Ok
value.
This function can be used for control flow based on Result values.
Examples
iex> StdResult.or_else({:ok, 2}, &{:ok, &1 * 2})
{:ok, 2}
iex> StdResult.or_else({:ok, 2}, &{:error, &1 * 4})
{:ok, 2}
iex> StdResult.or_else({:error, 2}, &{:ok, &1 * 2})
{:ok, 4}
iex> StdResult.or_else({:error, 2}, &{:error, &1 * 4})
{:error, 8}
Returns the right operand if the result is Err
, otherwise returns the
Ok
value.
Arguments passed to or_result/2
are eagerly evaluated; if you are
passing the result of a function call, it is recommended to use
or_else/2
, which is lazily evaluated.
Examples
iex> StdResult.or_result({:ok, 2}, {:error, "late error"})
{:ok, 2}
iex> StdResult.or_result({:error, "early error"}, {:ok, 2})
{:ok, 2}
iex> StdResult.or_result({:error, "not a 2"}, {:error, "late error"})
{:error, "late error"}
iex> StdResult.or_result({:ok, 2}, {:ok, 100})
{:ok, 2}
Partition a sequence of Results into one list of all the Ok
elements
and another list of all the Err
elements.
Examples
iex> ok_and_errors = [{:ok, 1}, {:error, false}, {:error, true}, {:ok, 2}]
iex> StdResult.partition_result(ok_and_errors)
{[1, 2], [false, true]}
@spec unit() :: {}
The {}
type, also called "unit".
The {}
type has exactly one value {}
, and is used when there is no
other meaningful value that could be returned.
Examples
iex> StdResult.unit()
{}
Same as unit/0
but can be used in guards, pattern matching, ...
Returns the contained Ok
value.
Because this function may raise, its use is generally discouraged.
Instead, prefer to use pattern matching and handle the Err
case
explicitly, or call unwrap_or/2
or unwrap_or_else/2
.
Examples
iex> StdResult.unwrap({:ok, 21})
21
iex> StdResult.unwrap({:error, "emergency failure"})
** (RuntimeError) emergency failure
Returns the contained Err
value.
For more details, see: unwrap/1
Examples
iex> StdResult.unwrap_err({:error, "emergency failure"})
"emergency failure"
iex> StdResult.unwrap_err({:ok, 42})
** (RuntimeError) 42
Returns the contained Ok
value or a provided default.
Arguments passed to unwrap_or/2
are eagerly evaluated; if you are
passing the result of a function call, it is recommended to use
unwrap_or_else/2
, which is lazily evaluated.
Examples
iex> StdResult.unwrap_or({:ok, 2}, 42)
2
iex> StdResult.unwrap_or({:error, "error"}, 42)
42
Returns the contained Ok
value or computes it from a closure.
Examples
iex> StdResult.unwrap_or_else({:ok, 2}, &String.length/1)
2
iex> StdResult.unwrap_or_else({:error, "foo"}, &String.length/1)
3