Permalink
Browse files

Split locals and assigns, delegate more responsibilities to the handler

  • Loading branch information...
1 parent f184917 commit 41fbb83a3c7a2e1595ff8052819691c4e50c1055 @josevalim josevalim committed Sep 9, 2012
View
@@ -31,42 +31,34 @@ defmodule Dynamo.View do
@doc """
Renders the given template with the given assigns.
"""
- def render(template, assigns) do
- Dynamo.View.Renderer.render(template, Keyword.put(assigns, :template, template))
+ def render(template, locals, assigns) do
+ Dynamo.View.Renderer.render(template, locals, assigns)
end
@doc """
Compiles the given set of `templates` into a module
given by `name`. It returns the module binary,
"""
- def compile_module(name, templates) do
- { _, binary, _ } = defmodule name do
- Enum.reduce templates, 0, fn(template, i) ->
- template = template.ref({ name, :"template_#{i}" })
- def :find, [template.key], [], do: Macro.escape(template)
- i + 1
- end
-
- def find(_) do
- nil
- end
-
- args = quote hygiene: false, do: [assigns]
-
- Enum.reduce templates, 0, fn(template, i) ->
- source = Dynamo.View.Handler.get!(template.handler).compile(template)
-
- source = quote hygiene: false do
- _ = assigns
- unquote(source)
+ def compile_module(name, templates, locals) do
+ { _, binary, _ } =
+ defmodule name do
+ Enum.reduce templates, 0, fn(template, i) ->
+ template = template.ref({ name, :"template_#{i}" })
+ def :find, [template.key], [], do: Macro.escape(template)
+ i + 1
end
- @file template.identifier
- def :"template_#{i}", args, [], do: source
+ def find(_) do
+ nil
+ end
- i + 1
+ Enum.reduce templates, 0, fn(template, i) ->
+ { args, source } = template.handler.compile(template, locals)
+ @file template.identifier
+ def :"template_#{i}", args, [], do: source
+ i + 1
+ end
end
- end
binary
end
@@ -72,7 +72,7 @@ defmodule Dynamo.View.PathFinder do
key: key,
updated_at: File.stat!(path).mtime,
identifier: path,
- handler: extname(path),
+ handler: Dynamo.View.Handler.get!(extname(path)),
format: extname(File.rootname(path)),
source: File.read!(path)
]
View
@@ -9,13 +9,22 @@ defmodule Dynamo.View.Handler do
@doc """
A template handler must simply implement
compile, receiving a Dynamo.View.Template
- record.
+ record. It must return the arguments and
+ a source, which will then be compiled to
+ a function.
A template handler must be necessarily
named as Dynamo.View.EXTHandler where
EXT is the handler extension.
"""
- defcallback compile(template)
+ defcallback compile(template, locals)
+
+ @doc """
+ Receives a module and function the compiled
+ template is stored plus the locals and assigns
+ to be used on dispatch.
+ """
+ defcallback render(module, function, locals, assigns)
@doc """
Get the template handler for the given extension.
@@ -46,7 +55,26 @@ defmodule Dynamo.View.EEXHandler do
@moduledoc false
@behaviour Dynamo.View.Handler
- def compile(Dynamo.View.Template[source: source, identifier: identifier]) do
- EEx.compile_string(source, file: identifier)
+ def compile(Dynamo.View.Template[source: source, identifier: identifier], locals) do
+ locals = [:assigns|locals]
+ match = match(locals)
+ source = EEx.compile_string(source, file: identifier)
+
+ { args(locals), quote do
+ __block__ unquote(match)
+ unquote(source)
+ end }
+ end
+
+ def render(module, function, locals, assigns) do
+ apply module, function, [assigns|Keyword.values(locals)]
+ end
+
+ defp args(locals) do
+ lc name inlist locals, do: { name, 0, nil }
+ end
+
+ defp match(locals) do
+ lc name inlist locals, do: { :=, 0, [{ :_, 0, nil }, { name, 0 , nil }] }
end
end
@@ -35,15 +35,17 @@ defmodule Dynamo.View.Renderer do
The on demand mode needs to be explicitly enabled
by calling start_link/0.
"""
- def render(Template[ref: { mod, fun }], assigns) do
- apply mod, fun, [assigns]
+ def render(Template[ref: { mod, fun }, handler: handler], locals, assigns) do
+ handler.render(mod, fun, locals, assigns)
end
- def render(template, assigns) do
+ def render(Template[handler: handler] = template, locals, assigns) do
module =
- get_cached(template) || compile(template) || raise_too_busy(template)
+ get_cached(template) ||
+ compile(template, Keyword.keys(locals)) ||
+ raise_too_busy(template)
- module.render(assigns)
+ handler.render(module, :render, locals, assigns)
end
## Callbacks
@@ -66,8 +68,8 @@ defmodule Dynamo.View.Renderer do
end
end
- def handle_call({ :register, identifier, updated_at, compiled }, _from, dict) do
- if module = generate_module(compiled, identifier, 0) do
+ def handle_call({ :register, identifier, updated_at, args, source }, _from, dict) do
+ if module = generate_module(args, source, identifier, 0) do
{ :reply, module, Dict.put(dict, identifier, { module, updated_at }) }
else
{ :reply, nil, dict }
@@ -101,9 +103,9 @@ defmodule Dynamo.View.Renderer do
:gen_server.call(__MODULE__, { :get_cached, identifier, updated_at })
end
- defp compile(Template[handler: handler, identifier: identifier, updated_at: updated_at] = template) do
- compiled = Dynamo.View.Handler.get!(handler).compile(template)
- :gen_server.call(__MODULE__, { :register, identifier, updated_at, compiled })
+ defp compile(Template[handler: handler, identifier: identifier, updated_at: updated_at] = template, locals) do
+ { args, source } = handler.compile(template, locals)
+ :gen_server.call(__MODULE__, { :register, identifier, updated_at, args, source })
end
defp raise_too_busy(Template[identifier: identifier]) do
@@ -115,29 +117,23 @@ defmodule Dynamo.View.Renderer do
:code.delete(module)
end
- defp generate_module(source, identifier, attempts) when attempts < @max_attemps do
+ defp generate_module(args, source, identifier, attempts) when attempts < @max_attemps do
random = :random.uniform(@slots)
module = Module.concat(Dynamo.View, "Template#{random}")
if :code.is_loaded(module) do
- generate_module(source, identifier, attempts + 1)
+ generate_module(args, source, identifier, attempts + 1)
else
- source = quote hygiene: false do
- _ = assigns
- unquote(source)
- end
-
defmodule module do
@file identifier
- args = quote hygiene: false, do: [assigns]
def :render, args, [], do: source
end
module
end
end
- defp generate_module(_, _, _) do
+ defp generate_module(_, _, _, _) do
nil
end
end
@@ -115,7 +115,7 @@ defmodule Mix.Tasks.Compile.Dynamo do
view_path.eager?,
template inlist view_path.all, do: template
- binary = Dynamo.View.compile_module(name, templates)
+ binary = Dynamo.View.compile_module(name, templates, [:conn])
File.write! File.join(compile_path, "#{name}.beam"), binary
Mix.shell.info "Generated #{inspect name}"
@@ -10,7 +10,7 @@ defmodule Dynamo.View.PathFinderTest do
path = File.join(@fixture_path, "hello.html.eex")
assert Dynamo.View.Template[identifier: ^path, key: "hello.html",
- handler: "eex", format: "html"] = @path_finder.find "hello.html"
+ handler: Dynamo.View.EEXHandler, format: "html"] = @path_finder.find "hello.html"
end
test "returns all templates" do
@@ -52,19 +52,19 @@ defmodule Dynamo.ViewTest do
end
test "compiles a module with the given templates" do
- Dynamo.View.compile_module(CompileTest.Sample0, @path_finder.all)
+ Dynamo.View.compile_module(CompileTest.Sample0, @path_finder.all, [])
path = File.join(@fixture_path, "hello.html.eex")
template = CompileTest.Sample0.find "hello.html"
assert Dynamo.View.Template[identifier: ^path, key: "hello.html",
- handler: "eex", format: "html", ref: { CompileTest.Sample0, _ }] = template
+ handler: Dynamo.View.EEXHandler, format: "html", ref: { CompileTest.Sample0, _ }] = template
{ mod, fun } = template.ref
assert apply(mod, fun, [[]]) == "HELLO!"
end
defp render(query) do
- Dynamo.View.render Dynamo.View.find(query, @view_paths), []
+ Dynamo.View.render Dynamo.View.find(query, @view_paths), [], []
end
end

0 comments on commit 41fbb83

Please sign in to comment.