Current section

Files

Jump to
mazurka lib mazurka dispatch.ex
Raw

lib/mazurka/dispatch.ex

defmodule Mazurka.Dispatch do
alias Mazurka.Compiler.Utils
defmacro __using__(_opts) do
quote do
import Mazurka.Dispatch
@before_compile Mazurka.Dispatch
defmacro __using__(_) do
dispatch = __MODULE__
quote do
def call(conn, opts) do
conn = conn
|> Plug.Conn.put_private(:mazurka_dispatch, unquote(dispatch))
|> Plug.Conn.put_private(:mazurka_router, __MODULE__)
super(conn, opts)
end
end
end
use Mazurka.Dispatch.BuiltIn
def resolve(module, function, arguments, conn, parent, ref, attrs) do
exec(module, function, arguments, conn, parent, ref, attrs)
end
end
end
defmacro __before_compile__(_) do
quote do
defp exec(module, function, args, %{private: %{mazurka_dispatch: dispatch}}, _parent, _ref, _attrs) do
raise %Mazurka.Dispatch.Exception{module: module, function: function, arity: length(args), dispatch: dispatch}
end
end
end
defmacro env(_env, [do: _block]) do
nil
end
defmacro service(definition) do
quote do
service unquote(definition), do: []
end
end
defmacro service(definition, [do: _] = do_block) do
case unescape(definition, __CALLER__) do
{module, function, arity} ->
args = gen_pos_args(arity)
quote do
service unquote(definition), unquote(module).unquote(function)(unquote_splicing(args)), unquote(do_block)
end
_ ->
quote do
service unquote(definition), unquote(definition), unquote(do_block)
end
end
end
defmacro service(source, target) do
quote do
service unquote(source), unquote(target), do: []
end
end
defmacro service(source, target, [do: _middleware]) do
case {unescape(source, __CALLER__), unescape(target, __CALLER__)} do
{{s_module, s_function, s_arity}, {t_module, t_function, t_args}} ->
s_args = gen_args(s_arity)
quote do
defp exec(unquote(s_module), unquote(s_function), unquote(s_args), var!(_conn), var!(_parent), var!(_ref), var!(_attrs)) do
unquote(t_module).unquote(t_function)(unquote_splicing(t_args))
end
end
{s_module, t_module} ->
quote do
defp exec(unquote(s_module), function, args, var!(_conn), var!(_parent), var!(_ref), var!(_attrs)) do
apply(unquote(t_module), function, args)
end
end
end
end
defp gen_args(arity) do
:lists.seq(1, arity)
|> Enum.map(&var/1)
end
defp gen_pos_args(arity) do
:lists.seq(1, arity)
|> Enum.map(fn(i) ->
{:&, [], [i]}
end)
end
defp unescape({:/, _, [{{:., _, [module, function]}, _, _}, arity]}, caller) do
module = Utils.eval(module, caller)
function = Utils.eval(function, caller)
{module, function, arity}
end
defp unescape({:__aliases__, _, _} = module, caller) do
Utils.eval(module, caller)
end
defp unescape({{:., _meta, [module, function]}, _, args}, caller) do
module = Utils.eval(module, caller)
function = Utils.eval(function, caller)
args = Enum.map(args, fn
({:&, _, [item]}) ->
var(item)
({:self, _, _}) ->
Macro.var(:_self, nil)
({:conn, _, _}) ->
Macro.var(:_conn, nil)
({:ref, _, _}) ->
Macro.var(:_ref, nil)
({:env, _, _}) ->
quote do
var!(_conn).private[:mazurka_env] || :prod
end
(other) ->
Utils.eval(other, caller) |> Macro.escape
end)
{module, function, args}
end
defp var(i) do
"_arg_#{i}"
|> String.to_atom
|> Macro.var(nil)
end
end