From 54e55efa70e9d1dc9016b7f0d720fd9ea7d38486 Mon Sep 17 00:00:00 2001 From: Sytse Reitsma Date: Sat, 13 Apr 2019 14:08:44 +0200 Subject: [PATCH 1/8] Wrote unit test for reserved print.md file name --- src/renderer/html_handlebars/hbs_renderer.rs | 39 +++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index b5ef228d..13f5b4ec 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -1,4 +1,4 @@ -use book::{Book, BookItem}; +use book::{Book, BookItem, Chapter}; use config::{Config, HtmlConfig, Playpen}; use errors::*; use renderer::html_handlebars::helpers; @@ -669,4 +669,41 @@ mod tests { assert_eq!(got, should_be); } } + + #[test] + fn print_dot_md_is_reserved() { + let handlebars = HtmlHandlebars::new(); + let item = BookItem::Chapter(Chapter::new( + "Goodbye World", + String::new(), + "print.md", + Vec::new(), + )); + let ctx = RenderItemContext { + handlebars: &Handlebars::new(), + destination: PathBuf::new(), + data: serde_json::from_str("{}").unwrap(), + is_index: false, + html_config: HtmlConfig { + curly_quotes: true, + google_analytics: Some(String::from("123456")), + additional_css: vec![PathBuf::from("./foo/bar/baz.css")], + theme: Some(PathBuf::from("./themedir")), + default_theme: Some(String::from("rust")), + playpen: Playpen { + editable: true, + copy_js: true, + }, + git_repository_url: Some(String::from("https://foo.com/")), + git_repository_icon: Some(String::from("fa-code-fork")), + ..Default::default() + } + }; + + let mut content = String::new(); + match handlebars.render_item(&item, ctx, &mut content) { + Ok(_) => assert!(false, "Expected a failure"), + Err(error)=> assert_eq!(error.to_string(), "print.md is reserved for internal use"), + }; + } } From 09baefc1442dfef629937ecbd8e051a27adac320 Mon Sep 17 00:00:00 2001 From: Sytse Reitsma Date: Sat, 13 Apr 2019 14:13:03 +0200 Subject: [PATCH 2/8] Unit test cleanup. Early exit when print.md clause is encountered. --- src/renderer/html_handlebars/hbs_renderer.rs | 47 ++++++++------------ 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index 13f5b4ec..39ca41f8 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -31,6 +31,11 @@ impl HtmlHandlebars { ) -> Result<()> { // FIXME: This should be made DRY-er and rely less on mutable state if let BookItem::Chapter(ref ch) = *item { + // "print.html" is used for the print page. + if ch.path == Path::new("print.md") { + bail!(ErrorKind::ReservedFilenameError(ch.path.clone())); + }; + let content = ch.content.clone(); let content = utils::render_markdown(&content, ctx.html_config.curly_quotes); @@ -46,10 +51,6 @@ impl HtmlHandlebars { .chain_err(|| "Could not convert path to str")?; let filepath = Path::new(&ch.path).with_extension("html"); - // "print.html" is used for the print page. - if ch.path == Path::new("print.md") { - bail!(ErrorKind::ReservedFilenameError(ch.path.clone())); - }; // Non-lexical lifetimes needed :'( let title: String; @@ -673,32 +674,20 @@ mod tests { #[test] fn print_dot_md_is_reserved() { let handlebars = HtmlHandlebars::new(); - let item = BookItem::Chapter(Chapter::new( - "Goodbye World", - String::new(), - "print.md", - Vec::new(), - )); + let item = BookItem::Chapter(Chapter{ + path: PathBuf::from("print.md"), + ..Default::default() + }); + let ctx = RenderItemContext { - handlebars: &Handlebars::new(), - destination: PathBuf::new(), - data: serde_json::from_str("{}").unwrap(), - is_index: false, - html_config: HtmlConfig { - curly_quotes: true, - google_analytics: Some(String::from("123456")), - additional_css: vec![PathBuf::from("./foo/bar/baz.css")], - theme: Some(PathBuf::from("./themedir")), - default_theme: Some(String::from("rust")), - playpen: Playpen { - editable: true, - copy_js: true, - }, - git_repository_url: Some(String::from("https://foo.com/")), - git_repository_icon: Some(String::from("fa-code-fork")), - ..Default::default() - } - }; + handlebars: &Handlebars::new(), + destination: PathBuf::new(), + data: serde_json::from_str("{}").unwrap(), + is_index: false, + html_config: HtmlConfig { + ..Default::default() + } + }; let mut content = String::new(); match handlebars.render_item(&item, ctx, &mut content) { From bdaa7311975772a3974d7440e396dc5b2e25d79f Mon Sep 17 00:00:00 2001 From: Sytse Reitsma Date: Wed, 17 Apr 2019 20:45:17 +0200 Subject: [PATCH 3/8] Removed some duplication in tester --- src/renderer/html_handlebars/hbs_renderer.rs | 87 ++++++++++++++------ 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index 39ca41f8..5459e9ec 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -1,4 +1,4 @@ -use book::{Book, BookItem, Chapter}; +use book::{Book, BookItem}; use config::{Config, HtmlConfig, Playpen}; use errors::*; use renderer::html_handlebars::helpers; @@ -36,6 +36,10 @@ impl HtmlHandlebars { bail!(ErrorKind::ReservedFilenameError(ch.path.clone())); }; + let path = ch.path + .to_str() + .chain_err(|| "Could not convert path to str")?; + let content = ch.content.clone(); let content = utils::render_markdown(&content, ctx.html_config.curly_quotes); @@ -45,13 +49,6 @@ impl HtmlHandlebars { print_content.push_str(&fixed_content); // Update the context with data for this file - let path = ch - .path - .to_str() - .chain_err(|| "Could not convert path to str")?; - let filepath = Path::new(&ch.path).with_extension("html"); - - // Non-lexical lifetimes needed :'( let title: String; { @@ -79,6 +76,7 @@ impl HtmlHandlebars { let rendered = self.post_process(rendered, &ctx.html_config.playpen); // Write to file + let filepath = Path::new(&ch.path).with_extension("html"); debug!("Creating {}", filepath.display()); utils::fs::write_file(&ctx.destination, &filepath, rendered.as_bytes())?; @@ -635,6 +633,8 @@ struct RenderItemContext<'a> { #[cfg(test)] mod tests { use super::*; + use book::Chapter; + #[test] fn original_build_header_links() { @@ -671,28 +671,65 @@ mod tests { } } + struct PathTestContext<'a> { + render_context: RenderItemContext<'a>, + item : BookItem, + } + + impl<'a> PathTestContext<'a> { + pub fn new(path: String, dummy_handlebars: &'a Handlebars) -> PathTestContext<'a> { + + PathTestContext { + render_context: RenderItemContext { + handlebars: dummy_handlebars, + destination: PathBuf::new(), + data: serde_json::from_str("{}").unwrap(), + is_index: false, + html_config: HtmlConfig { + ..Default::default() + } + }, + item : BookItem::Chapter( + Chapter { + path: PathBuf::from(path), + ..Default::default() + } + ), + } + } + } + #[test] fn print_dot_md_is_reserved() { - let handlebars = HtmlHandlebars::new(); - let item = BookItem::Chapter(Chapter{ - path: PathBuf::from("print.md"), - ..Default::default() - }); - - let ctx = RenderItemContext { - handlebars: &Handlebars::new(), - destination: PathBuf::new(), - data: serde_json::from_str("{}").unwrap(), - is_index: false, - html_config: HtmlConfig { - ..Default::default() - } - }; + let dummy_handlebars = Handlebars::new(); + let ctx = PathTestContext::new(String::from("print.md"), &dummy_handlebars); + let html_handlebars = HtmlHandlebars::new(); let mut content = String::new(); - match handlebars.render_item(&item, ctx, &mut content) { - Ok(_) => assert!(false, "Expected a failure"), + match html_handlebars.render_item(&ctx.item, ctx.render_context, &mut content) { + Ok(_) => assert!(false, "Expected a failure, because print.md is a reserved filename"), Err(error)=> assert_eq!(error.to_string(), "print.md is reserved for internal use"), }; } + + #[test] + #[cfg(not(target_os = "windows"))] //The failure we're after does not occur on windows :(, on Linux it does. + fn invalid_utf8_path_returns_error() { + let mut invalid_unicode = String::from("AB"); + unsafe { + let bytes = invalid_unicode.as_bytes_mut(); + bytes[0] = 0xC2; + bytes[1] = 0xC2; + } + + let dummy_handlebars = Handlebars::new(); + let ctx = PathTestContext::new(String::from(invalid_unicode), &dummy_handlebars); + let html_handlebars = HtmlHandlebars::new(); + + let mut content = String::new(); + match html_handlebars.render_item(&ctx.item, ctx.render_context, &mut content) { + Ok(_) => assert!(false, "Expected a failure in PathBuf::to_str (for BookItem::Chapter::path)"), + Err(error) => assert_eq!(error.to_string(), "Could not convert path to str"), + }; + } } From 261207064ef65da0a1a8ee3579fdb619f9cff5c7 Mon Sep 17 00:00:00 2001 From: Sytse Reitsma Date: Wed, 17 Apr 2019 20:49:09 +0200 Subject: [PATCH 4/8] Compiler warnings --- Cargo.lock | 2 ++ src/utils/mod.rs | 2 +- tests/rendered_output.rs | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7d981de6..49ffa66d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "aho-corasick" version = "0.6.8" diff --git a/src/utils/mod.rs b/src/utils/mod.rs index df997d5e..76dd16b9 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -61,7 +61,7 @@ pub fn id_from_content(content: &str) -> String { } // Remove spaces and hashes indicating a header - let trimmed = content.trim().trim_left_matches('#').trim(); + let trimmed = content.trim().trim_start_matches('#').trim(); normalize_id(trimmed) } diff --git a/tests/rendered_output.rs b/tests/rendered_output.rs index b7777ee7..062674a3 100644 --- a/tests/rendered_output.rs +++ b/tests/rendered_output.rs @@ -423,8 +423,8 @@ mod search { fn read_book_index(root: &Path) -> serde_json::Value { let index = root.join("book/searchindex.js"); let index = file_to_string(index).unwrap(); - let index = index.trim_left_matches("window.search = "); - let index = index.trim_right_matches(";"); + let index = index.trim_start_matches("window.search = "); + let index = index.trim_end_matches(";"); serde_json::from_str(&index).unwrap() } From dfaf7c7558258272f6f78d5d800309ca6ff9c784 Mon Sep 17 00:00:00 2001 From: Sytse Reitsma Date: Wed, 17 Apr 2019 20:57:46 +0200 Subject: [PATCH 5/8] Passed through rustfmt --- src/renderer/html_handlebars/hbs_renderer.rs | 62 ++++++++++++-------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index 5459e9ec..c8706d2f 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -36,7 +36,8 @@ impl HtmlHandlebars { bail!(ErrorKind::ReservedFilenameError(ch.path.clone())); }; - let path = ch.path + let path = ch + .path .to_str() .chain_err(|| "Could not convert path to str")?; @@ -45,7 +46,11 @@ impl HtmlHandlebars { let string_path = ch.path.parent().unwrap().display().to_string(); - let fixed_content = utils::render_markdown_with_base(&ch.content, ctx.html_config.curly_quotes, &string_path); + let fixed_content = utils::render_markdown_with_base( + &ch.content, + ctx.html_config.curly_quotes, + &string_path, + ); print_content.push_str(&fixed_content); // Update the context with data for this file @@ -511,7 +516,8 @@ fn build_header_links(html: &str) -> String { .expect("Regex should ensure we only ever get numbers here"); wrap_header_with_link(level, &caps[2], &mut id_counter) - }).into_owned() + }) + .into_owned() } /// Wraps a single header tag with a link, making sure each tag gets its own @@ -562,7 +568,8 @@ fn fix_code_blocks(html: &str) -> String { classes = classes, after = after ) - }).into_owned() + }) + .into_owned() } fn add_playpen_pre(html: &str, playpen_config: &Playpen) -> String { @@ -598,7 +605,8 @@ fn add_playpen_pre(html: &str, playpen_config: &Playpen) -> String { // not language-rust, so no-op text.to_owned() } - }).into_owned() + }) + .into_owned() } fn partition_source(s: &str) -> (String, String) { @@ -635,7 +643,6 @@ mod tests { use super::*; use book::Chapter; - #[test] fn original_build_header_links() { let inputs = vec![ @@ -673,28 +680,25 @@ mod tests { struct PathTestContext<'a> { render_context: RenderItemContext<'a>, - item : BookItem, + item: BookItem, } impl<'a> PathTestContext<'a> { pub fn new(path: String, dummy_handlebars: &'a Handlebars) -> PathTestContext<'a> { - PathTestContext { render_context: RenderItemContext { - handlebars: dummy_handlebars, - destination: PathBuf::new(), - data: serde_json::from_str("{}").unwrap(), - is_index: false, - html_config: HtmlConfig { - ..Default::default() - } - }, - item : BookItem::Chapter( - Chapter { - path: PathBuf::from(path), + handlebars: dummy_handlebars, + destination: PathBuf::new(), + data: serde_json::from_str("{}").unwrap(), + is_index: false, + html_config: HtmlConfig { ..Default::default() - } - ), + }, + }, + item: BookItem::Chapter(Chapter { + path: PathBuf::from(path), + ..Default::default() + }), } } } @@ -704,11 +708,14 @@ mod tests { let dummy_handlebars = Handlebars::new(); let ctx = PathTestContext::new(String::from("print.md"), &dummy_handlebars); let html_handlebars = HtmlHandlebars::new(); - + let mut content = String::new(); match html_handlebars.render_item(&ctx.item, ctx.render_context, &mut content) { - Ok(_) => assert!(false, "Expected a failure, because print.md is a reserved filename"), - Err(error)=> assert_eq!(error.to_string(), "print.md is reserved for internal use"), + Ok(_) => assert!( + false, + "Expected a failure, because print.md is a reserved filename" + ), + Err(error) => assert_eq!(error.to_string(), "print.md is reserved for internal use"), }; } @@ -725,10 +732,13 @@ mod tests { let dummy_handlebars = Handlebars::new(); let ctx = PathTestContext::new(String::from(invalid_unicode), &dummy_handlebars); let html_handlebars = HtmlHandlebars::new(); - + let mut content = String::new(); match html_handlebars.render_item(&ctx.item, ctx.render_context, &mut content) { - Ok(_) => assert!(false, "Expected a failure in PathBuf::to_str (for BookItem::Chapter::path)"), + Ok(_) => assert!( + false, + "Expected a failure in PathBuf::to_str (for BookItem::Chapter::path)" + ), Err(error) => assert_eq!(error.to_string(), "Could not convert path to str"), }; } From 21b5d322c8dab67b0d39b3f413f5b12e802aadb2 Mon Sep 17 00:00:00 2001 From: Sytse Reitsma Date: Thu, 18 Apr 2019 22:13:31 +0200 Subject: [PATCH 6/8] Cleanup of render_item Extracted get_title and render_print_content, added unit tests --- src/renderer/html_handlebars/hbs_renderer.rs | 95 +++++++++++++++----- 1 file changed, 71 insertions(+), 24 deletions(-) diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index c8706d2f..6b98a65d 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -1,4 +1,4 @@ -use book::{Book, BookItem}; +use book::{Book, BookItem, Chapter}; use config::{Config, HtmlConfig, Playpen}; use errors::*; use renderer::html_handlebars::helpers; @@ -41,34 +41,22 @@ impl HtmlHandlebars { .to_str() .chain_err(|| "Could not convert path to str")?; + self.render_print_content( + print_content, + &ch.content, + &ch.path, + ctx.html_config.curly_quotes, + ); + let content = ch.content.clone(); let content = utils::render_markdown(&content, ctx.html_config.curly_quotes); - - let string_path = ch.path.parent().unwrap().display().to_string(); - - let fixed_content = utils::render_markdown_with_base( - &ch.content, - ctx.html_config.curly_quotes, - &string_path, - ); - print_content.push_str(&fixed_content); - - // Update the context with data for this file - // Non-lexical lifetimes needed :'( - let title: String; - { - let book_title = ctx - .data - .get("book_title") - .and_then(serde_json::Value::as_str) - .unwrap_or(""); - title = ch.name.clone() + " - " + book_title; - } - ctx.data.insert("path".to_owned(), json!(path)); ctx.data.insert("content".to_owned(), json!(content)); ctx.data.insert("chapter_title".to_owned(), json!(ch.name)); + + let title = self.get_title(&ctx.data, &ch.name); ctx.data.insert("title".to_owned(), json!(title)); + ctx.data.insert( "path_to_root".to_owned(), json!(utils::fs::path_to_root(&ch.path)), @@ -98,6 +86,34 @@ impl HtmlHandlebars { Ok(()) } + fn render_print_content( + &self, + print_content: &mut String, + content: &String, + path: &PathBuf, + curly_quotes: bool, + ) { + let string_path = path.parent().unwrap().display().to_string(); + + let fixed_content = utils::render_markdown_with_base(content, curly_quotes, &string_path); + + print_content.push_str(&fixed_content); + } + + fn get_title( + &self, + render_data: &serde_json::Map, + chapter_name: &String, + ) -> String { + let book_title = render_data + .get("book_title") + .and_then(serde_json::Value::as_str) + .unwrap_or(""); + + let title = chapter_name.clone() + " - " + book_title; + title + } + #[cfg_attr(feature = "cargo-clippy", allow(clippy::let_and_return))] fn post_process(&self, rendered: String, playpen_config: &Playpen) -> String { let rendered = build_header_links(&rendered); @@ -641,7 +657,6 @@ struct RenderItemContext<'a> { #[cfg(test)] mod tests { use super::*; - use book::Chapter; #[test] fn original_build_header_links() { @@ -742,4 +757,36 @@ mod tests { Err(error) => assert_eq!(error.to_string(), "Could not convert path to str"), }; } + + #[test] + fn test_get_title() { + let json: serde_json::Map = + serde_json::from_str("{\"book_title\": \"Electric\"}").unwrap(); + let chapter_name = String::from("Froboz"); + + let html_handlebars = HtmlHandlebars::new(); + let title = html_handlebars.get_title(&json, &chapter_name); + assert_eq!("Froboz - Electric", title); + } + + #[test] + fn test_get_title_no_book_title() { + let json: serde_json::Map = serde_json::from_str("{}").unwrap(); + let chapter_name = String::from("Froboz"); + + let html_handlebars = HtmlHandlebars::new(); + let title = html_handlebars.get_title(&json, &chapter_name); + assert_eq!("Froboz - ", title); // Mmm, I'd ditch the " - " here + } + + #[test] + fn test_render_print_content() { + let mut print_content = String::from(""); + let path = PathBuf::from("foobar.md"); + let content = String::from("# Awesome"); + + let html_handlebars = HtmlHandlebars::new(); + html_handlebars.render_print_content(&mut print_content, &content, &path, true); + assert_eq!("

