defmodule Formular.Client.Config do alias __MODULE__ @type formula_name() :: String.t() @type formula_def :: {module(), formula_name(), context :: module()} @type formula_full_def :: formula_def() | {module(), name :: String.t()} @type compile_function :: ({name :: String.t(), code :: binary(), module(), nil | module()} -> :ok | {:error, term()}) @type t :: %Config{ client_name: String.t(), url: String.t(), formulas: [formula_def()], compiler: {module(), atom(), args :: list()} | compile_function(), adapter: {module(), keyword()} } defstruct [ :client_name, :url, :formulas, compiler: {Formular.Client.Compiler, :compile, []}, adapter: {Formular.Client.Adapter.Websocket, []} ] @doc """ Build a new config constructure. """ @spec new(Enum.t()) :: t() def new(opts) do struct!(Config, opts) |> format_formulas() end defp format_formulas(config) do config |> Map.update!( :formulas, &Enum.map(&1 || [], fn name when is_binary(name) -> {nil, name, nil} {_, _, _} = f -> f {mod, name} -> {mod, name, nil} end) ) end @doc """ Get the config for a given formula name. """ @spec formula_config(t(), formula_name()) :: formula_def() | nil def formula_config(%Config{formulas: formulas}, name) when is_list(formulas) do Enum.find(formulas, fn {_mod, ^name, _context} -> true _ -> false end) end def formula_config(_, _name) do nil end end