Packages
plug
0.7.0
1.20.3
1.20.2
1.20.1
retired
1.20.0
retired
1.19.5
1.19.4
1.19.3
1.19.2
1.19.1
1.19.0
1.18.5
1.18.4
1.18.3
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.6
1.16.5
1.16.4
1.16.3
1.16.2
1.16.1
1.16.0
1.15.6
1.15.5
1.15.4
1.15.3
1.15.2
1.15.1
1.15.0
1.14.2
1.14.1
1.14.0
1.13.6
1.13.5
1.13.4
1.13.3
1.13.2
1.13.1
retired
1.13.0
retired
1.12.1
1.12.0
1.11.1
1.11.0
1.10.4
1.10.3
1.10.2
1.10.1
1.10.0
1.9.0
1.8.3
1.8.2
1.8.1
1.8.0
1.7.2
1.7.1
1.7.0
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.5.0-rc.2
1.5.0-rc.1
1.5.0-rc.0
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-rc.0
1.3.6
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc.0
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.14.0
0.13.1
0.13.0
0.12.2
0.12.1
0.12.0
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.0
0.5.3
0.5.2
0.5.1
0.5.0
0.4.4
0.4.3
0.4.2
0.4.1
Compose web applications with functions
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/plug/builder.ex
defmodule Plug.Builder do
alias Plug.Conn
@moduledoc """
Conveniences for building plugs.
This module can be used into a module in order to build
a plug stack:
defmodule MyApp do
use Plug.Builder
plug :hello, upper: true
def hello(conn, opts) do
body = if opts[:upper], do: "WORLD", else: "world"
send_resp(conn, 200, body)
end
end
`Plug.Builder` will define a `init/1` function (which is overridable)
and a `call/2` function with the compiled stack. By implementing the
Plug API, `Plug.Builder` guarantees this module can be handed to a web
server or used as part of another stack.
Note this module also exports a `compile/1` function for those willing
to collect and compile their plugs manually.
## Halting a Plug Stack
A Plug Stack can be halted with `Plug.Conn.halt/1`. The Builder will prevent
further plugs downstream from being invoked and return current connection.
"""
@type plug :: module | atom
@doc false
defmacro __using__(_) do
quote do
@behaviour Plug
def init(opts) do
opts
end
def call(conn, opts) do
plug_builder_call(conn, opts)
end
defoverridable [init: 1, call: 2]
import Plug.Builder, only: [plug: 1, plug: 2]
Module.register_attribute(__MODULE__, :plugs, accumulate: true)
@before_compile Plug.Builder
end
end
@doc false
defmacro __before_compile__(env) do
plugs = Module.get_attribute(env.module, :plugs)
{conn, body} = Plug.Builder.compile(plugs)
quote do
defp plug_builder_call(unquote(conn), _), do: unquote(body)
end
end
@doc """
A macro that stores a new plug.
"""
defmacro plug(plug, opts \\ []) do
quote do
@plugs {unquote(plug), unquote(opts)}
end
end
@doc """
Compiles a plug stack.
It expects a reversed stack (with the last plug coming first)
and returns a tuple containing the reference to the connection
as first argument and the compiled quote stack.
"""
@spec compile([{plug, Plug.opts}]) :: {Macro.t, Macro.t}
def compile(stack) do
conn = quote do: conn
{conn, Enum.reduce(stack, conn, "e_plug(init_plug(&1), &2))}
end
defp init_plug({plug, opts}) do
case Atom.to_char_list(plug) do
'Elixir.' ++ _ ->
init_module_plug(plug, opts)
_ ->
init_fun_plug(plug, opts)
end
end
defp init_module_plug(plug, opts) do
opts = plug.init(opts)
if function_exported?(plug, :call, 2) do
{:call, plug, opts}
else
raise ArgumentError, message: "#{inspect plug} plug must implement call/2"
end
end
defp init_fun_plug(plug, opts) do
{:fun, plug, opts}
end
defp quote_plug({:call, plug, opts}, acc) do
quote do
case unquote(plug).call(conn, unquote(Macro.escape(opts))) do
%Conn{halted: true} = conn -> conn
%Conn{} = conn -> unquote(acc)
_ -> raise "expected #{unquote(inspect plug)}.call/2 to return a Plug.Conn"
end
end
end
defp quote_plug({:fun, plug, opts}, acc) do
quote do
case unquote(plug)(conn, unquote(Macro.escape(opts))) do
%Conn{halted: true} = conn -> conn
%Conn{} = conn -> unquote(acc)
_ -> raise "expected #{unquote(plug)}/2 to return a Plug.Conn"
end
end
end
end