View Source Oxide.Result (oxide v0.6.0)
Helpers for working with result tuples, {:ok, value} and {:error, reason}.
Unless otherwise stated, functions raise FunctionClauseError when given an unexpected
non-result. :ok, :error, {:ok, value1, value2}, etc. are not considered results.
Summary
Functions
Result pipe operator.
Return true if an enumerable of results are all ok.
Transform an unwrapped ok value with f, or return an error unchanged.
Return true if any of an enumerable of results is ok.
Assert a result.
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.
Transform a result, mapping an ok value with f and leaving errors unchanged.
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 whether a result is ok.
Return an ok result unchanged, or transform an unwrapped error reason with f.
Returns true if the given value is a result tuple.
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.
Unwrap an :ok result, falling back to default for an :error result.
Unwrap an :ok result, or else act on the error in some way.
Types
Functions
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)
endcan 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}
Return true if an enumerable of results are all ok.
iex> Result.all?([{:ok, 1}, {:ok, 2}])
true
iex> Result.all?([{:ok, 1}, {:error, 2}])
false
@spec and_then(t(v, e), (v -> w)) :: w | {:error, e} when v: var, w: var, e: var
Transform an unwrapped ok value with f, or return an error unchanged.
Similar to map/2 except the transformed value is returned unwrapped. Useful when passing
a result into another function that returns a result.
iex> {:ok, 3} |> Result.and_then(fn x -> x + 1 end)
4
iex> {:error, :nan} |> Result.and_then(fn x -> x + 1 end)
{:error, :nan}
Return true if any of an enumerable of results is ok.
iex> Result.any?([{:ok, 1}, {:error, 2}])
true
iex> Result.any?([{:error, 1}, {:error, 2}])
false
Assert a result.
Returns the value unchanged if it is a result; raises RuntimeError otherwise.
iex> Result.assert_result!({:ok, 42})
{:ok, 42}
iex> Result.assert_result!({:error, :not_found})
{:error, :not_found}
iex> Result.assert_result!(42)
** (RuntimeError) Not a result
iex> Result.assert_result!({:ok, 42, 43})
** (RuntimeError) Not a result
iex> Result.assert_result!(:ok)
** (RuntimeError) Not a result
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}
@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}
Return whether a result is an error.
iex> Result.error?({:ok, 3})
false
iex> Result.error?({:error, 3})
true
Transform a result, mapping an ok value with f and leaving errors unchanged.
Similar to and_then/2 and useful for transformations that don't return a result.
iex> {:ok, 3} |> Result.map(fn x -> x + 1 end)
{:ok, 4}
iex> {:error, :nan} |> Result.map(fn x -> x + 1 end)
{:error, :nan}
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"}
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.
iex> 3 |> Result.ok()
{:ok, 3}
iex> Result.ok({:ok, 3})
{:ok, {:ok, 3}}
Return whether a result is ok.
iex> Result.ok?({:ok, 3})
true
iex> Result.ok?({:error, 3})
false
@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
Returns true if the given value is a result tuple.
iex> Result.result?({:ok, 42})
true
iex> Result.result?({:error, :not_found})
true
iex> Result.result?(42)
false
iex> Result.result?({:ok, 42, 43})
false
iex> Result.result?(:ok)
false
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}
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.
If an error reason is an exception, it is raised as-is; otherwise, a RuntimeError
is raised with the inspected error reason in the exception message.
iex> Result.unwrap!({:ok, :value})
:value
iex> Result.unwrap!({:error, %{code: 500}})
** (RuntimeError) Unwrapped an error: %{code: 500}
iex> Result.unwrap!({:error, ArgumentError.exception("oh no")})
** (ArgumentError) oh no
@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
@spec unwrap_or_else(t(v, e), (e -> w)) :: v | w when e: var, w: var, v: var
Unwrap an :ok result, or else act on the error in some way.
iex> Result.unwrap_or_else({:ok, 0}, fn e -> e + 1000 end)
0
iex> Result.unwrap_or_else({:error, 0}, fn e -> e + 1000 end)
1000