lib/formular/client.ex

defmodule Formular.Client do
  @moduledoc """
  Documentation for `Formular.Client`.
  """

  alias Formular.Client.Cache

  @spec eval(
          name :: binary(),
          binding :: keyword(),
          options :: Formular.options()
        ) :: {:ok, term()} | {:error, term()}

  def eval(name, binding, options \\ []) do
    case code_or_module!(name) do
      {:function, f} ->
        {:ok, f.(binding, options)}

      {:code, code} ->
        Formular.eval(code, binding, options)

      {:module, mod} ->
        Formular.eval({:module, mod}, binding, options)
    end
  end

  defp code_or_module!(name) do
    case Cache.get(name) do
      {nil, code} when is_binary(code) ->
        {:code, code}

      code when is_binary(code) ->
        {:code, code}

      nil ->
        raise "Code has not been fetched"

      mod when is_atom(mod) ->
        {:module, mod}

      {mod, _code} when is_atom(mod) and not is_nil(mod) ->
        {:module, mod}

      f when is_function(f, 2) ->
        {:function, f}
    end
  end
end