Updated the call site for handlebars rendering

This commit is contained in:
Michael Bryan 2018-03-14 23:28:32 +08:00
parent 951c873df6
commit 867fbfec05
No known key found for this signature in database
GPG Key ID: E9C602B0D9A998DC
2 changed files with 80 additions and 77 deletions

View File

@ -4,7 +4,6 @@ use std::collections::BTreeMap;
use serde_json; use serde_json;
use handlebars::{Context, Handlebars, Helper, RenderContext, RenderError, Renderable}; use handlebars::{Context, Handlebars, Helper, RenderContext, RenderError, Renderable};
type StringMap = BTreeMap<String, String>; type StringMap = BTreeMap<String, String>;
/// Target for `find_chapter`. /// Target for `find_chapter`.
@ -15,22 +14,23 @@ enum Target {
impl Target { impl Target {
/// Returns target if found. /// Returns target if found.
fn find(&self, fn find(
base_path: &String, &self,
current_path: &String, base_path: &String,
current_item: &StringMap, current_path: &String,
previous_item: &StringMap, current_item: &StringMap,
) -> Result<Option<StringMap>, RenderError> { previous_item: &StringMap,
) -> Result<Option<StringMap>, RenderError> {
match self { match self {
&Target::Next => { &Target::Next => {
let previous_path = previous_item.get("path").ok_or_else(|| { let previous_path = previous_item
RenderError::new("No path found for chapter in JSON data") .get("path")
})?; .ok_or_else(|| RenderError::new("No path found for chapter in JSON data"))?;
if previous_path == base_path { if previous_path == base_path {
return Ok(Some(current_item.clone())); return Ok(Some(current_item.clone()));
} }
}, }
&Target::Previous => { &Target::Previous => {
if current_path == base_path { if current_path == base_path {
@ -43,21 +43,18 @@ impl Target {
} }
} }
fn find_chapter( fn find_chapter(rc: &mut RenderContext, target: Target) -> Result<Option<StringMap>, RenderError> {
rc: &mut RenderContext,
target: Target
) -> Result<Option<StringMap>, RenderError> {
debug!("Get data from context"); debug!("Get data from context");
let chapters = rc.evaluate_absolute("chapters").and_then(|c| { let chapters = rc.evaluate_absolute("chapters", true).and_then(|c| {
serde_json::value::from_value::<Vec<StringMap>>(c.clone()) serde_json::value::from_value::<Vec<StringMap>>(c.clone())
.map_err(|_| RenderError::new("Could not decode the JSON data")) .map_err(|_| RenderError::new("Could not decode the JSON data"))
})?; })?;
let base_path = rc.evaluate_absolute("path")? let base_path = rc.evaluate_absolute("path", true)?
.as_str() .as_str()
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? .ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
.replace("\"", ""); .replace("\"", "");
let mut previous: Option<StringMap> = None; let mut previous: Option<StringMap> = None;
@ -78,7 +75,7 @@ fn find_chapter(
} }
} }
Ok(None) Ok(None)
} }
fn render( fn render(
@ -91,18 +88,21 @@ fn render(
let mut context = BTreeMap::new(); let mut context = BTreeMap::new();
chapter.get("name") chapter
.ok_or_else(|| RenderError::new("No title found for chapter in JSON data")) .get("name")
.map(|name| context.insert("title".to_owned(), json!(name)))?; .ok_or_else(|| RenderError::new("No title found for chapter in JSON data"))
.map(|name| context.insert("title".to_owned(), json!(name)))?;
chapter.get("path") chapter
.ok_or_else(|| RenderError::new("No path found for chapter in JSON data")) .get("path")
.and_then(|p| { .ok_or_else(|| RenderError::new("No path found for chapter in JSON data"))
Path::new(p).with_extension("html") .and_then(|p| {
.to_str() Path::new(p)
.ok_or_else(|| RenderError::new("Link could not be converted to str")) .with_extension("html")
.map(|p| context.insert("link".to_owned(), json!(p.replace("\\", "/")))) .to_str()
})?; .ok_or_else(|| RenderError::new("Link could not be converted to str"))
.map(|p| context.insert("link".to_owned(), json!(p.replace("\\", "/"))))
})?;
trace!("Render template"); trace!("Render template");
@ -138,14 +138,14 @@ pub fn next(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(), R
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
static TEMPLATE: &'static str = static TEMPLATE: &'static str =
"{{#previous}}{{title}}: {{link}}{{/previous}}|{{#next}}{{title}}: {{link}}{{/next}}"; "{{#previous}}{{title}}: {{link}}{{/previous}}|{{#next}}{{title}}: {{link}}{{/next}}";
#[test] #[test]
fn test_next_previous() { fn test_next_previous() {
let data = json!({ let data = json!({
"name": "two", "name": "two",
"path": "two.path", "path": "two.path",
"chapters": [ "chapters": [
@ -164,18 +164,19 @@ mod tests {
] ]
}); });
let mut h = Handlebars::new(); let mut h = Handlebars::new();
h.register_helper("previous", Box::new(previous)); h.register_helper("previous", Box::new(previous));
h.register_helper("next", Box::new(next)); h.register_helper("next", Box::new(next));
assert_eq!( assert_eq!(
h.template_render(TEMPLATE, &data).unwrap(), h.render_template(TEMPLATE, &data).unwrap(),
"one: one.html|three: three.html"); "one: one.html|three: three.html"
} );
}
#[test] #[test]
fn test_first() { fn test_first() {
let data = json!({ let data = json!({
"name": "one", "name": "one",
"path": "one.path", "path": "one.path",
"chapters": [ "chapters": [
@ -194,17 +195,18 @@ mod tests {
] ]
}); });
let mut h = Handlebars::new(); let mut h = Handlebars::new();
h.register_helper("previous", Box::new(previous)); h.register_helper("previous", Box::new(previous));
h.register_helper("next", Box::new(next)); h.register_helper("next", Box::new(next));
assert_eq!( assert_eq!(
h.template_render(TEMPLATE, &data).unwrap(), h.render_template(TEMPLATE, &data).unwrap(),
"|two: two.html"); "|two: two.html"
} );
#[test] }
fn test_last() { #[test]
let data = json!({ fn test_last() {
let data = json!({
"name": "three", "name": "three",
"path": "three.path", "path": "three.path",
"chapters": [ "chapters": [
@ -223,12 +225,13 @@ mod tests {
] ]
}); });
let mut h = Handlebars::new(); let mut h = Handlebars::new();
h.register_helper("previous", Box::new(previous)); h.register_helper("previous", Box::new(previous));
h.register_helper("next", Box::new(next)); h.register_helper("next", Box::new(next));
assert_eq!( assert_eq!(
h.template_render(TEMPLATE, &data).unwrap(), h.render_template(TEMPLATE, &data).unwrap(),
"two: two.html|"); "two: two.html|"
} );
}
} }

View File

@ -8,7 +8,7 @@ use pulldown_cmark::{html, Event, Parser, Tag};
// Handlebars helper to construct TOC // Handlebars helper to construct TOC
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct RenderToc { pub struct RenderToc {
pub no_section_label: bool pub no_section_label: bool,
} }
impl HelperDef for RenderToc { impl HelperDef for RenderToc {
@ -16,14 +16,14 @@ impl HelperDef for RenderToc {
// get value from context data // get value from context data
// rc.get_path() is current json parent path, you should always use it like this // rc.get_path() is current json parent path, you should always use it like this
// param is the key of value you want to display // param is the key of value you want to display
let chapters = rc.evaluate_absolute("chapters").and_then(|c| { let chapters = rc.evaluate_absolute("chapters", true).and_then(|c| {
serde_json::value::from_value::<Vec<BTreeMap<String, String>>>(c.clone()) serde_json::value::from_value::<Vec<BTreeMap<String, String>>>(c.clone())
.map_err(|_| RenderError::new("Could not decode the JSON data")) .map_err(|_| RenderError::new("Could not decode the JSON data"))
})?; })?;
let current = rc.evaluate_absolute("path")? let current = rc.evaluate_absolute("path", true)?
.as_str() .as_str()
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? .ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
.replace("\"", ""); .replace("\"", "");
rc.writer.write_all(b"<ol class=\"chapter\">")?; rc.writer.write_all(b"<ol class=\"chapter\">")?;
@ -107,12 +107,12 @@ impl HelperDef for RenderToc {
// filter all events that are not inline code blocks // filter all events that are not inline code blocks
let parser = Parser::new(name).filter(|event| match *event { let parser = Parser::new(name).filter(|event| match *event {
Event::Start(Tag::Code) | Event::Start(Tag::Code)
Event::End(Tag::Code) | | Event::End(Tag::Code)
Event::InlineHtml(_) | | Event::InlineHtml(_)
Event::Text(_) => true, | Event::Text(_) => true,
_ => false, _ => false,
}); });
// render markdown to html // render markdown to html
let mut markdown_parsed_name = String::with_capacity(name.len() * 3 / 2); let mut markdown_parsed_name = String::with_capacity(name.len() * 3 / 2);