Reputation: 7098
I am trying to get my head around the elixir module lifecycle and one thing that I have noticed is that calling a plug macro in the before_compile block doesn't execute the plug when the calling the controller. It was my understanding that this block executes right before compilation so the plug macro would also be compiled in the module.
For given this:
defmacro __before_compile__(env) do
quote do
plug :say_hi
end
end
With a method in a phoinex controller:
def say_hi(conn, _) do
IO.inspect("hello")
end
This will not print hello, where as having the same quoted block in a using block will. What am I missing?
Chris
Upvotes: 1
Views: 240
Reputation: 961
Per the relevant documentation on Module
and compilation callbacks, __before_compile__
needs to invoked in the target module with @before_compile MyApp.MyModule
(where MyApp.MyModule
is the name of your module).
If you're trying to make __before_compile__
happen in another module that use
s your module, you can define __using__
and __before_compile__
, like so:
defmodule MyApp.MyModule do
defmacro __using__(_) do
quote do
@before_compile MyApp.MyModule
end
end
defmacro __before_compile__(env) do
quote do
plug :say_hi
end
end
end
The Sugar web development framework has a relatively simple real-world demonstration of how this works in its controller code; when you call use Sugar.Controller
in a controller module (say, MyApp.Controllers.Main
), the Sugar.Controller.__using__/1
macro is invoked, which in turn causes @before_compile Sugar.Controller
to be invoked in the context of MyApp.Controllers.Main
, thus doing a bunch of behind-the-scenes Plug-related magic (mostly implementing the Plug
behavior, but that's a bit beside the point here).
Phoenix also does similar similar things with its controllers, though with a bit of indirection; Phoenix.Controller.Pipeline
is another good demonstration of this pattern (albeit more complex).
On an unrelated note, I've had very mixed results with getting IO.inspect
or IO.puts
(or IO.
anything, for that matter) to actually show up in this sort of situation. You might want to try require Logger; Logger.info "hello"
instead.
Upvotes: 1