defmodule SuperPlug do @moduledoc """ Give your Plug superpowers! ## Usage defmodule FooPlug do use SuperPlug def init(opts) do ... end def call(conn, opts) do ... end end ## Primary Superpower `call/1` initializes default options. iex> conn = %{assigns: %{}} ...> FooPlug.call(conn) %{assigns: %{fooed?: false}} ## Secondary Superpower `call/2` initializes keyword options. iex> conn = %{assigns: %{}} ...> FooPlug.call(conn, foo?: true) %{assigns: %{fooed?: true}} ## Tertiary Superpower `call/2` short circuits if an error is assigned. iex> conn = %{assigns: %{error: :not_found}} ...> FooPlug.call(conn) %{assigns: %{error: :not_found}} It can be configured to return the error as a tuple. defmodule BarPlug do use SuperPlug, return_error_as_tuple: true ... end iex> conn = %{assigns: %{error: :not_found}} ...> BarPlug.call(conn) {:error, :not_found, %{assigns: %{error: :not_found}}} """ defmacro __using__(return_error_as_tuple: true) do quote do def call(conn), do: call(conn, init([])) def call(conn, opts) when is_list(opts), do: call(conn, init(opts)) def call(conn = %{assigns: %{error: error}}, _), do: {:error, error, conn} end end defmacro __using__(_opts) do quote do def call(conn), do: call(conn, init([])) def call(conn, opts) when is_list(opts), do: call(conn, init(opts)) def call(conn = %{assigns: %{error: _}}, _), do: conn end end end