pipet v0.1.1 Pipet View Source

Macro for conditionally piping a value through a series of expressions.

Prior art

Pipet was heavily inspired by, and would not exist without:

Link to this section Summary

Functions

Conditionally pipe a value through a series of operations

Link to this section Functions

Link to this macro pipet(subject, list) View Source (macro)
pipet(Macro.t, [{:do, [Macro.t]}]) :: Macro.t

Conditionally pipe a value through a series of operations.

pipes is a series of conditional expressions. At each step of the way, if the condition succeeds, then the value will be applied as the first argument of the last expression of the body of the condition as in |>, and if the condition fails the expression will be skipped. The supported forms of conditional expressions are:

  • if
  • unless
  • cond
  • case

Raw function calls are also supported, in which case the value is piped through just like in |>

Examples

Basic if conditions are supported:

pipet [1, 2, 3] do
  if do_increment?(), do: Enum.map(& &1 + 1)
  if do_double?(),    do: map(& &1 * 1)
  if do_string?(),    do: Enum.map(&to_string/1)
end

case and cond use whichever branch succeeds:

pipet [1, 2, 3] do
  case operation do
    :increment -> Enum.map(& &1 + 1)
    :double    -> map(& &1 * 1)
    :string    -> Enum.map(&to_string/1)
  end
end

Conditional expressions can be combined with bare function calls, which will always execute:

pipet ["1", "2", "3"] do
  String.to_integer()
  if do_increment?(), do: Enum.map(& &1 + 1)
end

Multi-expression bodies pipe through the last expression:

pipet [1, 2, 3] do
  if do_add_num?() do
    num = 3
    Enum.map(& &1 + num)
  end

  case something() do
    {:ok, x} ->
      x = x + 1
      Enum.map(& &1 + x)

    :error ->
      Enum.map(& &1 - 2)
  end
end

Notes

  • pipet evaluates conditions in order, not all at once. For example, the following:

    def print_hello_and_return_true() do

    IO.puts "hello"
    true

    end

    pipet 1 do

    if print_hello_and_return_true() do
      IO.puts "world"
      increment()
    end
    unless print_hello_and_return_true() do
      IO.puts "goodbye"
    end

    end

    prints:

    > hello > world > hello

  • the rules for case are as usual - if none of the branches of a case block match a CaseClauseError will be thrown. If you want a fallthrough case you can provide a call to the identity function:

    pipet 1 do

    case {:foo, :bar} do
      :never_matches -> increment()
      _ -> (& &1).()
    end

    end