Skip to content

Commit 12d1c7f

Browse files
authored
feat(extensions): pre-write extensions (#83)
fix(extensions): don't require a config module
1 parent 3eeb90f commit 12d1c7f

File tree

6 files changed

+76
-66
lines changed

6 files changed

+76
-66
lines changed

config/test.exs

+1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ config :logger, level: :warning
55
config :tableau, :config, url: "http://localhost:4999"
66
config :tableau, Tableau.RSSExtension, enabled: false
77
config :tableau, Tableau.PostExtension, enabled: false
8+
config :tableau, Tableau.SitemapExtension, enabled: false
89
config :tableau, Mix.Tasks.Tableau.LogExtension, enabled: true
910
config :tableau, Mix.Tasks.Tableau.FailExtension, enabled: true

lib/mix/tasks/tableau.build.ex

+55-56
Original file line numberDiff line numberDiff line change
@@ -21,34 +21,7 @@ defmodule Mix.Tasks.Tableau.Build do
2121

2222
mods = :code.all_available()
2323

24-
token =
25-
for module <- pre_build_extensions(mods), reduce: token do
26-
token ->
27-
config_mod = Module.concat([module, Config])
28-
29-
raw_config =
30-
:tableau |> Application.get_env(module, %{}) |> Map.new()
31-
32-
if raw_config[:enabled] do
33-
{:ok, config} =
34-
config_mod.new(raw_config)
35-
36-
{:ok, key} = Tableau.Extension.key(module)
37-
38-
token = put_in(token[key], config)
39-
40-
case module.run(token) do
41-
{:ok, token} ->
42-
token
43-
44-
:error ->
45-
Logger.error("#{inspect(module)} failed to run")
46-
token
47-
end
48-
else
49-
token
50-
end
51-
end
24+
token = mods |> pre_build_extensions() |> run_extensions(token)
5225

5326
mods = :code.all_available()
5427
graph = Tableau.Graph.new(mods)
@@ -60,12 +33,14 @@ defmodule Mix.Tasks.Tableau.Build do
6033
{mod, Map.new(Tableau.Graph.Nodable.opts(mod) || [])}
6134
end
6235

63-
{page_mods, pages} = Enum.unzip(pages)
36+
{page_mods, just_pages} = Enum.unzip(pages)
6437

65-
token = put_in(token.site[:pages], pages)
38+
token = put_in(token.site[:pages], just_pages)
6639

67-
for mod <- page_mods do
68-
content = Tableau.Document.render(graph, mod, token)
40+
token = mods |> pre_write_extensions() |> run_extensions(token)
41+
42+
for {mod, page} <- Enum.zip(page_mods, token.site.pages) do
43+
content = Tableau.Document.render(graph, mod, token, page)
6944
permalink = Tableau.Graph.Nodable.permalink(mod)
7045
dir = Path.join(out, permalink)
7146

@@ -78,32 +53,16 @@ defmodule Mix.Tasks.Tableau.Build do
7853
File.cp_r!(config.include_dir, out)
7954
end
8055

81-
for module <- post_write_extensions(mods), reduce: token do
82-
token ->
83-
config_mod = Module.concat([module, Config])
84-
85-
raw_config =
86-
:tableau |> Application.get_env(module, %{}) |> Map.new()
87-
88-
if raw_config[:enabled] do
89-
{:ok, config} =
90-
config_mod.new(raw_config)
91-
92-
{:ok, key} = Tableau.Extension.key(module)
93-
94-
token = put_in(token[key], config)
56+
token = run_extensions(post_write_extensions(mods), token)
9557

96-
case module.run(token) do
97-
{:ok, token} ->
98-
token
58+
token
59+
end
9960

100-
:error ->
101-
Logger.error("#{inspect(module)} failed to run")
102-
token
103-
end
104-
else
105-
token
106-
end
61+
defp validate_config(config_mod, raw_config) do
62+
if Code.ensure_loaded?(config_mod) do
63+
config_mod.new(raw_config)
64+
else
65+
{:ok, raw_config}
10766
end
10867
end
10968

@@ -118,6 +77,17 @@ defmodule Mix.Tasks.Tableau.Build do
11877
Enum.sort_by(extensions, & &1.__tableau_extension_priority__())
11978
end
12079

80+
defp pre_write_extensions(modules) do
81+
extensions =
82+
for {mod, _, _} <- modules,
83+
mod = Module.concat([to_string(mod)]),
84+
match?({:ok, :pre_write}, Tableau.Extension.type(mod)) do
85+
mod
86+
end
87+
88+
Enum.sort_by(extensions, & &1.__tableau_extension_priority__())
89+
end
90+
12191
defp post_write_extensions(modules) do
12292
extensions =
12393
for {mod, _, _} <- modules,
@@ -128,4 +98,33 @@ defmodule Mix.Tasks.Tableau.Build do
12898

12999
Enum.sort_by(extensions, & &1.__tableau_extension_priority__())
130100
end
101+
102+
defp run_extensions(extensions, token) do
103+
for module <- extensions, reduce: token do
104+
token ->
105+
config_mod = Module.concat([module, Config])
106+
107+
raw_config =
108+
:tableau |> Application.get_env(module, %{enabled: true}) |> Map.new()
109+
110+
if raw_config[:enabled] do
111+
{:ok, config} = validate_config(config_mod, raw_config)
112+
113+
{:ok, key} = Tableau.Extension.key(module)
114+
115+
token = put_in(token[key], config)
116+
117+
case module.run(token) do
118+
{:ok, token} ->
119+
token
120+
121+
:error ->
122+
Logger.error("#{inspect(module)} failed to run")
123+
token
124+
end
125+
else
126+
token
127+
end
128+
end
129+
end
131130
end

lib/tableau/document.ex

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ defmodule Tableau.Document do
2020
end
2121
end
2222

23-
def render(graph, module, assigns) do
23+
def render(graph, module, assigns, page) do
2424
[root | mods] =
2525
case Graph.dijkstra(graph, module, :root) do
2626
path when is_list(path) ->
@@ -32,7 +32,7 @@ defmodule Tableau.Document do
3232
raise "Failed to find layout path for #{inspect(module)}"
3333
end
3434

35-
page_assigns = Map.new(Tableau.Graph.Nodable.opts(module) || [])
35+
page_assigns = (Tableau.Graph.Nodable.opts(module) || []) |> Map.new() |> Map.merge(page)
3636
mods = for mod <- mods, do: {mod, page_assigns, assigns}
3737

3838
Tableau.Graph.Nodable.template(root, Map.merge(assigns, %{inner_content: mods, page: page_assigns}))

lib/tableau/extension.ex

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ defmodule Tableau.Extension do
1616
There are currently the following extension types:
1717
1818
- `:pre_build` - executed before tableau builds your site and writes anything to disk.
19+
- `:pre_write` - executed after tableau builds your site but before it writes anything to disk.
1920
- `:post_write` - executed after tableau builds your site and writes everything to disk.
2021
2122
## Example

test/mix/tasks/tableau.build_test.exs

+14-5
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,26 @@ defmodule Mix.Tasks.Tableau.FailExtension do
1717
@moduledoc false
1818
use Tableau.Extension, key: :fail, type: :pre_build, priority: 100
1919

20-
defmodule Config do
21-
@moduledoc false
22-
def new(i), do: {:ok, i}
23-
end
24-
2520
def run(_site) do
2621
IO.inspect(System.monotonic_time(), label: "first")
2722
:error
2823
end
2924
end
3025

26+
defmodule Mix.Tasks.Tableau.FooExtension do
27+
@moduledoc false
28+
use Tableau.Extension, key: :foo, type: :pre_write, priority: 100
29+
30+
def run(token) do
31+
pages =
32+
for page <- token.site.pages do
33+
Map.put(page, :foo, "bar")
34+
end
35+
36+
{:ok, put_in(token.site.pages, pages)}
37+
end
38+
end
39+
3140
defmodule Mix.Tasks.Tableau.BuildTest.About do
3241
@moduledoc false
3342
import Tableau.Strung

test/tableau/document_test.exs

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ defmodule Tableau.DocumentTest.About do
1515
:def,
1616
:template,
1717
~g'''
18-
<div id="<%= @page.yo %>">
18+
<div id="<%= @page.yo %>" class="<%= @page.foo %>">
1919
hi
2020
</div>
2121
'''html,
@@ -103,7 +103,7 @@ defmodule Tableau.DocumentTest do
103103

104104
test "renders a document" do
105105
graph = Tableau.Graph.new(:code.all_available())
106-
content = Document.render(graph, __MODULE__.About, %{site: %{}})
106+
content = Document.render(graph, __MODULE__.About, %{site: %{}}, %{foo: "bar"})
107107

108108
assert Floki.parse_document!(content) ===
109109
[
@@ -112,7 +112,7 @@ defmodule Tableau.DocumentTest do
112112
{"head", [], []},
113113
{"body", [],
114114
[
115-
{"div", [{"id", "inner-layout"}], [{"div", [{"id", "lo"}], ["\n hi\n"]}]}
115+
{"div", [{"id", "inner-layout"}], [{"div", [{"id", "lo"}, {"class", "bar"}], ["\n hi\n"]}]}
116116
]}
117117
]}
118118
]

0 commit comments

Comments
 (0)