lib/reactor/argument/build.ex

defprotocol Reactor.Argument.Build do
  @moduledoc """
  A protocol which can be used to convert something into an argument.
  """

  alias Reactor.Argument

  @doc """
  Convert the input into an argument.
  """
  @spec build(t) :: {:ok, [Argument.t()]} | {:error, any}
  def build(input)
end

defimpl Reactor.Argument.Build, for: Reactor.Argument do
  alias Reactor.Argument

  def build(argument), do: {:ok, [argument]}
end

defimpl Reactor.Argument.Build, for: Tuple do
  alias Reactor.Argument
  import Reactor.Utils

  def build({name, {:input, source}}), do: {:ok, [Argument.from_input(name, source)]}
  def build({name, {:result, source}}), do: {:ok, [Argument.from_result(name, source)]}
  def build({name, value}), do: {:ok, [Argument.from_value(name, value)]}
  def build(tuple), do: {:error, argument_error(:tuple, "contains a non-argument value", tuple)}
end