Mutare.UseExpansion behaviour (mutare v0.1.2)

Copy Markdown View Source

Capability behaviour for overriding a use that Mutare cannot expand safely in-process.

Mutare.Transform.Uses normally expands module-level use calls to recover injected imports, aliases, requires, and behaviours. Some __using__ macros mutate their caller or depend on compile-time state unavailable to the scan process. An enabled extension can implement expand_use/3 to supply those directives explicitly.

This capability is independent of macro routing. A library integration commonly implements both Mutare.UseExpansion and Mutare.CallRouting, but either may be used alone. The module is listed once under :extensions:

defmodule Mutare.Gettext do
  @behaviour Mutare.UseExpansion
  @behaviour Mutare.CallRouting

  @impl Mutare.UseExpansion
  def expand_use(Gettext, _args, _context) do
    Mutare.UseExpansion.expand([quote(do: import(Gettext.Macros))])
  end

  def expand_use(_used, _args, _context), do: :decline

  @impl Mutare.CallRouting
  def call_routes, do: [{Gettext.Macros, :gettext, 1, [:raw]}]
end

Multiple handlers are consulted in :extensions order; the first result other than :decline wins. Options from a {module, opts} entry arrive in context.opts.

Summary

Types

Context passed to expand_use/3.

The result of handling a use, or :decline to try the next handler.

Callbacks

Overrides expansion of use used_module, ....

Functions

Build an expansion from injected directives and optional behaviour modules.

Types

context()

@type context() :: %{
  :module => module(),
  :opts => keyword(),
  optional(atom()) => term()
}

Context passed to expand_use/3.

  • :module — the alias-resolved caller module containing the use;
  • :opts — options from this extension's {module, opts} configuration entry.

It is a map so future context can be added without changing callback arity.

expansion()

@type expansion() :: Mutare.UseExpansion.Expansion.t() | :decline

The result of handling a use, or :decline to try the next handler.

Callbacks

expand_use(used_module, args, context)

@callback expand_use(used_module :: module(), args :: [Macro.t()], context :: context()) ::
  expansion()

Overrides expansion of use used_module, ....

used_module is alias-resolved. args is the quoted argument list written after the module. Return an expansion built by expand/2, or :decline to let the next handler try. Invalid returns, raises, throws, and exits are wrapped in Mutare.UseExpansion.ContractError.

Functions

expand(directives, behaviours \\ [])

@spec expand([Macro.t()], [module()]) :: Mutare.UseExpansion.Expansion.t()

Build an expansion from injected directives and optional behaviour modules.

Examples

iex> expansion = Mutare.UseExpansion.expand([quote(do: import String)], [GenServer])
iex> {length(expansion.directives), expansion.behaviours}
{1, [GenServer]}