Macro.expand_once
expand_once, go back to Macro module for more information.
Receives an AST node and expands it once.
The following contents are expanded:
- Macros (local or remote)
- Aliases are expanded (if possible) and return atoms
- Compilation environment macros (
__CALLER__/0,__DIR__/0,__ENV__/0and__MODULE__/0) - Module attributes reader (
@foo)
If the expression cannot be expanded, it returns the expression itself. This function does not traverse the AST, only the root node is expanded.
expand_once/2 performs the expansion just once. Check expand/2
to perform expansion until the node can no longer be expanded.
Examples
In the example below, we have a macro that generates a module
with a function named name_length that returns the length
of the module name. The value of this function will be calculated
at compilation time and not at runtime.
Consider the implementation below:
defmacro defmodule_with_length(name, do: block) do
length = length(Atom.to_charlist(name))
quote do
defmodule unquote(name) do
def name_length, do: unquote(length)
unquote(block)
end
end
endWhen invoked like this:
defmodule_with_length My.Module do
def other_function, do: ...
endThe compilation will fail because My.Module when quoted
is not an atom, but a syntax tree as follows:
{:__aliases__, [], [:My, :Module]}That said, we need to expand the aliases node above to an atom, so we can retrieve its length. Expanding the node is not straightforward because we also need to expand the caller aliases. For example:
alias MyHelpers, as: My
defmodule_with_length My.Module do
def other_function, do: ...
endThe final module name will be MyHelpers.Module and not
My.Module. With Macro.expand/2, such aliases are taken
into consideration. Local and remote macros are also
expanded. We could rewrite our macro above to use this
function as:
defmacro defmodule_with_length(name, do: block) do
expanded = Macro.expand(name, __CALLER__)
length = length(Atom.to_charlist(expanded))
quote do
defmodule unquote(name) do
def name_length, do: unquote(length)
unquote(block)
end
end
end