Packages
altworx_runbox
14.1.0
25.0.0
24.0.0
23.1.0
23.0.0
22.2.0
22.1.0
22.0.0
21.2.0
21.1.2
21.1.1
21.1.0
21.0.0
20.0.0
19.0.0
18.0.0
17.2.0
17.1.0
17.0.1
17.0.0
16.2.0
16.1.0
16.0.0
15.0.0
14.1.0
14.0.1
14.0.0
13.0.3
13.0.2
13.0.1
13.0.0
12.1.0
12.0.0
11.0.1
11.0.0
10.0.0
9.0.0
8.0.0
7.0.1
7.0.0
6.0.0
5.0.0
4.0.0
3.0.0
2.1.0
2.0.0
1.4.1
1.4.0
1.3.0
1.2.0
1.1.0
1.0.0
0.1.3
0.1.2
0.1.1
0.1.0
Runbox is a library for running Altworx scenarios.
Current section
Files
Jump to
Current section
Files
lib/runbox/utils/enum.ex
defmodule Runbox.Utils.Enum do
@moduledoc group: :utilities
@moduledoc """
A set of utility functions for Enums.
"""
@doc """
Returns `:ok` if `fun` applied to every element of `enumerable` returns `:ok`.
Otherwise it returns the first error occurred during `fun` call.
## Example
iex> each_while_ok([], fn _ -> :not_called_at_all end)
:ok
iex> each_while_ok([1, 2, 3], fn _ -> :ok end)
:ok
iex> each_while_ok([1, 2, 3], &(if &1 == 2, do: {:error, &1}, else: :ok))
{:error, 2}
"""
@spec each_while_ok(Enumerable.t(), (any() -> result)) :: result
when result: :ok | {:error, reason :: any()}
def each_while_ok(enumerable, fun) do
with {:ok, :ok} <- reduce_while_ok(enumerable, :ok, &each_if_ok_reducer(&1, &2, fun)) do
:ok
end
end
@doc """
Returns `{:ok, list_of_values}` if `fun` applied to every element of
`enumerable` returns `{:ok, value}`. Otherwise it returns the first
error occurred during `fun` call.
## Example
iex> map_while_ok([], fn _ -> :not_called_at_all end)
{:ok, []}
iex> map_while_ok([1, 2, 3], &({:ok, &1 * 2}))
{:ok, [2, 4, 6]}
iex> map_while_ok([1, 2, 3], &(if &1 == 2, do: {:error, &1 * 2}, else: {:ok, &1 * 2}))
{:error, 4}
"""
@spec map_while_ok(Enumerable.t(), (any() -> {:ok, any()} | {:error, reason :: any()})) ::
{:ok, list()} | {:error, reason :: any()}
def map_while_ok(enumerable, fun) do
with {:ok, items} <- reduce_while_ok(enumerable, [], &map_if_ok_reducer(&1, &2, fun)) do
{:ok, Enum.reverse(items)}
end
end
@doc """
Invokes `fun` for each element in the `enumerable` with the accumulator.
If every `fun` call returns `{:ok, new_acc}`, functions returns `{:ok, last_acc}`.
Otherwise it returns the first error occurred during `fun` call.
## Example
iex> reduce_while_ok([], :initial, fn _, _ -> :not_called_at_all end)
{:ok, :initial}
iex> reduce_while_ok([1, 2, 3], 0, &({:ok, &1 + &2}))
{:ok, 6}
iex> reduce_while_ok([1, 2, 3], 0, &(if &1 == 2, do: {:error, &1 + &2}, else: {:ok, &1 + &2}))
{:error, 3}
"""
@spec reduce_while_ok(
Enumerable.t(),
any(),
(any(), any() -> {:ok, any()} | {:error, reason: any()})
) :: {:ok, any()} | {:error, reason :: any()}
def reduce_while_ok(enumerable, acc, fun) do
Enum.reduce_while(enumerable, {:ok, acc}, &halt_on_error(&1, &2, fun))
end
defp each_if_ok_reducer(item, :ok, fun) do
with :ok <- fun.(item) do
{:ok, :ok}
end
end
defp halt_on_error(item, {:ok, acc}, fun) do
case fun.(item, acc) do
{:ok, _acc} = new -> {:cont, new}
{:error, _reason} = error -> {:halt, error}
end
end
defp map_if_ok_reducer(item, acc, fun) do
with {:ok, value} <- fun.(item) do
{:ok, [value | acc]}
end
end
end