Skip to content

Commit e39efa4

Browse files
authored
feat(pages, posts): use custom converter in frontmatter (#113)
Allow a page or post to specify a custom converter in the frontmatter. The frontmatter key `:converter` is optional. If included, it should specify a string-value of a converter module. If not included, the default config setting will be used. Closes #112
1 parent 8b73de1 commit e39efa4

File tree

4 files changed

+95
-8
lines changed

4 files changed

+95
-8
lines changed

lib/tableau/extensions/page_extension.ex

+17-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ defmodule Tableau.PageExtension do
1111
* `:title` - The title of the page
1212
* `:permalink` - The permalink of the page.
1313
* `:layout` - A string representation of a Tableau layout module.
14+
* `:converter` - A string representation of a converter module. (optional)
1415
1516
## Example
1617
@@ -19,6 +20,7 @@ defmodule Tableau.PageExtension do
1920
title: "Getting Started"
2021
permalink: "/docs/:title"
2122
layout: "ElixirTools.PageLayout"
23+
converter: "MyConverter"
2224
```
2325
2426
## Permalink
@@ -59,6 +61,8 @@ defmodule Tableau.PageExtension do
5961
adoc: MySite.AsciiDocConverter
6062
],
6163
```
64+
65+
As noted above, a converter can be overridden on a specific page, using the frontmatter `:converter` key.
6266
"""
6367

6468
use Tableau.Extension, key: :pages, type: :pre_build, priority: 100
@@ -88,10 +92,11 @@ defmodule Tableau.PageExtension do
8892
config.dir
8993
|> Path.join("**/*.{#{exts}}")
9094
|> Common.paths()
91-
|> Common.entries(fn %{path: path, ext: ext, front_matter: front_matter, pre_convert_body: pre_convert_body} ->
92-
renderer = fn assigns -> converters[ext].convert(path, front_matter, pre_convert_body, assigns) end
93-
94-
{build(path, front_matter, pre_convert_body, config), renderer}
95+
|> Common.entries(fn pathmap ->
96+
{
97+
build(pathmap.path, pathmap.front_matter, pathmap.pre_convert_body, config),
98+
fn assigns -> pick_module_and_convert(converters, pathmap, assigns) end
99+
}
95100
end)
96101

97102
graph =
@@ -108,6 +113,14 @@ defmodule Tableau.PageExtension do
108113
|> Map.put(:graph, graph)}
109114
end
110115

116+
defp to_module(nil), do: nil
117+
defp to_module(string) when is_binary(string), do: Module.concat(string, nil)
118+
119+
defp pick_module_and_convert(converters, pathmap, assigns) do
120+
cnv_module = to_module(pathmap.front_matter[:converter]) || converters[pathmap.ext]
121+
cnv_module.convert(pathmap.path, pathmap.front_matter, pathmap.pre_convert_body, assigns)
122+
end
123+
111124
defp build(filename, front_matter, body, pages_config) do
112125
front_matter
113126
|> Map.put(:__tableau_page_extension__, true)

lib/tableau/extensions/post_extension.ex

+17-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ defmodule Tableau.PostExtension do
1212
* `:permalink` - The permalink of the post. `:title` will be replaced with the posts title and non alphanumeric characters removed. Optional.
1313
* `:date` - A string representation of an Elixir `NaiveDateTime`, often presented as a `sigil_N`. This will be converted to your configured timezone.
1414
* `:layout` - A string representation of a Tableau layout module.
15+
* `:converter` - A string representation of a converter module. (optional)
1516
1617
## Example
1718
@@ -21,6 +22,7 @@ defmodule Tableau.PostExtension do
2122
permalink: "/news/:title"
2223
date: "~N[2023-09-19 01:00:00]"
2324
layout: "ElixirTools.PostLayout"
25+
converter: "MyConverter"
2426
```
2527
2628
## Permalink
@@ -65,6 +67,8 @@ defmodule Tableau.PostExtension do
6567
adoc: MySite.AsciiDocConverter
6668
],
6769
```
70+
71+
As noted above, a converter can be overridden on a specific page, using the frontmatter `:converter` key.
6872
"""
6973

7074
use Tableau.Extension, key: :posts, type: :pre_build, priority: 100
@@ -96,10 +100,11 @@ defmodule Tableau.PostExtension do
96100
config.dir
97101
|> Path.join("**/*.{#{exts}}")
98102
|> Common.paths()
99-
|> Common.entries(fn %{path: path, ext: ext, front_matter: front_matter, pre_convert_body: pre_convert_body} ->
100-
renderer = fn assigns -> converters[ext].convert(path, front_matter, pre_convert_body, assigns) end
101-
102-
{build(path, front_matter, pre_convert_body, config), renderer}
103+
|> Common.entries(fn pathmap ->
104+
{
105+
build(pathmap.path, pathmap.front_matter, pathmap.pre_convert_body, config),
106+
fn assigns -> pick_module_and_convert(converters, pathmap, assigns) end
107+
}
103108
end)
104109
|> Enum.sort_by(fn {post, _} -> post.date end, {:desc, DateTime})
105110
|> then(fn posts ->
@@ -124,6 +129,14 @@ defmodule Tableau.PostExtension do
124129
|> Map.put(:graph, graph)}
125130
end
126131

132+
defp to_module(nil), do: nil
133+
defp to_module(string) when is_binary(string), do: Module.concat(string, nil)
134+
135+
defp pick_module_and_convert(converters, pathmap, assigns) do
136+
cnv_module = to_module(pathmap.front_matter[:converter]) || converters[pathmap.ext]
137+
cnv_module.convert(pathmap.path, pathmap.front_matter, pathmap.pre_convert_body, assigns)
138+
end
139+
127140
defp build(filename, attrs, body, posts_config) do
128141
Application.put_env(:date_time_parser, :include_zones_from, ~N[2010-01-01T00:00:00])
129142

test/tableau/extensions/page_extension_test.exs

+29
Original file line numberDiff line numberDiff line change
@@ -228,5 +228,34 @@ defmodule Tableau.PageExtensionTest do
228228
]
229229
} = token
230230
end
231+
232+
test "renders with a custom converter in frontmatter", %{tmp_dir: dir, token: token} do
233+
File.write(Path.join(dir, "a-page.md"), """
234+
---
235+
title: missing layout key
236+
type: articles
237+
permalink: /:type/:title
238+
converter: "Tableau.MDExConverter"
239+
---
240+
241+
A great page
242+
""")
243+
244+
assert {:ok, token} = PageExtension.run(token)
245+
246+
assert %{
247+
pages: [
248+
%{
249+
__tableau_page_extension__: true,
250+
body: "\nA great page\n",
251+
file: ^dir <> "/a-page.md",
252+
layout: Blog.DefaultPageLayout,
253+
permalink: "/articles/missing-layout-key",
254+
title: "missing layout key",
255+
type: "articles"
256+
}
257+
]
258+
} = token
259+
end
231260
end
232261
end

