Skip to content

Instantly share code, notes, and snippets.

@carlosipe
Forked from aportnov/router.ex
Created February 7, 2018 14:22
Show Gist options
  • Save carlosipe/9429521c1bd3e2ac1fd79d903c7de194 to your computer and use it in GitHub Desktop.
Save carlosipe/9429521c1bd3e2ac1fd79d903c7de194 to your computer and use it in GitHub Desktop.
Elixir: Compiled EEx templates in Plug application
defmodule MyModule.Router do
@moduledoc """
Http Entry Point
"""
use Plug.Router
use Plug.ErrorHandler
plug Plug.Logger
plug :match
plug :dispatch
use MyModule.View
get "/hello/:name" do
send_resp(conn, 200, render("sample/template", name: name))
end
match _ do
send_resp(conn, 404, "Not found")
end
defp handle_errors(conn, %{kind: _kind, reason: _reason, stack: _stack}) do
send_resp(conn, conn.status, "Something went wrong")
end
end
@moduledoc """
Compilation Notes:
EEx expects @var notation to be defined inside :assigns keyword list,
so by doing var!(assigns) to a function params, it turns that into expected :assigns variable inside EEx generated AST
def unquote(name)(var!(assigns)) do
doing:
_ = var!(assigns)
basically clears warnings, in cases where no @var_name variables are used in the template
"""
defmodule MyModule.Template do
@templates "web/templates"
defmacro __using__(_options) do
quote do
require EEx
import unquote(__MODULE__)
@before_compile unquote(__MODULE__)
end
end
defmacro __before_compile__(_env) do
templates = find_templates
ast = templates |> Enum.map(fn(path) -> compile(path) end)
quote do
unquote(ast)
end
end
def view_name(@templates <> path), do: view_name(path)
def view_name("/" <> path), do: view_name(path)
def view_name(path) do
path
|> String.downcase
|> String.replace("/", "_")
|> String.replace(".eex", "")
|> String.to_atom
end
defp find_templates(), do: find_templates(@templates)
defp find_templates(root) do
Path.wildcard("#{root}/**/*.eex")
end
defp compile(path) do
name = view_name(path)
block = EEx.compile_file(path)
quote do
@file unquote(path)
@external_resource unquote(path)
def unquote(name)(var!(assigns)) do
_ = var!(assigns)
unquote(block)
end
end
end
end
defmodule MyModule.View do
use MyModule.Template
def render(path, assigns) do
name = view_name(path)
apply(__MODULE__, name, [assigns])
end
defmacro __using__(_options) do
quote do
import unquote(__MODULE__)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment