Current section

Files

Jump to
interceptor lib configuration configurator.ex
Raw

lib/configuration/configurator.ex

defmodule Interceptor.Configurator do
alias Interceptor.Utils
defmacro __using__(_opts) do
quote do
import unquote(__MODULE__)
Module.register_attribute(__MODULE__, :interceptions, accumulate: true)
@before_compile unquote(__MODULE__)
def debug_intercept_config(), do: get_intercept_config()
end
end
defmacro __before_compile__(_env) do
quote do
def get_intercept_config() do
@interceptions
|> Enum.reverse()
|> transform_streamlined_config_to_tuple_config()
end
end
end
@doc """
This function converts a map or a list of 2-element tuples (i.e. any structure
that can be iterated with `Enum.map/1` as a list of 2-element tuples) into a
"proper" (i.e. tuple-based) intercept configuration map. Each
element is a `{mfa_to_intercept, callbacks}` tuple, where `mfa_to_intercept`
is the MFA of the function to intercept as a `"Module.function/arity"` string,
and `callbacks` is a keyword list whose keys may be one of `:before, :after,
:on_success, :on_error or :wrapper`, and the values the callback functions to
call also as a `"Module.function/arity"` string.
If instead of a `"Module.function/arity"` string, a function is already in
the MFA tuple format, i.e., it is already written as {Module, :function, 2},
instead of `"Module.function/2"`, the transformation won't do nothing.
The intercepted function can now have a `*` for its `arity` or
`function_name` and `arity` on both tuple-based and
string-based format (e.g. `{Module, :*, :*}` or `Module.*/*`).
"""
def transform_streamlined_config_to_tuple_config(intercept_config) do
intercept_config
|> Enum.map(fn {mfa_to_intercept, callbacks} ->
to_intercept = Utils.get_intercepted_mfa_from_string(mfa_to_intercept)
{to_intercept, convert_callbacks_to_mfa(callbacks)}
end)
|> Enum.into(%{})
end
defp convert_callbacks_to_mfa([callback | rest]),
do: [convert_callback_to_mfa(callback) | convert_callbacks_to_mfa(rest)]
defp convert_callbacks_to_mfa([]), do: []
defp convert_callback_to_mfa({type, mfa_string}) when type in [:before, :after, :on_success, :on_error, :wrapper] do
mfa = Utils.get_mfa_from_string(mfa_string)
{type, mfa}
end
defmacro intercept(mfa_to_intercept, callbacks) do
quote bind_quoted: [mfa_to_intercept: mfa_to_intercept, callbacks: callbacks] do
@interceptions {mfa_to_intercept, callbacks}
end
end
end