Packages

Elixir library to handle generic routing tasks in Plug.Router and Phoenix router style

Current section

Files

Jump to
gen_router lib controller.ex
Raw

lib/controller.ex

defmodule GenRouter.Controller do
@moduledoc """
Boilerplate to define controller in scope of GenRouter.
"""
@doc """
Callable plugs in controllers.
"""
defmacro plug(ast, opts \\ []) do
{plug, guard} =
case ast do
{:when, _, [plug | guard]} -> {plug, guard}
plug -> {plug, true}
end
quote do
@plugs {unquote(plug), unquote(opts), unquote(Macro.escape(guard))}
end
end
defmacro __before_compile__(env) do
plugs = Module.get_attribute(env.module, :plugs)
quote do
defp plugs, do: unquote(Macro.escape(plugs))
end
end
@doc """
Custom controller factory.
"""
defmacro __using__(_opts) do
quote do
alias GenRouter.Conn
import GenRouter.Conn
import GenRouter.Controller
Module.register_attribute(__MODULE__, :plugs, accumulate: true)
@before_compile GenRouter.Controller
@doc """
Do matching to a proper controller action.
"""
@spec do_action(atom(), Conn.t(), Keyword.t()) :: Conn.t()
def do_action(action, conn, opts \\ []) do
conn =
plugs()
|> Enum.reverse()
|> Enum.reduce(conn, fn {plug, plug_opts, guards}, conn ->
guards =
if is_boolean(guards) do
guards
else
{[guards], _} = Code.eval_quoted(guards, action: action)
guards
end
if guards do
apply(plug, :call, [conn, plug_opts])
else
conn
end
end)
unless conn.halted do
apply(__MODULE__, action, [conn, opts])
else
conn
end
end
end
end
end