I have a demo app “rlp” from this topic. Looking at rlp_web.ex
I notice this:
This can be used in your application as:
use RlpWeb, :controller
use RlpWeb, :view
Shortly thereafter this:
def controller do
quote do
use Phoenix.Controller, namespace: RlpWeb
import Plug.Conn
import RlpWeb.Router.Helpers
import RlpWeb.Gettext
end
end
def view do
quote do
use Phoenix.View, root: "lib/rlp_web/templates",
namespace: RlpWeb
# Import convenience functions from controllers
import Phoenix.Controller, only: [get_flash: 2, view_module: 1]
# Use all HTML functionality (forms, tags, etc)
use Phoenix.HTML
import RlpWeb.Router.Helpers
import RlpWeb.ErrorHelpers
import RlpWeb.Gettext
end
end
def router do
quote do
use Phoenix.Router
import Plug.Conn
import Phoenix.Controller
end
end
def channel do
quote do
use Phoenix.Channel
import RlpWeb.Gettext
end
end
One thing you should notice is that each of these functions wrap:
quote do
...
end
That should tell you that the controller
, view
, router
, channel
functions generate code. This happens at compile-time, not run-time. So these functions are intended for compile-time use, not run-time use.
defmacro __using__(which) when is_atom(which) do
apply(__MODULE__, which, [])
end
apply
is simply Kernel.apply/3
. And again defmacro
tells you that you are dealing with a compile-time construct.
So
use RlpWeb, :controller
would become at compile time
Kernel.apply(RlpWeb, :controller, [])
which is equivalent to
RlpWeb.controller()
which refers to that function we’ve just come across. So in page_controller.ex
:
defmodule RlpWeb.PageController do
use RlpWeb, :controller
def index(conn, _params) do
render conn, "index.html"
end
end
The use RlpWeb, :controller
causes RlpWeb.controller()
to be run at compile time which results in the code wrapped in quote do ... end
being dumped unceremoniously into RlpWeb.PageController
resulting in
defmodule RlpWeb.PageController do
use Phoenix.Controller, namespace: RlpWeb
import Plug.Conn
import RlpWeb.Router.Helpers
import RlpWeb.Gettext
def index(conn, _params) do
render conn, "index.html"
end
end
Notice how there is now another use
there that needs exactly the same treatment during compile time.
Understanding exactly what code becomes available when during compilation can be a bit confusing. For that How does Elixir compile/execute code? may help.