diff --git a/lib/plug/router.ex b/lib/plug/router.ex index 4c9c07f9..0c754b74 100644 --- a/lib/plug/router.ex +++ b/lib/plug/router.ex @@ -267,22 +267,31 @@ defmodule Plug.Router do init_mode = Module.get_attribute(env.module, :plug_builder_opts)[:init_mode] defs = - for {callback, {mod, opts}} <- router_to do - if init_mode == :runtime do - quote do - defp unquote(callback)(conn, _opts) do - unquote(mod).call(conn, unquote(mod).init(unquote(Macro.escape(opts)))) + for {callback, {target, opts}} <- router_to do + case {init_mode, Atom.to_string(target)} do + {:runtime, "Elixir." <> _} -> + quote do + defp unquote(callback)(conn, _opts) do + unquote(target).call(conn, unquote(target).init(unquote(Macro.escape(opts)))) + end + end + + {_, "Elixir." <> _} -> + opts = target.init(opts) + + quote do + defp unquote(callback)(conn, _opts) do + require unquote(target) + unquote(target).call(conn, unquote(Macro.escape(opts))) + end end - end - else - opts = mod.init(opts) - - quote do - defp unquote(callback)(conn, _opts) do - require unquote(mod) - unquote(mod).call(conn, unquote(Macro.escape(opts))) + + _ -> + quote do + defp unquote(callback)(conn, _opts) do + unquote(target)(conn, unquote(Macro.escape(opts))) + end end - end end end @@ -575,6 +584,7 @@ defmodule Plug.Router do router_to = Module.get_attribute(module, :plug_router_to) callback = :"plug_router_to_#{map_size(router_to)}" router_to = Map.put(router_to, callback, {to, init_opts}) + Module.put_attribute(module, :plug_router_to, router_to) {Macro.var(callback, nil), options} end diff --git a/test/plug/router_test.exs b/test/plug/router_test.exs index b6fed1e3..3886fba2 100644 --- a/test/plug/router_test.exs +++ b/test/plug/router_test.exs @@ -206,12 +206,18 @@ defmodule Plug.RouterTest do forward "/plug/init_opts", to: plug, init_opts: opts, private: %{baz: :qux} forward "/plug/forward_local", to: :forward_local + match "/plug/match_local", to: :match_local forward "/plug/forward_local_opts", to: :forward_local, init_opts: opts, private: %{baz: :qux} + match "/plug/match_local_opts", to: :match_local, init_opts: opts, private: %{baz: :qux} def forward_local(conn, opts) do resp(conn, 200, "#{inspect(opts)}") end + def match_local(conn, opts) do + resp(conn, 200, "#{inspect(opts)}") + end + match _ do resp(conn, 404, "oops") end @@ -586,12 +592,23 @@ defmodule Plug.RouterTest do assert conn.resp_body == "[]" end + test "matches to a function plug" do + conn = call(Sample, conn(:get, "/plug/match_local")) + assert conn.resp_body == "[]" + end + test "forwards to a function plug with options" do conn = call(Sample, conn(:get, "/plug/forward_local_opts")) assert conn.private[:baz] == :qux assert conn.resp_body == ":hello" end + test "matches to a function plug with options" do + conn = call(Sample, conn(:get, "/plug/match_local_opts")) + assert conn.private[:baz] == :qux + assert conn.resp_body == ":hello" + end + test "emit start and stop event when router dispatches" do start_router_id = {:start, :rand.uniform(100)} stop_router_id = {:stop, :rand.uniform(100)}