improvement(Reactor.Step): remove can?/1 and replace with optional callbacks. (#6)

This commit is contained in:
James Harton 2023-05-12 15:50:49 +12:00 committed by GitHub
parent e8035f5646
commit 7b2e469135
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 19 additions and 53 deletions

View file

@ -59,7 +59,7 @@ defmodule Reactor.Executor.StepRunner do
end end
defp maybe_compensate(module, reason, arguments, context, options) do defp maybe_compensate(module, reason, arguments, context, options) do
if module.can?(:compensate) do if Step.can?(module, :compensate) do
compensate(module, reason, arguments, context, options) compensate(module, reason, arguments, context, options)
else else
{:error, reason} {:error, reason}

View file

@ -41,14 +41,6 @@ defmodule Reactor.Step do
""" """
@type undo_result :: :ok | :retry | {:error, any} @type undo_result :: :ok | :retry | {:error, any}
@doc """
Capability discovery callback.
Return true for the capabilities that your step supports. See
`t:capability` for a list of all capabilities.
"""
@callback can?(capability) :: boolean
@doc """ @doc """
Execute the step. Execute the step.
@ -83,6 +75,8 @@ defmodule Reactor.Step do
@doc """ @doc """
Compensate for the failure of the step. Compensate for the failure of the step.
> Do not implement this callback if your step doesn't support compensation.
If `run/3` returned an error then this callback will be called the error If `run/3` returned an error then this callback will be called the error
reason and the original arguments. reason and the original arguments.
@ -117,6 +111,8 @@ defmodule Reactor.Step do
@doc """ @doc """
Undo a previously successful execution of the step. Undo a previously successful execution of the step.
> Do not implement this callback if your step doesn't support undoing.
This callback is called when the reactor encounters an unhandled error later This callback is called when the reactor encounters an unhandled error later
in it's execution run and must undo the work previously done. in it's execution run and must undo the work previously done.
@ -146,17 +142,22 @@ defmodule Reactor.Step do
options :: keyword options :: keyword
) :: undo_result ) :: undo_result
@optional_callbacks compensate: 4, undo: 4
@doc """ @doc """
Find out of a step has a capability. Find out of a step has a capability.
""" """
@spec can?(Step.t(), capability()) :: boolean @spec can?(module | Step.t(), capability()) :: boolean
def can?(%Step{impl: {module, _opts}}, capability) def can?(%Step{impl: {module, _opts}}, capability)
when is_atom(module), when is_atom(module) and capability in ~w[undo compensate]a,
do: module.can?(capability) do: function_exported?(module, capability, 4)
def can?(%Step{impl: module}, capability) def can?(%Step{impl: module}, capability)
when is_atom(module), when is_atom(module) and capability in ~w[undo compensate]a,
do: module.can?(capability) do: function_exported?(module, capability, 4)
def can?(module, capability) when is_atom(module) and capability in ~w[undo compensate]a,
do: function_exported?(module, capability, 4)
def can?(_step, _capability), do: false def can?(_step, _capability), do: false
@ -199,10 +200,6 @@ defmodule Reactor.Step do
defmacro __using__(_opts) do defmacro __using__(_opts) do
quote do quote do
@behaviour unquote(__MODULE__) @behaviour unquote(__MODULE__)
def compensate(_, _, _, _), do: :ok
def undo(_, _, _, _), do: :ok
defoverridable compensate: 4, undo: 4
end end
end end
end end

View file

@ -8,11 +8,6 @@ defmodule Reactor.Step.AnonFn do
use Reactor.Step use Reactor.Step
@doc false
@impl true
@spec can?(any) :: false
def can?(_), do: false
@doc false @doc false
@impl true @impl true
@spec run(Reactor.inputs(), Reactor.context(), keyword) :: {:ok | :error, any} @spec run(Reactor.inputs(), Reactor.context(), keyword) :: {:ok | :error, any}

View file

@ -5,11 +5,6 @@ defmodule Reactor.Step.Input do
use Reactor.Step use Reactor.Step
@doc false
@impl true
@spec can?(any) :: false
def can?(_), do: false
@doc false @doc false
@impl true @impl true
@spec run(Reactor.inputs(), Reactor.context(), keyword) :: {:ok | :error, any} @spec run(Reactor.inputs(), Reactor.context(), keyword) :: {:ok | :error, any}

