According to Metaprogramming Elixir
p.39, it says:
Elixir allows us to set a special module attribute, @before_compile, to notify the compiler that an extra step is required just before compilation is finished.
Then why isn’t it named @after_compile?
According to the Elixir Getting Started Guide:
Finally, callbacks such as
@before_compile
allow us to inject code into the module when its definition is complete.
Is the end of “module definition” the same thing as the “end of compilation”?
Finally, the Module docs think @before_compile works the the opposite of what Metaprogramming Elixir
says:
A hook that will be invoked before the module is compiled.
…which makes more sense to me given @before_compile’s name.
However, the Module docs also say:
@before_compile
…
…
Note : unlike@after_compile
, the callback function/macro must be placed in a separate module (because when the callback is invoked, the current module does not yet exist).
Yet, the example in Metaprogramming Elixir puts the callback macro inside the same module that specifies @before_compile.
My survey of the literature reveals that @before_compile
is not well understood.
My question is why the example on p.39 cannot be modified like this:
defmacro __using__(_options) do
quote do
import unquote(__MODULE__)
Module.register_attribute(__MODULE__, :tests, accumulate: true)
@before_compile unquote(__MODULE__)
end
end
defmacro __before_compile__(_env) do
IO.inspect @tests #******* WARNING *********
quote do
def run do
IO.puts "Running the tests: (#{inspect @tests})"
end
end
end
I get a warning:
warning: undefined module attribute @tests, please remove access to @tests or explicitly set it before access
my.ex:15: Assertion (module)
If @tests is replaced at compile time inside the quote block, why isn’t @tests replaced at compile time outside the quote block?