Bunch v1.0.0 Bunch View Source
A bunch of general-purpose helper and convenience functions.
Link to this section Summary
Functions
Imports a bunch of Bunch macros: withl/1
, withl/2
, ~>/2
, ~>>/2
, quote_expr/1
, quote_expr/2
Returns an :error
tuple if given value is nil
and :ok
tuple otherwise
Embeds the argument in a one-element list if it is not a list itself. Otherwise works as identity
Works like quote/2
, but doesn't require a do/end block and options are passed
as the last argument
Returns given stateful try value along with its status
Works like withl/2
, but allows shorter syntax
A labeled version of the with
macro
Helper for writing pipeline-like syntax. Maps given value using match clauses or lambda-like syntax
Works similar to ~>/2
, but accepts only ->
clauses and appends default
identity clause at the end
Link to this section Functions
__using__(args) View Source (macro)
Imports a bunch of Bunch macros: withl/1
, withl/2
, ~>/2
, ~>>/2
, quote_expr/1
, quote_expr/2
error_if_nil(v, reason)
View Source
error_if_nil(value, reason) :: Bunch.Type.try_t(value)
when value: any(), reason: any()
error_if_nil(value, reason) :: Bunch.Type.try_t(value) when value: any(), reason: any()
Returns an :error
tuple if given value is nil
and :ok
tuple otherwise.
Examples
iex> map = %{:answer => 42}
iex> Bunch.error_if_nil(map[:answer], :reason)
{:ok, 42}
iex> Bunch.error_if_nil(map[:invalid], :reason)
{:error, :reason}
listify(list) View Source
Embeds the argument in a one-element list if it is not a list itself. Otherwise works as identity.
Works similarly to List.wrap/1
, but treats nil
as any non-list value,
instead of returning empty list in this case.
Examples
iex> Bunch.listify(:a)
[:a]
iex> Bunch.listify([:a, :b, :c])
[:a, :b, :c]
iex> Bunch.listify(nil)
[nil]
quote_expr(code, opts \\ []) View Source (macro)
Works like quote/2
, but doesn't require a do/end block and options are passed
as the last argument.
Useful when quoting a single expression.
Examples
iex> use Bunch
iex> quote_expr(String.t())
quote do String.t() end
iex> quote_expr(unquote(x) + 2, unquote: false)
quote unquote: false do unquote(x) + 2 end
Nesting
Nesting calls to quote
disables unquoting in the inner call, while placing
quote_expr
in quote
or another quote_expr
does not:
iex> use Bunch
iex> quote do quote do unquote(:code) end end == quote do quote do :code end end
false
iex> quote do quote_expr(unquote(:code)) end == quote do quote_expr(:code) end
true
stateful_try_with_status(res)
View Source
stateful_try_with_status(result) :: {status, result}
when status: Bunch.Type.try_t(),
result:
Bunch.Type.stateful_try_t(state :: any())
| Bunch.Type.stateful_try_t(value :: any(), state :: any())
stateful_try_with_status(result) :: {status, result} when status: Bunch.Type.try_t(), result: Bunch.Type.stateful_try_t(state :: any()) | Bunch.Type.stateful_try_t(value :: any(), state :: any())
Returns given stateful try value along with its status.
withl(keyword) View Source (macro)
Works like withl/2
, but allows shorter syntax.
Examples
iex> use Bunch
iex> x = 1
iex> y = 2
iex> withl a: true <- x > 0,
...> b: false <- y |> rem(2) == 0,
...> do: {x, y},
...> else: (a: false -> {:error, :x}; b: true -> {:error, :y})
{:error, :y}
For more details and more verbose and readable syntax, check docs for withl/2
.
withl(with_clauses, list) View Source (macro)
A labeled version of the with
macro.
Helps to determine in else
block which with clause
did not match.
Therefore else
block is always required. Due to the Elixir syntax requirements,
all clauses have to be labeled.
Labels also make it possible to access results of already succeeded matches from else clauses. That is why labels have to be known at the compile time.
There should be at least one clause in the else block for each label that
corresponds to a <-
clause.
Duplicate labels are allowed.
Examples
iex> use Bunch
iex> list = [-1, 3, 2]
iex> binary = <<1,2>>
iex> withl max: i when i > 0 <- list |> Enum.max(),
...> bin: <<b::binary-size(i), _::binary>> <- binary do
...> {list, b}
...> else
...> max: i -> {:error, :invalid_maximum, i}
...> bin: b -> {:error, :binary_too_short, b, i}
...> end
{:error, :binary_too_short, <<1,2>>, 3}
expr ~> mapper View Source (macro)
Helper for writing pipeline-like syntax. Maps given value using match clauses or lambda-like syntax.
Examples
iex> use Bunch
iex> {:ok, 10} ~> ({:ok, x} -> x)
10
iex> 5 ~> &1 + 2
7
Lambda-like expressions are not converted to lambdas under the hood, but
result of expr
is injected to &1
at the compile time.
Useful especially when dealing with a pipeline of operations (made up e.g.
with pipe (|>
) operator) some of which are hard to express in such form:
iex> use Bunch
iex> ["Joe", "truck", "jacket"]
...> |> Enum.map(&String.downcase/1)
...> |> Enum.filter(& &1 |> String.starts_with?("j"))
...> ~> ["Words:" | &1]
...> |> Enum.join("\n")
"Words:
joe
jacket"
expr ~>> mapper_clauses View Source (macro)
Works similar to ~>/2
, but accepts only ->
clauses and appends default
identity clause at the end.
Examples
iex> use Bunch
iex> {:ok, 10} ~>> ({:ok, x} -> {:ok, x+1})
{:ok, 11}
iex> :error ~>> ({:ok, x} -> {:ok, x+1})
:error