test/tableau/extensions/post_extension_test.exs

+32
Original file line numberDiff line numberDiff line change
@@ -291,5 +291,37 @@ defmodule Tableau.PostExtensionTest do
291291
]
292292
} = token
293293
end
294+
295+
test "renders with a custom converter in frontmatter", %{tmp_dir: dir, token: token} do
296+
File.write(Path.join(dir, "a-post.md"), """
297+
---
298+
title: foo man chu_foo.js
299+
type: articles
300+
layout: Some.Layout
301+
date: 2023-02-01 00:01:00
302+
permalink: /:type/:year/:month/:day/:title
303+
converter: "Tableau.MDExConverter"
304+
---
305+
306+
A great post
307+
""")
308+
309+
assert {:ok, token} = PostExtension.run(token)
310+
311+
assert %{
312+
posts: [
313+
%{
314+
__tableau_post_extension__: true,
315+
body: "\nA great post\n",
316+
date: ~U[2023-02-01 00:01:00Z],
317+
file: ^dir <> "/a-post.md",
318+
layout: Some.Layout,
319+
permalink: "/articles/2023/02/01/foo-man-chu-foo.js",
320+
title: "foo man chu_foo.js",
321+
type: "articles"
322+
}
323+
]
324+
} = token
325+
end
294326
end
295327
end

0 commit comments

Comments
 (0)