Current section

Files

Jump to
reactor lib reactor step anon_fn.ex
Raw

lib/reactor/step/anon_fn.ex

defmodule Reactor.Step.AnonFn do
@moduledoc """
The built-in step for executing in-line DSL anonymous functions.
## Options
* `run` - a one or two arity function or MFA which will be called as the run
function of the step.
* `compensate` - a one to three arity function or MFA which will be called as
the compensate function of the step. Optional.
* `undo` - a one to three arity function or MFA which will be called as the
undo function of this step. Optional.
"""
use Reactor.Step
@behaviour Reactor.Mermaid
@doc false
@impl true
@spec run(Reactor.inputs(), Reactor.context(), keyword) :: {:ok | :error, any}
def run(arguments, context, options) do
case Keyword.fetch!(options, :run) do
fun when is_function(fun, 1) ->
fun.(arguments)
fun when is_function(fun, 2) ->
fun.(arguments, context)
{m, f, a} when is_atom(m) and is_atom(f) and is_list(a) ->
apply(m, f, [arguments, context] ++ a)
end
rescue
error -> {:error, error}
end
@doc false
@impl true
@spec compensate(any, Reactor.inputs(), Reactor.context(), keyword) ::
{:continue, any} | :ok | :retry
def compensate(reason, arguments, context, options) do
case Keyword.fetch(options, :compensate) do
{:ok, fun} when is_function(fun, 1) ->
fun.(reason)
{:ok, fun} when is_function(fun, 2) ->
fun.(reason, arguments)
{:ok, fun} when is_function(fun, 3) ->
fun.(reason, arguments, context)
{:ok, {m, f, a}} when is_atom(m) and is_atom(f) and is_list(a) ->
apply(m, f, [reason, arguments, context] ++ a)
_ ->
:ok
end
end
@doc false
@impl true
@spec undo(any, Reactor.inputs(), Reactor.context(), keyword) :: :ok | :retry | {:error, any}
def undo(value, arguments, context, options) do
case Keyword.fetch(options, :undo) do
{:ok, fun} when is_function(fun, 1) ->
fun.(value)
{:ok, fun} when is_function(fun, 2) ->
fun.(value, arguments)
{:ok, fun} when is_function(fun, 3) ->
fun.(value, arguments, context)
{:ok, {m, f, a}} when is_atom(m) and is_atom(f) and is_list(a) ->
apply(m, f, [value, arguments, context] ++ a)
_ ->
:ok
end
end
@doc false
@impl true
def can?(%{impl: {_, opts}}, :undo), do: is_function(Keyword.get(opts, :undo))
def can?(%{impl: {_, opts}}, :compensate), do: is_function(Keyword.get(opts, :compensate))
def can?(_, _), do: false
@doc false
@impl true
def to_mermaid(step, options),
do: __MODULE__.Mermaid.to_mermaid(step, options)
end