solution v1.0.2 Solution View Source
A Macro-based approach to working with ok/error tuples
This module exposes two main things:
- guard-clause macros
is_ok/1
,is_error/1
andis_okerror/1
(as well as arity-2 variants of the same), to be used whenever you like. scase/2
andswith/2
, replacements forcase
andwith
-statements respectively that allow you to pattern match on ok/error tuples more effectively, as well as bind to one ore multiple of the values stored inside.
Link to this section Summary
Functions
Matches any error datatype.
Matches {:error, res}
(as well as tuples with more elements). res
is then bound.
Turns a nillable type (that can be either nil
or a non-nil value) into an ok/error tuple.
Changes an :ok
into an :error
, an {:ok, ...}
into an {:error, ...}
and vice-versa.
Matches when x
is one of the following
Matches when x
is a long-enough ok-tuple that has more than n_elems
elements.
Matches when x
is one of the following
Matches when x
is a long-enough ok-tuple that has more than n_elems
elements.
Matches when either is_ok(x)
or is_error(x)
matches.
Matches when x
is a long-enough ok-tuple that has more than n_elems
elements.
Matches any ok datatype.
Matches {:ok, res}
(as well as tuples with more elements). res
is then bound.
Matches any ok/error datatype.
Matches any ok or error type. tag
is then bound to :ok
or :error
.
Matches {:ok, res}
, {:error, res}
(as well as tuples with more elements). tag
and res
are bound.
Works like a normal case
-statement,
but will expand ok()
, error()
and okerror()
macros to the left side of ->
.
Works like a normal with
-statement,
but will expand ok()
, error()
and okerror()
macros to the left side of <-
.
Link to this section Functions
error() View Source (macro)
Matches any error datatype.
(See also is_error/1
)
Has to be used inside the LHS of a scase
or swith
statement.
error(res) View Source (macro)
Matches {:error, res}
(as well as tuples with more elements). res
is then bound.
(See also is_error/1
)
Has to be used inside the LHS of a scase
or swith
statement.
from_nillable(thing) View Source
Turns a nillable type (that can be either nil
or a non-nil value) into an ok/error tuple.
Also handles Erlang's 'nil'-type equivalent: the atom :undefined
.
iex> from_nillable(nil)
{:error, nil}
iex> from_nillable(42)
{:ok, 42}
iex> (%{a: "yes!"} |> Map.get(:a) |> from_nillable())
{:ok, "yes!"}
iex> (%{a: "yes!"} |> Map.get(:b) |> from_nillable())
{:error, nil}
iex> from_nillable(:undefined)
{:error, :undefined}
invert_okerror(okerror) View Source
Changes an :ok
into an :error
, an {:ok, ...}
into an {:error, ...}
and vice-versa.
iex> invert_okerror(:ok)
:error
iex> invert_okerror({:ok, 1,2,3})
{:error, 1,2,3}
iex> invert_okerror({:error, "failure"})
{:ok, "failure"}
iex> invert_okerror("improper datatype")
** (ArgumentError) argument error
is_error(x) View Source (macro)
Matches when x
is one of the following:
:error
{:error, _}
{:error, _, _}
or a longer tuple where the first element is the atom
:error
. ({:error, ...}
)iex> is_error(:error) true iex> is_error({:error, 42}) true iex> is_error({:error, "I", "have", "many", "elements"}) true iex> is_error(:asdf) false iex> is_error({:ok, "success!"}) false
is_error(x, n_elems) View Source (macro)
Matches when x
is a long-enough ok-tuple that has more than n_elems
elements.
is_ok(x) View Source (macro)
Matches when x
is one of the following:
:ok
{:ok, _}
{:ok, _, _}
or a longer tuple where the first element is the atom
:ok
({:ok, ...}
)iex> is_ok(:ok) true iex> is_ok({:ok, 42}) true iex> is_ok({:ok, "I", "have", "many", "elements"}) true iex> is_ok(:asdf) false iex> is_ok({:error, "failure"}) false
is_ok(x, n_elems) View Source (macro)
Matches when x
is a long-enough ok-tuple that has more than n_elems
elements.
is_okerror(x) View Source (macro)
Matches when either is_ok(x)
or is_error(x)
matches.
iex> is_okerror({:ok, "Yay!"})
true
iex> is_okerror({:error, "Nay"})
true
iex> is_okerror(false)
false
iex> is_okerror({})
false
iex> is_okerror({:ok, "the", "quick", "brown", "fox"})
true
is_okerror(x, n_elems) View Source (macro)
Matches when x
is a long-enough ok-tuple that has more than n_elems
elements.
Warning: Will not match plain :ok
or :error
!
ok() View Source (macro)
Matches any ok datatype.
(See also is_ok/1
)
Has to be used inside the LHS of a scase
or swith
statement.
ok(res) View Source (macro)
Matches {:ok, res}
(as well as tuples with more elements). res
is then bound.
(See also is_ok/1
)
Has to be used inside the LHS of a scase
or swith
statement.
okerror() View Source (macro)
Matches any ok/error datatype.
Has to be used inside the LHS of a scase
or swith
statement.
okerror(tag) View Source (macro)
Matches any ok or error type. tag
is then bound to :ok
or :error
.
(See also is_okerror/1
)
Has to be used inside the LHS of a scase
or swith
statement.
okerror(tag, res) View Source (macro)
Matches {:ok, res}
, {:error, res}
(as well as tuples with more elements). tag
and res
are bound.
(See also is_okerror/1
)
tag
is bound to the value :ok
or :error
depending on the tuple.
res
is bound to what the second element might be.
Has to be used inside the LHS of a scase
or swith
statement.
scase(input, conditions) View Source (macro)
Works like a normal case
-statement,
but will expand ok()
, error()
and okerror()
macros to the left side of ->
.
iex> scase {:ok, 10} do
...> ok() -> "Yay!"
...> _ -> "Failure"
...> end
"Yay!"
You can also pass arguments to ok()
, error()
or okerror()
which will then be bound and available
to be used inside the case expression:
iex> scase {:ok, "foo", 42} do
...> ok(res, extra) ->
...> "result: #{res}, extra: #{extra}"
...> _ ->
...> "Failure"
...> end
"result: foo, extra: 42"
Note that for ok()
and error()
, the first argument will match the first element after the :ok
or :error
tag.
On the other hand, for okerror()
, the first argument will match the tag :ok
or :error
.
Note: It is not required to import Solution to use the macros inside swith
without prefixing them.
swith(statements, conditions) View Source (macro)
Works like a normal with
-statement,
but will expand ok()
, error()
and okerror()
macros to the left side of <-
.
iex> x = {:ok, 10}
iex> y = {:ok, 33}
iex> swith ok(res) <- x,
...> ok(res2) <- y do
...> "We have: #{res} #{res2}"
...> else
...> _ -> "Failure"
...> end
"We have: 10 33"
You can also pass arguments to ok()
, error()
or okerror()
which will then be bound and available
to be used inside the rest of the swith
-expression:
iex> x = {:ok, 10}
iex> y = {:error, 33}
iex> z = {:ok, %{a: 42}}
iex> swith ok(res) <- x,
...> error(res2) <- y,
...> okerror(tag, metamap) <- z,
...> %{a: val} = metamap do
...> "We have: #{res} #{res2} #{tag} #{val}"
...> else
...> _ -> "Failure"
...> end
"We have: 10 33 ok 42"
Note that for ok()
and error()
, the first argument will match the first element after the :ok
or :error
tag.
On the other hand, for okerror()
, the first argument will match the tag :ok
or :error
.
Note: It is not required to import Solution to use the macros inside swith
without prefixing them.