Skip to content

Commit 5b9cd77

Browse files
authored
Merge pull request #1542 from rust-lang/senekor/txwlxzqokmyl
Replace tera filters with macros
2 parents a98611f + c8bcfd9 commit 5b9cd77

File tree

10 files changed

+103
-106
lines changed

10 files changed

+103
-106
lines changed

src/blogs.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ pub struct Blog {
3737
maintained_by: String,
3838
index_html: String,
3939
#[serde(serialize_with = "add_postfix_slash")]
40-
prefix: PathBuf,
41-
posts: Vec<Post>,
40+
path: PathBuf,
41+
pages: Vec<Post>,
4242
}
4343

4444
impl Blog {
45-
fn load(prefix: PathBuf, dir: &Path) -> eyre::Result<Self> {
45+
fn load(path: PathBuf, dir: &Path) -> eyre::Result<Self> {
4646
let manifest_content = std::fs::read_to_string(dir.join(MANIFEST_FILE))?
4747
.strip_prefix("+++\n")
4848
.unwrap()
@@ -94,8 +94,8 @@ impl Blog {
9494
maintained_by: manifest.maintained_by,
9595
index_html: manifest.index_html,
9696
link_text: manifest.link_text,
97-
prefix,
98-
posts,
97+
path,
98+
pages: posts,
9999
})
100100
}
101101

@@ -111,12 +111,12 @@ impl Blog {
111111
&self.index_title
112112
}
113113

114-
pub(crate) fn prefix(&self) -> &Path {
115-
&self.prefix
114+
pub(crate) fn path(&self) -> &Path {
115+
&self.path
116116
}
117117

118118
pub(crate) fn posts(&self) -> &[Post] {
119-
&self.posts
119+
&self.pages
120120
}
121121
}
122122

@@ -139,10 +139,10 @@ fn load_recursive(base: &Path, current: &Path, blogs: &mut Vec<Blog>) -> eyre::R
139139
let file_name = path.file_name().and_then(|n| n.to_str());
140140
if let (Some(file_name), Some(parent)) = (file_name, path.parent()) {
141141
if file_name == MANIFEST_FILE {
142-
let prefix = parent
142+
let path = parent
143143
.strip_prefix(base)
144144
.map_or_else(|_| PathBuf::new(), Path::to_path_buf);
145-
blogs.push(Blog::load(prefix, parent)?);
145+
blogs.push(Blog::load(path, parent)?);
146146
}
147147
}
148148
}

src/lib.rs

Lines changed: 13 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use rayon::prelude::*;
99
use sass_rs::{Options, compile_file};
1010
use serde::Serialize;
1111
use serde_json::{Value, json};
12-
use std::collections::HashMap;
1312
use std::fs::{self, File};
1413
use std::io::{self, Write};
1514
use std::path::{Path, PathBuf};
@@ -33,53 +32,12 @@ struct ReleasePost {
3332
url: String,
3433
}
3534

