View Source Oxide.Result (oxide v0.4.1)

Helpers for working with result tuples, {:ok, value} and {:error, reason}.

Unless otherwise stated, functions raise FunctionClauseError when given an unexpected non-result.

Summary

Functions

Result pipe operator.

Collects a list of results into a single result.

Convert a maybe-nil value to a result.

Wrap a value in an error result.

Return whether a result is an error.

Return whether a result is ok.

Return a result leaving errors unchanged but transforming the value of an :ok result.

Return a result leaving ok values unchanged but transforming an error reason with f.

Return an unwrapped ok value transformed by f, or default if result is an error.

Wrap a value in an ok result.

Return an ok result unchanged, or transform an unwrapped error reason with f.

Equivalent to Kernel.tap/2 for error results.

Equivalent to Kernel.tap/2 for ok results.

Unwrap an :ok result, and raise an :error reason as a RuntimeError.

Unwrap an :ok result, falling back to default for an :error result.

Unwrap an :ok result, falling back to executing a zero-arity function if the result is an error.

Types

@type t() :: {:ok, any()} | {:error, any()}
@type t(v) :: {:ok, v} | {:error, any()}
@type t(v, e) :: {:ok, v} | {:error, e}

Functions

Link to this macro

left &&& right

View Source (macro)

Result pipe operator.

The result pipe operator &&&/2 is a result-aware analogue to the pipe operator |>. It allows chaining functions that return results, piping the inner value of :ok results and short-circuiting the pipeline if any of the functions return an error. For example

with {:ok, x1} <- f1(x),
     {:ok, x2} <- f2(x1) do
  f3(x2)
end

can be written as

x |> f1() &&& f2() &&& f3()

More examples:

iex> {:ok, :foo} &&& Atom.to_string()
"foo"
iex> {:ok, 3} &&& then(fn x -> {:ok, x + 1} end) &&& List.wrap()
[4]
iex> {:ok, :foo} &&& Atom.to_string() |> String.capitalize()
"Foo"
iex> {:error, :oops} &&& Atom.to_string() |> String.capitalize()
{:error, :oops}
@spec and_then(t(v, e), (v -> w)) :: w | {:error, e} when v: var, w: var, e: var
@spec collect([t()]) :: t()

Collects a list of results into a single result.

If any of the results is an error, the first error is returned. Otherwise, a single ok result is returned with a list of the result values.

iex> [{:ok, 1}, {:ok, 2}, {:ok, 3}] |> Result.collect()
{:ok, [1, 2, 3]}
iex> [{:ok, 1}, {:error, 2}, {:ok, 3}, {:error, 4}] |> Result.collect()
{:error, 2}
Link to this function

err_if_nil(value, reason)

View Source
@spec err_if_nil(v | nil, e) :: t(v, e) when v: var, e: var

Convert a maybe-nil value to a result.

Maps nil to {:error, reason} and any non-nil value to {:ok, value}.

iex> %{"key" => "value"} |> Map.get("key") |> Result.err_if_nil(:notfound)
{:ok, "value"}
iex> %{"key" => "value"} |> Map.get("missing") |> Result.err_if_nil(:notfound)
{:error, :notfound}
@spec error(e) :: {:error, e} when e: var

Wrap a value in an error result.

iex> :some_error_reason |> Result.error()
{:error, :some_error_reason}
@spec is_error?(t()) :: boolean()

Return whether a result is an error.

iex> Result.is_error?({:ok, 3})
false
iex> Result.is_error?({:error, 3})
true
@spec is_ok?(t()) :: boolean()

Return whether a result is ok.

iex> Result.is_ok?({:ok, 3})
true
iex> Result.is_ok?({:error, 3})
false
@spec map(t(v, e), (v -> w)) :: t(w, e) when v: var, w: var

Return a result leaving errors unchanged but transforming the value of an :ok result.

iex> Result.map({:ok, 3}, fn x -> x + 1 end)
{:ok, 4}
iex> Result.map({:error, :nan}, fn x -> x + 1 end)
{:error, :nan}
@spec map_err(t(v, e), (e -> f)) :: t(v, f) when e: var, f: var

Return a result leaving ok values unchanged but transforming an error reason with f.

iex> Result.map_err({:ok, 3}, fn x -> x + 1 end)
{:ok, 3}
iex> Result.map_err({:error, :nan}, &:erlang.atom_to_binary/1)
{:error, "nan"}
Link to this function

map_or(result, default, f)

View Source
@spec map_or(t(v, any()), w, (v -> x)) :: x | w when w: var, v: var, x: var

Return an unwrapped ok value transformed by f, or default if result is an error.

iex> Result.map_or({:ok, 3}, 0, fn x -> x + 1 end)
4
iex> Result.map_or({:error, :nan}, 0, fn x -> x + 1 end)
0
@spec ok(v) :: {:ok, v} when v: var

Wrap a value in an ok result.

@spec or_else(t(v, e), (e -> f)) :: {:ok, v} | f when e: var, f: var, v: var

Return an ok result unchanged, or transform an unwrapped error reason with f.

iex> Result.or_else({:ok, :xylophone}, fn err -> err + 1 end)
{:ok, :xylophone}
iex> Result.or_else({:error, 3}, fn err -> err + 1 end)
4
@spec tap_err(t(v, e), (e -> any())) :: t(v, e) when e: var

Equivalent to Kernel.tap/2 for error results.

Calls f with the reason of an :error result, and returns the result unchanged.

iex> {:ok, 3} |> Result.tap_err(&IO.inspect/1)
{:ok, 3}
iex> {:error, :oops} |> Result.tap_err(&IO.inspect/1)
:oops
{:error, :oops}
@spec tap_ok(t(v), (v -> any())) :: t(v) when v: var

Equivalent to Kernel.tap/2 for ok results.

Calls f with the value of an :ok result, and returns the result unchanged.

iex> {:ok, 3} |> Result.tap_ok(&IO.inspect/1)
3
{:ok, 3}
iex> {:error, :oops} |> Result.tap_ok(&IO.inspect/1)
{:error, :oops}
@spec unwrap!(t(v)) :: v when v: var

Unwrap an :ok result, and raise an :error reason as a RuntimeError.

iex> Result.unwrap!({:ok, :value})
:value
iex> Result.unwrap!({:error, %{code: 500}})
** (RuntimeError) Unwrapped an error: %{code: 500}
@spec unwrap_err!(t(any(), e)) :: e when e: var
Link to this function

unwrap_or(result, default)

View Source
@spec unwrap_or(t(v), w) :: v | w when w: var, v: var

Unwrap an :ok result, falling back to default for an :error result.

iex> Result.unwrap_or({:ok, :cake}, :icecream)
:cake
iex> Result.unwrap_or({:error, :peas}, :icecream)
:icecream
Link to this function

unwrap_or_else(result, f)

View Source
@spec unwrap_or_else(t(v), (-> w)) :: v | w when w: var, v: var

Unwrap an :ok result, falling back to executing a zero-arity function if the result is an error.

iex> Result.unwrap_or_else({:ok, :cake}, fn -> :icecream end)
:cake
iex> Result.unwrap_or_else({:error, :peas}, fn -> :icecream end)
:icecream