tagged v0.3.0 Tagged.PipeWith View Source
Generates a function for selective execution, with pass-through of terms that
does not match, much like the regular with ... <- ..., do: ...
construct.
Examples
Given a module that defines a success() | failure()
type:
defmodule DocTest.PipeWith do
use Tagged
deftagged not_an_integer
deftagged not_a_number
@type reason :: not_an_integer() | not_a_number()
deftagged success
deftagged failure
@type result :: success(integer()) | failure(reason())
def validate_input(x) when is_integer(x), do: success(x)
def validate_input(x), do: failure(not_an_integer(x))
def next_number(x), do: x + 1
def try_recovery({_, x}) when is_number(x), do: success(floor(x))
def try_recovery({_, x}), do: failure(not_a_number(x))
end
This is quite similar to the regular with ... <- ..., do: ..., else: ...
for happy paths:
iex> require DocTest.PipeWith
iex> import DocTest.PipeWith
iex> with success(v) <- validate_input(1),
...> do: next_number(v)
2
iex> validate_input(1)
...> |> with_success(&next_number/1)
2
When the path is not a happy path, it offers more fluent control over recovery from failures at any point in the pipe:
iex> require DocTest.PipeWith
iex> import DocTest.PipeWith
iex> with success(v) <- validate_input(0.7) do
...> next_number(v)
...> else
...> failure(e) -> with success(v) <- try_recovery(e),
...> do: next_number(v)
...> end
1
iex> validate_input(0.7)
...> |> with_failure(&try_recovery/1)
...> |> with_success(&next_number/1)
1