36-
fn month_name(month_num: &Value, _args: &HashMap<String, Value>) -> tera::Result<Value> {
37-
let month_num = month_num
38-
.as_u64()
39-
.expect("month_num should be an unsigned integer");
40-
let name = match month_num {
41-
1 => "Jan.",
42-
2 => "Feb.",
43-
3 => "Mar.",
44-
4 => "Apr.",
45-
5 => "May",
46-
6 => "June",
47-
7 => "July",
48-
8 => "Aug.",
49-
9 => "Sept.",
50-
10 => "Oct.",
51-
11 => "Nov.",
52-
12 => "Dec.",
53-
_ => panic!("invalid month! ({month_num})"),
54-
};
55-
Ok(name.into())
56-
}
57-
58-
// Tera and Handlebars escape HTML differently by default.
59-
// Tera: &<>"'/
60-
// Handlebars: &<>"'`=
61-
// To make the transition testable, this function escapes just like Handlebars.
62-
fn escape_hbs(input: &Value, _args: &HashMap<String, Value>) -> tera::Result<Value> {
63-
let input = input.as_str().expect("input should be a string");
64-
Ok(input
65-
.replace("&", "&amp;")
66-
.replace("<", "&lt;")
67-
.replace(">", "&gt;")
68-
.replace("\"", "&quot;")
69-
.replace("'", "&#x27;")
70-
.replace("`", "&#x60;")
71-
.replace("=", "&#x3D;")
72-
.into())
73-
}
74-
7535
impl Generator {
7636
fn new(
7737
out_directory: impl AsRef<Path>,
7838
posts_directory: impl AsRef<Path>,
7939
) -> eyre::Result<Self> {
8040
let mut tera = Tera::new("templates/*")?;
81-
tera.register_filter("month_name", month_name);
82-
tera.register_filter("escape_hbs", escape_hbs);
8341
tera.autoescape_on(vec![]); // disable auto-escape for .html templates
8442
Ok(Generator {
8543
tera,
@@ -148,7 +106,7 @@ impl Generator {
148106
}
149107

150108
fn render_blog(&self, blog: &Blog) -> eyre::Result<()> {
151-
std::fs::create_dir_all(self.out_directory.join(blog.prefix()))?;
109+
std::fs::create_dir_all(self.out_directory.join(blog.path()))?;
152110

153111
let path = self.render_index(blog)?;
154112

@@ -177,24 +135,24 @@ impl Generator {
177135
.map(|other_blog| {
178136
json!({
179137
"link_text": other_blog.link_text(),
180-
"url": other_blog.prefix().join("index.html"),
138+
"url": other_blog.path().join("index.html"),
181139
})
182140
})
183141
.collect();
184142

185143
let data = json!({
186144
"title": blog.index_title(),
187-
"blog": blog,
145+
"section": blog,
188146
"other_blogs": other_blogs,
189147
});
190-
let path = blog.prefix().join("index.html");
148+
let path = blog.path().join("index.html");
191149
self.render_template(&path, "index.html", data)?;
192150
Ok(path)
193151
}
194152

195153
fn render_post(&self, blog: &Blog, post: &Post) -> eyre::Result<PathBuf> {
196154
let path = blog
197-
.prefix()
155+
.path()
198156
.join(format!("{:04}", &post.year))
199157
.join(format!("{:02}", &post.month))
200158
.join(format!("{:02}", &post.day));
@@ -206,8 +164,8 @@ impl Generator {
206164

207165
let data = json!({
208166
"title": format!("{} | {}", post.title, blog.title()),
209-
"blog": blog,
210-
"post": post,
167+
"section": blog,
168+
"page": post,
211169
});
212170

213171
let path = path.join(filename);
@@ -218,12 +176,12 @@ impl Generator {
218176
fn render_feed(&self, blog: &Blog) -> eyre::Result<()> {
219177
let posts: Vec<_> = blog.posts().iter().take(10).collect();
220178
let data = json!({
221-
"blog": blog,
222-
"posts": posts,
179+
"section": blog,
180+
"pages": posts,
223181
"feed_updated": chrono::Utc::now().with_nanosecond(0).unwrap().to_rfc3339(),
224182
});
225183

226-
self.render_template(blog.prefix().join("feed.xml"), "feed.xml", data)?;
184+
self.render_template(blog.path().join("feed.xml"), "feed.xml", data)?;
227185
Ok(())
228186
}
229187

@@ -235,8 +193,8 @@ impl Generator {
235193
.map(|post| ReleasePost {
236194
title: post.title.clone(),
237195
url: blog
238-
.prefix()
239-
.join(post.url.clone())
196+
.path()
197+
.join(post.path.clone())
240198
.to_string_lossy()
241199
.to_string(),
242200
})
@@ -246,7 +204,7 @@ impl Generator {
246204
feed_updated: chrono::Utc::now().with_nanosecond(0).unwrap().to_rfc3339(),
247205
};
248206
fs::write(
249-
self.out_directory.join(blog.prefix()).join("releases.json"),
207+
self.out_directory.join(blog.path()).join("releases.json"),
250208
serde_json::to_string(&data)?,
251209
)?;
252210
Ok(())

src/posts.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub struct Post {
1919
pub(crate) month: u8,
2020
pub(crate) day: u8,
2121
pub(crate) contents: String,
22-
pub(crate) url: String,
22+
pub(crate) path: String,
2323
pub(crate) published: String,
2424
pub(crate) updated: String,
2525
pub(crate) release: bool,
@@ -122,7 +122,7 @@ impl Post {
122122
month,
123123
day,
124124
contents,
125-
url,
125+
path: url,
126126
published,
127127
updated,
128128
release,

templates/feed.xml

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,29 @@
1+
{% import "macros.html" as macros %}
12
<?xml version="1.0" encoding="utf-8"?>
23
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
3-
<generator uri="https://blog.rust-lang.org/{{blog.prefix}}" version="0.1.0">{{blog.title}}</generator>
4-
<link href="https://blog.rust-lang.org/{{blog.prefix}}feed.xml" rel="self" type="application/atom+xml" />
5-
<link href="https://blog.rust-lang.org/{{blog.prefix}}" rel="alternate" type="text/html" />
6-
<id>https://blog.rust-lang.org/{{blog.prefix}}</id>
7-
<title>{{blog.title}}</title>
8-
<subtitle>{{blog.description}}</subtitle>
4+
<generator uri="https://blog.rust-lang.org/{{ section.path }}" version="0.1.0">{{ section.title }}</generator>
5+
<link href="https://blog.rust-lang.org/{{ section.path }}feed.xml" rel="self" type="application/atom+xml" />
6+
<link href="https://blog.rust-lang.org/{{ section.path }}" rel="alternate" type="text/html" />
7+
<id>https://blog.rust-lang.org/{{ section.path }}</id>
8+
<title>{{ section.title }}</title>
9+
<subtitle>{{ section.description }}</subtitle>
910
<author>
10-
<name>Maintained by {{blog.maintained_by}}.</name>
11+
<name>Maintained by {{ section.maintained_by }}.</name>
1112
<uri>https://github.com/rust-lang/blog.rust-lang.org/</uri>
1213
</author>
1314
<updated>{{feed_updated}}</updated>
1415

15-
{% for post in posts %}
16+
{% for page in pages %}
1617
<entry>
17-
<title>{{post.title | escape_hbs}}</title>
18-
<link rel="alternate" href="https://blog.rust-lang.org/{{blog.prefix}}{{post.url | escape_hbs}}" type="text/html" title="{{post.title | escape_hbs}}" />
19-
<published>{{post.published | escape_hbs}}</published>
20-
<updated>{{post.updated | escape_hbs}}</updated>
21-
<id>https://blog.rust-lang.org/{{blog.prefix}}{{post.url | escape_hbs}}</id>
22-
<content type="html" xml:base="https://blog.rust-lang.org/{{blog.prefix}}{{post.url | escape_hbs}}">{{post.contents | escape_hbs}}</content>
18+
<title>{{ macros::escape_hbs(input=page.title) }}</title>
19+
<link rel="alternate" href="https://blog.rust-lang.org/{{ section.path }}{{ macros::escape_hbs(input=page.path) }}" type="text/html" title="{{ macros::escape_hbs(input=page.title) }}" />
20+
<published>{{ macros::escape_hbs(input=page.published) }}</published>
21+
<updated>{{ macros::escape_hbs(input=page.updated) }}</updated>
22+
<id>https://blog.rust-lang.org/{{ section.path }}{{ macros::escape_hbs(input=page.path) }}</id>
23+
<content type="html" xml:base="https://blog.rust-lang.org/{{ section.path }}{{ macros::escape_hbs(input=page.path) }}">{{ macros::escape_hbs(input=page.contents) }}</content>
2324

2425
<author>
25-
<name>{{post.author | escape_hbs}}</name>
26+
<name>{{ macros::escape_hbs(input=page.author) }}</name>
2627
</author>
2728
</entry>
2829
{%- endfor %}

templates/headers.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
{% macro headers(title, blog) -%}
1+
{% macro headers(title, section) -%}
22
<!-- Twitter card -->
33
<meta name="twitter:card" content="summary">
44
<meta name="twitter:site" content="@rustlang">
55
<meta name="twitter:creator" content="@rustlang">
6-
<meta name="twitter:title" content="{{title | escape_hbs}}">
7-
<meta name="twitter:description" content="{{blog.description}}">
6+
<meta name="twitter:title" content="{{ macros::escape_hbs(input=title) }}">
7+
<meta name="twitter:description" content="{{ section.description }}">
88
<meta name="twitter:image" content="https://www.rust-lang.org/static/images/rust-social.jpg">
99

1010
<!-- Facebook OpenGraph -->
11-
<meta property="og:title" content="{{title | escape_hbs}}" />
12-
<meta property="og:description" content="{{blog.description}}">
11+
<meta property="og:title" content="{{ macros::escape_hbs(input=title) }}" />
12+
<meta property="og:description" content="{{ section.description }}">
1313
<meta property="og:image" content="https://www.rust-lang.org/static/images/rust-social-wide.jpg" />
1414
<meta property="og:type" content="website" />
1515
<meta property="og:locale" content="en_US" />
@@ -36,7 +36,7 @@
3636
<meta name="theme-color" content="#ffffff">
3737

3838
<!-- atom -->
39-
<link type="application/atom+xml" rel="alternate" href="https://blog.rust-lang.org/{{blog.prefix}}feed.xml" title="{{blog.title}}" />
39+
<link type="application/atom+xml" rel="alternate" href="https://blog.rust-lang.org/{{ section.path }}feed.xml" title="{{ section.title }}" />
4040

4141
<!-- theme switcher -->
4242
<script src="/scripts/theme-switch.js"></script>

templates/index.html

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1+
{% import "macros.html" as macros %}
12
{% extends "layout.html" %}
23
{% block page %}
34
<header class="mt3 mt0-ns mb4-ns">
45
<div class="container flex flex-column flex-row-l justify-between-l">
56
<div class="mw6-l">
6-
<p>{{blog.index_html}}</p>
7+
<p>{{ section.index_html }}</p>
78
</div>
89
</div>
910
<div class="container flex flex-column flex-row-l justify-between-l">
1011
<div class="mw8-l">
1112
<p>
1213
<b>See also:</b>
1314
{%- for other in other_blogs %}
14-
<a href="/{{other.url}}">{{other.link_text | escape_hbs}}</a>
15+
<a href="/{{other.url}}">{{ macros::escape_hbs(input=other.link_text) }}</a>
1516
{%- endfor %}
1617
</p>
1718
</div>
@@ -22,14 +23,14 @@
2223
<div class="w-100 mw-none ph3 mw8-m mw9-l center f3">
2324

2425
<table class="post-list collapse w-100 f2-l f2-m f3-s">
25-
{%- for post in blog.posts %}
26-
{% if post.show_year %}<tr>
26+
{%- for page in section.pages %}
27+
{% if page.show_year %}<tr>
2728
<td class="bn"></td>
28-
<td class="bn"><h3 class="f0-l f1-m f2-s mt4 mb0">Posts in {{post.year}}</h3></td>
29+
<td class="bn"><h3 class="f0-l f1-m f2-s mt4 mb0">Posts in {{ page.year }}</h3></td>
2930
</tr>{% endif %}
3031
<tr>
31-
<td class="tr o-60 pr4 pr5-l bn">{{post.month | month_name}}&nbsp;{{post.day}}</td>
32-
<td class="bn"><a href="{{post.url}}">{{post.title | escape_hbs}}</a></td>
32+
<td class="tr o-60 pr4 pr5-l bn">{{ macros::month_name(num=page.month) }}&nbsp;{{ page.day }}</td>
33+
<td class="bn"><a href="{{ page.path }}">{{ macros::escape_hbs(input=page.title) }}</a></td>
3334
</tr>
3435
{%- endfor %}
3536
</table>

templates/layout.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1+
{% import "macros.html" as macros %}
12
{% import "headers.html" as headers %}
23
{% import "nav.html" as nav %}
34
{% import "footer.html" as footer %}
45
<!DOCTYPE html>
56
<html lang="en">
67
<head>
78
<meta charset="utf-8">
8-
<title>{{ title | escape_hbs }}</title>
9+
<title>{{ macros::escape_hbs(input=title) }}</title>
910
<meta name="viewport" content="width=device-width,initial-scale=1.0">
1011
<meta name="description" content="Empowering everyone to build reliable and efficient software.">
11-
{{ headers::headers(title=title, blog=blog) | indent(prefix=" ", blank=true) }}
12+
{{ headers::headers(title=title, section=section) | indent(prefix=" ", blank=true) }}
1213
</head>
1314
<body>
14-
{{ nav::nav(blog=blog) | indent(prefix=" ", blank=true) }}
15+
{{ nav::nav(section=section) | indent(prefix=" ", blank=true) }}
1516
{%- block page %}{% endblock page %}
1617
{{ footer::footer() | indent(prefix=" ", blank=true) }}
1718
</body>

templates/macros.html

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{% macro month_name(num) %}
2+
{%- if num == 1 %}Jan.
3+
{%- elif num == 2 %}Feb.
4+
{%- elif num == 3 %}Mar.
5+
{%- elif num == 4 %}Apr.
6+
{%- elif num == 5 %}May
7+
{%- elif num == 6 %}June
8+
{%- elif num == 7 %}July
9+
{%- elif num == 8 %}Aug.
10+
{%- elif num == 9 %}Sept.
11+
{%- elif num == 10 %}Oct.
12+
{%- elif num == 11 %}Nov.
13+
{%- elif num == 12 %}Dec.
14+
{%- else %}{{ throw(message="invalid month! " ~ num) }}
15+
{%- endif %}
16+
{%- endmacro month_name %}
17+
18+
{#
19+
The blog templates used to be written in Handlebars, but Tera and Handlebars
20+
escape HTML differently by default:
21+
Tera: &<>"'/
22+
Handlebars: &<>"'`=
23+
To keep the output identical, this macro matches the behavior of Handlebars.
24+
#}
25+
{% macro escape_hbs(input) -%}
26+
{{ input
27+
| replace(from="&", to="&amp;")
28+
| replace(from="<", to="&lt;")
29+
| replace(from=">", to="&gt;")
30+
| replace(from='"', to="&quot;")
31+
| replace(from="'", to="&#x27;")
32+
| replace(from="`", to="&#x60;")
33+
| replace(from="=", to="&#x3D;")
34+
}}
35+
{%- endmacro escape_hbs %}

0 commit comments

Comments
 (0)