Big clean-up, reduced the unwrap's to 2 in the library part! Closes #36 The unwraps where replaced with more diverse error messages #14

This commit is contained in:
Mathieu David 2015-08-11 22:55:51 +02:00
parent b6034e8fbe
commit 0932bfd576
6 changed files with 161 additions and 70 deletions

View File

@ -36,7 +36,7 @@ by appending a path to the command:
mdbook init path/to/book mdbook init path/to/book
``` ```
#### --theme ## --theme
When you use the `--theme` argument, the default theme will be copied into a directory When you use the `--theme` argument, the default theme will be copied into a directory
called `theme` in your source directory so that you can modify it. called `theme` in your source directory so that you can modify it.

View File

@ -8,6 +8,7 @@ use std::path::{Path, PathBuf};
pub struct BookConfig { pub struct BookConfig {
pub title: String, pub title: String,
pub author: String, pub author: String,
root: PathBuf,
dest: PathBuf, dest: PathBuf,
src: PathBuf, src: PathBuf,
pub indent_spaces: i32, pub indent_spaces: i32,
@ -16,10 +17,11 @@ pub struct BookConfig {
impl BookConfig { impl BookConfig {
pub fn new() -> Self { pub fn new(root: &Path) -> Self {
BookConfig { BookConfig {
title: String::new(), title: String::new(),
author: String::new(), author: String::new(),
root: root.to_owned(),
dest: PathBuf::from("book"), dest: PathBuf::from("book"),
src: PathBuf::from("src"), src: PathBuf::from("src"),
indent_spaces: 4, // indentation used for SUMMARY.md indent_spaces: 4, // indentation used for SUMMARY.md
@ -42,32 +44,50 @@ impl BookConfig {
debug!("[*]: Reading config"); debug!("[*]: Reading config");
let mut data = String::new(); let mut data = String::new();
config_file.read_to_string(&mut data).unwrap();
// Just return if an error occured.
// I would like to propagate the error, but I have to return `&self`
match config_file.read_to_string(&mut data) {
Err(_) => return self,
_ => {},
}
// Convert to JSON // Convert to JSON
let config = Json::from_str(&data).unwrap(); if let Ok(config) = Json::from_str(&data) {
// Extract data
// Extract data debug!("[*]: Extracting data from config");
// Title & author
if let Some(a) = config.find_path(&["title"]) { self.title = a.to_string().replace("\"", "") }
if let Some(a) = config.find_path(&["author"]) { self.author = a.to_string().replace("\"", "") }
debug!("[*]: Extracting data from config"); // Destination
// Title & author if let Some(a) = config.find_path(&["dest"]) {
if let Some(a) = config.find_path(&["title"]) { self.title = a.to_string().replace("\"", "") } let dest = PathBuf::from(&a.to_string().replace("\"", ""));
if let Some(a) = config.find_path(&["author"]) { self.author = a.to_string().replace("\"", "") }
// Destination // If path is relative make it absolute from the parent directory of src
if let Some(a) = config.find_path(&["dest"]) { match dest.is_relative() {
let dest = PathBuf::from(&a.to_string().replace("\"", "")); true => {
let dest = self.get_root().join(&dest).to_owned();
// If path is relative make it absolute from the parent directory of src self.set_dest(&dest);
if dest.is_relative() { },
let dest = &self.get_src().parent().unwrap().join(&dest); false => { self.set_dest(&dest); },
self.set_dest(dest); }
} }
} }
self self
} }
pub fn get_root(&self) -> &Path {
&self.root
}
pub fn set_root(&mut self, root: &Path) -> &mut Self {
self.root = root.to_owned();
self
}
pub fn get_dest(&self) -> &Path { pub fn get_dest(&self) -> &Path {
&self.dest &self.dest
} }

View File

@ -1,4 +1,4 @@
use std::path::{Path, PathBuf}; use std::path::Path;
use std::fs::{self, File, metadata}; use std::fs::{self, File, metadata};
use std::io::Write; use std::io::Write;
use std::error::Error; use std::error::Error;
@ -12,7 +12,6 @@ use renderer::HtmlHandlebars;
pub struct MDBook { pub struct MDBook {
config: BookConfig, config: BookConfig,
pub root: PathBuf,
pub content: Vec<BookItem>, pub content: Vec<BookItem>,
renderer: Box<Renderer>, renderer: Box<Renderer>,
} }
@ -39,9 +38,8 @@ impl MDBook {
} }
MDBook { MDBook {
root: root.to_path_buf(),
content: vec![], content: vec![],
config: BookConfig::new() config: BookConfig::new(root)
.set_src(&root.join("src")) .set_src(&root.join("src"))
.set_dest(&root.join("book")) .set_dest(&root.join("book"))
.to_owned(), .to_owned(),
@ -106,7 +104,7 @@ impl MDBook {
// There is a very high chance that the error is due to the fact that // There is a very high chance that the error is due to the fact that
// the directory / file does not exist // the directory / file does not exist
debug!("[*]: {:?} does not exist, trying to create directory", dest); debug!("[*]: {:?} does not exist, trying to create directory", dest);
fs::create_dir(&dest).unwrap(); try!(fs::create_dir(&dest));
}, },
Ok(_) => { /* If there is no error, the directory / file does exist */ } Ok(_) => { /* If there is no error, the directory / file does exist */ }
} }
@ -117,7 +115,7 @@ impl MDBook {
// There is a very high chance that the error is due to the fact that // There is a very high chance that the error is due to the fact that
// the directory / file does not exist // the directory / file does not exist
debug!("[*]: {:?} does not exist, trying to create directory", src); debug!("[*]: {:?} does not exist, trying to create directory", src);
fs::create_dir(&src).unwrap(); try!(fs::create_dir(&src));
}, },
Ok(_) => { /* If there is no error, the directory / file does exist */ } Ok(_) => { /* If there is no error, the directory / file does exist */ }
} }
@ -128,7 +126,7 @@ impl MDBook {
// There is a very high chance that the error is due to the fact that // There is a very high chance that the error is due to the fact that
// the directory / file does not exist // the directory / file does not exist
debug!("[*]: {:?} does not exist, trying to create SUMMARY.md", src.join("SUMMARY.md")); debug!("[*]: {:?} does not exist, trying to create SUMMARY.md", src.join("SUMMARY.md"));
Ok(File::create(&src.join("SUMMARY.md")).unwrap()) Ok(try!(File::create(&src.join("SUMMARY.md"))))
}, },
Ok(_) => { Ok(_) => {
/* If there is no error, the directory / file does exist */ /* If there is no error, the directory / file does exist */
@ -143,7 +141,7 @@ impl MDBook {
try!(writeln!(f, "")); try!(writeln!(f, ""));
try!(writeln!(f, "- [Chapter 1](./chapter_1.md)")); try!(writeln!(f, "- [Chapter 1](./chapter_1.md)"));
let mut chapter_1 = File::create(&src.join("chapter_1.md")).unwrap(); let mut chapter_1 = try!(File::create(&src.join("chapter_1.md")));
try!(writeln!(chapter_1, "# Chapter 1")); try!(writeln!(chapter_1, "# Chapter 1"));
} }
@ -181,7 +179,7 @@ impl MDBook {
// There is a very high chance that the error is due to the fact that // There is a very high chance that the error is due to the fact that
// the directory / file does not exist // the directory / file does not exist
debug!("[*]: {:?} does not exist, trying to create directory", theme_dir); debug!("[*]: {:?} does not exist, trying to create directory", theme_dir);
fs::create_dir(&theme_dir).unwrap(); try!(fs::create_dir(&theme_dir));
}, },
Ok(_) => { /* If there is no error, the directory / file does exist */ } Ok(_) => { /* If there is no error, the directory / file does exist */ }
} }
@ -226,7 +224,8 @@ impl MDBook {
/// of the current working directory by using a relative path instead of an absolute path. /// of the current working directory by using a relative path instead of an absolute path.
pub fn read_config(mut self) -> Self { pub fn read_config(mut self) -> Self {
self.config.read_config(&self.root); let root = self.config.get_root().to_owned();
self.config.read_config(&root);
self self
} }
@ -256,7 +255,16 @@ impl MDBook {
} }
pub fn set_dest(mut self, dest: &Path) -> Self { pub fn set_dest(mut self, dest: &Path) -> Self {
self.config.set_dest(&self.root.join(dest));
// Handle absolute and relative paths
match dest.is_absolute() {
true => { self.config.set_dest(dest); },
false => {
let dest = self.config.get_root().join(dest).to_owned();
self.config.set_dest(&dest);
}
}
self self
} }
@ -265,7 +273,16 @@ impl MDBook {
} }
pub fn set_src(mut self, src: &Path) -> Self { pub fn set_src(mut self, src: &Path) -> Self {
self.config.set_src(&self.root.join(src));
// Handle absolute and relative paths
match src.is_absolute() {
true => { self.config.set_src(src); },
false => {
let src = self.config.get_root().join(src).to_owned();
self.config.set_src(&src);
}
}
self self
} }