Awesome

\n", print_content); + } } From 47531f7576f13d1e92e4c5af1b295ec7e9939edc Mon Sep 17 00:00:00 2001 From: Sytse Reitsma Date: Thu, 25 Apr 2019 20:25:18 +0200 Subject: [PATCH 7/8] Final cleanup of render content --- src/renderer/html_handlebars/hbs_renderer.rs | 46 ++++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index 6b98a65d..5b17c12b 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -41,12 +41,11 @@ impl HtmlHandlebars { .to_str() .chain_err(|| "Could not convert path to str")?; - self.render_print_content( - print_content, + print_content.push_str(&self.render_print_content( &ch.content, &ch.path, - ctx.html_config.curly_quotes, - ); + &ctx.html_config, + )); let content = ch.content.clone(); let content = utils::render_markdown(&content, ctx.html_config.curly_quotes); @@ -88,16 +87,16 @@ impl HtmlHandlebars { fn render_print_content( &self, - print_content: &mut String, content: &String, path: &PathBuf, - curly_quotes: bool, - ) { + config: &HtmlConfig, + ) -> String { let string_path = path.parent().unwrap().display().to_string(); - let fixed_content = utils::render_markdown_with_base(content, curly_quotes, &string_path); + let fixed_content = + utils::render_markdown_with_base(content, config.curly_quotes, &string_path); - print_content.push_str(&fixed_content); + fixed_content } fn get_title( @@ -781,12 +780,33 @@ mod tests { #[test] fn test_render_print_content() { - let mut print_content = String::from(""); let path = PathBuf::from("foobar.md"); - let content = String::from("# Awesome"); + let content = String::from("# Awesome 'quotes'"); + let html_config = HtmlConfig { + curly_quotes: false, + ..Default::default() + }; let html_handlebars = HtmlHandlebars::new(); - html_handlebars.render_print_content(&mut print_content, &content, &path, true); - assert_eq!("