View file

@ -9,11 +9,6 @@ defmodule Reactor.Step.Transform do
alias Reactor.Step alias Reactor.Step
use Step use Step
@doc false
@impl true
@spec can?(any) :: false
def can?(_), do: false
@doc false @doc false
@impl true @impl true
@spec run(Reactor.inputs(), Reactor.context(), keyword) :: {:ok | :error, any} @spec run(Reactor.inputs(), Reactor.context(), keyword) :: {:ok | :error, any}

View file

@ -144,9 +144,6 @@ defmodule Reactor.ExecutorTest do
@moduledoc false @moduledoc false
use Reactor.Step use Reactor.Step
def can?(:undo), do: true
def can?(_), do: false
def run(%{agent: agent}, _, opts) do def run(%{agent: agent}, _, opts) do
if Keyword.get(opts, :fail, false) do if Keyword.get(opts, :fail, false) do
{:error, "I fail"} {:error, "I fail"}
@ -203,8 +200,6 @@ defmodule Reactor.ExecutorTest do
@moduledoc false @moduledoc false
use Reactor.Step use Reactor.Step
def can?(_), do: false
def run(%{from: from}, _, _) do def run(%{from: from}, _, _) do
{:ok, step} = {:ok, step} =
Reactor.Builder.new_step(:count_down, __MODULE__, numbers: {:result, :count_down}) Reactor.Builder.new_step(:count_down, __MODULE__, numbers: {:result, :count_down})

View file

@ -6,8 +6,6 @@ defmodule Example.BasicReactor do
@moduledoc false @moduledoc false
use Reactor.Step use Reactor.Step
def can?(_), do: false
def run(arguments, _context, _options) when arguments.age >= 18 and arguments.country == :nz, def run(arguments, _context, _options) when arguments.age >= 18 and arguments.country == :nz,
do: {:ok, true} do: {:ok, true}

View file

@ -5,8 +5,6 @@ defmodule Example.ComplexReactor do
defmodule Noop do defmodule Noop do
use Reactor.Step use Reactor.Step
def can?(_), do: false
@moduledoc false @moduledoc false
def run(_, _, _), do: {:ok, :noop} def run(_, _, _), do: {:ok, :noop}
end end

View file

@ -5,8 +5,6 @@ defmodule Example.CyclicReactor do
defmodule Noop do defmodule Noop do
use Reactor.Step use Reactor.Step
def can?(_), do: false
@moduledoc false @moduledoc false
def run(_, _, _), do: {:ok, :noop} def run(_, _, _), do: {:ok, :noop}
end end

View file

@ -2,8 +2,7 @@ defmodule Example.Step.Compensable do
@moduledoc false @moduledoc false
use Reactor.Step use Reactor.Step
def can?(:compensate), do: true
def can?(_), do: false
def run(_, _, _), do: {:ok, __MODULE__} def run(_, _, _), do: {:ok, __MODULE__}
def compensate(_, _, _, _), do: :ok
end end

View file

@ -2,7 +2,5 @@ defmodule Example.Step.Doable do
@moduledoc false @moduledoc false
use Reactor.Step use Reactor.Step
def can?(_), do: false
def run(_, _, _), do: {:ok, __MODULE__} def run(_, _, _), do: {:ok, __MODULE__}
end end

View file

@ -2,7 +2,6 @@ defmodule Example.Step.Greeter do
@moduledoc false @moduledoc false
use Reactor.Step use Reactor.Step
def can?(_), do: false
def run(%{whom: nil}, _, _), do: {:ok, "Hello, World!"} def run(%{whom: nil}, _, _), do: {:ok, "Hello, World!"}
def run(%{whom: whom}, _, _), do: {:ok, "Hello, #{whom}!"} def run(%{whom: whom}, _, _), do: {:ok, "Hello, #{whom}!"}
end end

View file

@ -2,8 +2,7 @@ defmodule Example.Step.Undoable do
@moduledoc false @moduledoc false
use Reactor.Step use Reactor.Step
def can?(:undo), do: true
def can?(_), do: false
def run(_, _, _), do: {:ok, __MODULE__} def run(_, _, _), do: {:ok, __MODULE__}
def undo(_, _, _, _), do: :ok
end end