View File

@ -72,7 +72,11 @@ impl Renderer for HtmlHandlebars {
// Remove content from previous file and render content for this one // Remove content from previous file and render content for this one
data.remove("path"); data.remove("path");
data.insert("path".to_string(), item.path.to_str().unwrap().to_json()); match item.path.to_str() {
Some(p) => { data.insert("path".to_string(), p.to_json()); },
None => return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not convert path to str"))),
}
// Remove content from previous file and render content for this one // Remove content from previous file and render content for this one
data.remove("content"); data.remove("content");
@ -144,7 +148,10 @@ fn make_data(book: BookItems, config: &BookConfig) -> Result<BTreeMap<String,Jso
let mut chapter = BTreeMap::new(); let mut chapter = BTreeMap::new();
chapter.insert("section".to_string(), section.to_json()); chapter.insert("section".to_string(), section.to_json());
chapter.insert("name".to_string(), item.name.to_json()); chapter.insert("name".to_string(), item.name.to_json());
chapter.insert("path".to_string(), item.path.to_str().unwrap().to_json()); match item.path.to_str() {
Some(p) => { chapter.insert("path".to_string(), p.to_json()); },
None => return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not convert path to str"))),
}
chapters.push(chapter); chapters.push(chapter);
} }

View File

@ -30,9 +30,13 @@ pub fn previous(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext
debug!("[*]: Decode chapters from JSON"); debug!("[*]: Decode chapters from JSON");
// Decode json format // Decode json format
let decoded: Vec<BTreeMap<String, String>> = json::decode(&chapters.to_string()).unwrap(); let decoded: Vec<BTreeMap<String, String>> = match json::decode(&chapters.to_string()) {
Ok(data) => data,
Err(_) => return Err(RenderError{ desc: "Could not decode the JSON data"}),
};
let mut previous: Option<BTreeMap<String, String>> = None; let mut previous: Option<BTreeMap<String, String>> = None;
debug!("[*]: Search for current Chapter"); debug!("[*]: Search for current Chapter");
// Search for current chapter and return previous entry // Search for current chapter and return previous entry
for item in decoded { for item in decoded {
@ -48,22 +52,32 @@ pub fn previous(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext
// Create new BTreeMap to extend the context: 'title' and 'link' // Create new BTreeMap to extend the context: 'title' and 'link'
let mut previous_chapter = BTreeMap::new(); let mut previous_chapter = BTreeMap::new();
debug!("[*]: Inserting title: {}", previous.get("name").unwrap()); // Chapter title
previous_chapter.insert("title".to_string(), previous.get("name").unwrap().to_json()); match previous.get("name") {
Some(n) => {
debug!("[*]: Inserting title: {}", n);
previous_chapter.insert("title".to_string(), n.to_json())
},
None => {
debug!("[*]: No title found for chapter");
return Err(RenderError{ desc: "No title found for chapter in JSON data" })
}
};
debug!("[*]: Inserting link: {}", // Chapter link
path_to_root.join(
Path::new(previous.get("path").unwrap())
.with_extension("html")
).to_str().unwrap());
previous_chapter.insert( match previous.get("path") {
"link".to_string(), Some(p) => {
path_to_root.join( let path = path_to_root.join(Path::new(p).with_extension("html"));
Path::new(previous.get("path").unwrap()) debug!("[*]: Inserting link: {:?}", path);
.with_extension("html")
).to_str().unwrap().to_json() match path.to_str() {
); Some(p) => { previous_chapter.insert("link".to_string(), p.to_json()); },
None => return Err(RenderError{ desc: "Link could not be converted to str" })
}
},
None => return Err(RenderError{ desc: "No path found for chapter in JSON data" })
}
debug!("[*]: Inject in context"); debug!("[*]: Inject in context");
// Inject in current context // Inject in current context
@ -71,7 +85,13 @@ pub fn previous(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext
debug!("[*]: Render template"); debug!("[*]: Render template");
// Render template // Render template
_h.template().unwrap().render(&updated_context, r, rc).unwrap(); match _h.template() {
Some(t) => {
try!(t.render(&updated_context, r, rc));
},
None => return Err(RenderError{ desc: "Error with the handlebars template" })
}
} }
break; break;
@ -81,8 +101,11 @@ pub fn previous(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext
} }
}, },
_ => continue, _ => continue,
} }
} }
Ok(()) Ok(())
} }
@ -110,7 +133,10 @@ pub fn next(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext) ->
debug!("[*]: Decode chapters from JSON"); debug!("[*]: Decode chapters from JSON");
// Decode json format // Decode json format
let decoded: Vec<BTreeMap<String, String>> = json::decode(&chapters.to_string()).unwrap(); let decoded: Vec<BTreeMap<String, String>> = match json::decode(&chapters.to_string()) {
Ok(data) => data,
Err(_) => return Err(RenderError{ desc: "Could not decode the JSON data"}),
};
let mut previous: Option<BTreeMap<String, String>> = None; let mut previous: Option<BTreeMap<String, String>> = None;
debug!("[*]: Search for current Chapter"); debug!("[*]: Search for current Chapter");
@ -122,37 +148,48 @@ pub fn next(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext) ->
Some(path) if path.len() > 0 => { Some(path) if path.len() > 0 => {
if let Some(previous) = previous { if let Some(previous) = previous {
if previous.get("path").unwrap() == &current {
let path = match previous.get("path") {
Some(p) => p,
None => return Err(RenderError{ desc: "No path found for chapter in JSON data"})
};
if path == &current {
debug!("[*]: Found current chapter"); debug!("[*]: Found current chapter");
debug!("[*]: Creating BTreeMap to inject in context"); debug!("[*]: Creating BTreeMap to inject in context");
// Create new BTreeMap to extend the context: 'title' and 'link' // Create new BTreeMap to extend the context: 'title' and 'link'
let mut next_chapter = BTreeMap::new(); let mut next_chapter = BTreeMap::new();
debug!("[*]: Inserting title: {}", item.get("name").unwrap()); match item.get("name") {
next_chapter.insert("title".to_string(), item.get("name").unwrap().to_json()); Some(n) => {
debug!("[*]: Inserting title: {}", n);
next_chapter.insert("title".to_string(), n.to_json());
}
None => return Err(RenderError{ desc: "No title found for chapter in JSON data"})
}
debug!("[*]: Inserting link: {}", let link = path_to_root.join(Path::new(path).with_extension("html"));
path_to_root.join( debug!("[*]: Inserting link: {:?}", link);
Path::new(item.get("path").unwrap())
.with_extension("html")
).to_str().unwrap());
next_chapter.insert( match link.to_str() {
"link".to_string(), Some(l) => { next_chapter.insert("link".to_string(), l.to_json()); },
path_to_root.join( None => return Err(RenderError{ desc: "Link could not converted to str"})
Path::new(item.get("path").unwrap()) }
.with_extension("html")
).to_str().unwrap().to_json()
);
debug!("[*]: Inject in context"); debug!("[*]: Inject in context");
// Inject in current context // Inject in current context
let updated_context = c.extend(&next_chapter); let updated_context = c.extend(&next_chapter);
debug!("[*]: Render template"); debug!("[*]: Render template");
// Render template // Render template
_h.template().unwrap().render(&updated_context, r, rc).unwrap(); match _h.template() {
Some(t) => {
try!(t.render(&updated_context, r, rc));
},
None => return Err(RenderError{ desc: "Error with the handlebars template" })
}
break break
} }

View File

@ -63,7 +63,9 @@ impl Theme {
match File::open(&src.join("index.hbs")) { match File::open(&src.join("index.hbs")) {
Ok(mut f) => { Ok(mut f) => {
theme.index.clear(); // Reset the value, because read_to_string appends... theme.index.clear(); // Reset the value, because read_to_string appends...
f.read_to_end(&mut theme.index).unwrap(); match f.read_to_end(&mut theme.index) {
_ => {}
};
}, },
_ => {}, _ => {},
} }
@ -72,7 +74,9 @@ impl Theme {
match File::open(&src.join("book.js")) { match File::open(&src.join("book.js")) {
Ok(mut f) => { Ok(mut f) => {
theme.js.clear(); theme.js.clear();
f.read_to_end(&mut theme.js).unwrap(); match f.read_to_end(&mut theme.js){
_ => {}
}
}, },
_ => {}, _ => {},
} }
@ -81,7 +85,9 @@ impl Theme {
match File::open(&src.join("book.css")) { match File::open(&src.join("book.css")) {
Ok(mut f) => { Ok(mut f) => {
theme.css.clear(); theme.css.clear();
f.read_to_end(&mut theme.css).unwrap(); match f.read_to_end(&mut theme.css) {
_ => {}
}
}, },
_ => {}, _ => {},
} }
@ -90,7 +96,9 @@ impl Theme {
match File::open(&src.join("highlight.js")) { match File::open(&src.join("highlight.js")) {
Ok(mut f) => { Ok(mut f) => {
theme.highlight_js.clear(); theme.highlight_js.clear();
f.read_to_end(&mut theme.highlight_js).unwrap(); match f.read_to_end(&mut theme.highlight_js) {
_ => {}
}
}, },
_ => {}, _ => {},
} }
@ -99,7 +107,9 @@ impl Theme {
match File::open(&src.join("highlight.css")) { match File::open(&src.join("highlight.css")) {
Ok(mut f) => { Ok(mut f) => {
theme.highlight_css.clear(); theme.highlight_css.clear();
f.read_to_end(&mut theme.highlight_css).unwrap(); match f.read_to_end(&mut theme.highlight_css) {
_ => {}
}
}, },
_ => {}, _ => {},
} }