Awesome

\n", print_content); + assert_eq!( + "

Awesome 'quotes'

\n", + html_handlebars.render_print_content(&content, &path, &html_config) + ); + } + + #[test] + fn test_render_print_content_with_curly_quotes() { + let path = PathBuf::from("foobar.md"); + let content = String::from("# Some curly 'quotes'?"); + let html_config = HtmlConfig { + curly_quotes: true, + ..Default::default() + }; + + let html_handlebars = HtmlHandlebars::new(); + assert_eq!( + "

Some curly ‘quotes’?

\n", + html_handlebars.render_print_content(&content, &path, &html_config) + ); } } From d6866774420d51ccd70124e3e2c6393d996dba34 Mon Sep 17 00:00:00 2001 From: Sytse Reitsma Date: Thu, 25 Apr 2019 20:54:54 +0200 Subject: [PATCH 8/8] Removed code duplication for page rendering --- src/renderer/html_handlebars/hbs_renderer.rs | 31 ++++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index 5b17c12b..5a6438d4 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -29,7 +29,7 @@ impl HtmlHandlebars { mut ctx: RenderItemContext, print_content: &mut String, ) -> Result<()> { - // FIXME: This should be made DRY-er and rely less on mutable state + // FIXME: This should rely less on mutable state if let BookItem::Chapter(ref ch) = *item { // "print.html" is used for the print page. if ch.path == Path::new("print.md") { @@ -62,29 +62,34 @@ impl HtmlHandlebars { ); // Render the handlebars template with the data - debug!("Render template"); - let rendered = ctx.handlebars.render("index", &ctx.data)?; - - let rendered = self.post_process(rendered, &ctx.html_config.playpen); - - // Write to file - let filepath = Path::new(&ch.path).with_extension("html"); - debug!("Creating {}", filepath.display()); - utils::fs::write_file(&ctx.destination, &filepath, rendered.as_bytes())?; + debug!("Render template for {}", ch.path.display()); + self.render_content(&ctx, &Path::new(&ch.path).with_extension("html"))?; if ctx.is_index { ctx.data.insert("path".to_owned(), json!("index.html")); ctx.data.insert("path_to_root".to_owned(), json!("")); - let rendered_index = ctx.handlebars.render("index", &ctx.data)?; - let rendered_index = self.post_process(rendered_index, &ctx.html_config.playpen); + debug!("Creating index.html from {}", path); - utils::fs::write_file(&ctx.destination, "index.html", rendered_index.as_bytes())?; + self.render_content(&ctx, &Path::new("index.html"))?; } } Ok(()) } + fn render_content( + &self, + ctx: &RenderItemContext, + filepath: &Path + ) -> Result <()> { + let rendered = ctx.handlebars.render("index", &ctx.data)?; + let rendered = self.post_process(rendered, &ctx.html_config.playpen); + + // Write to file + debug!("Creating {}", filepath.display()); + utils::fs::write_file(&ctx.destination, &filepath, rendered.as_bytes()) + } + fn render_print_content( &self, content: &String,