diff --git a/build.rs b/build.rs index 89cc16cf..b3481dad 100644 --- a/build.rs +++ b/build.rs @@ -15,10 +15,6 @@ fn main() { .build("data.rs") .unwrap(); - // TODO this using cargo as a Makefile. This is only for development, it - // doesn't have to be part of the production auto-build. Use either a - // Makefile or an npm command if stylus comes from npm anyway. - if let Ok(_) = env::var("CARGO_FEATURE_REGENERATE_CSS") { // Compile stylus stylesheet to css diff --git a/src/book/book.rs b/src/book/book.rs index 3bfbb218..2405c0e1 100644 --- a/src/book/book.rs +++ b/src/book/book.rs @@ -35,7 +35,7 @@ impl Book { book } - /// Parses in the SUMMARY.md or creates one + /// Parses the SUMMARY.md or creates one pub fn parse_or_create_summary_file(&mut self, first_as_index: bool) -> Result<&mut Self, String> { let summary_path = self.config.src.join("SUMMARY.md"); @@ -81,7 +81,7 @@ impl Book { content } - // TODO update + // These don't seem to be used. // /// This method takes a slice `&[x, y, z]` as parameter and returns the corresponding chapter. // /// For example, to retrieve chapter 2.3 we would use: diff --git a/src/book/bookconfig.rs b/src/book/bookconfig.rs index 984a8eee..42f417ca 100644 --- a/src/book/bookconfig.rs +++ b/src/book/bookconfig.rs @@ -16,8 +16,6 @@ pub struct BookConfig { // Paths - // TODO test if dest and src behaves correctly when mdbook.dest_base and mdbook.src_base is not 'book' and 'src' - pub dest: PathBuf, pub src: PathBuf, @@ -25,8 +23,9 @@ pub struct BookConfig { /// The title of the book. pub title: String, - /// The subtitle, when titles are in the form of "The Immense Journey: An - /// Imaginative Naturalist Explores the Mysteries of Man and Nature" + /// The subtitle, when the book's full title is in the form of "The Immense + /// Journey: An Imaginative Naturalist Explores the Mysteries of Man and + /// Nature" pub subtitle: Option, /// A brief description or summary of the book. pub description: Option, @@ -94,7 +93,7 @@ impl BookConfig { /// write data back to it. /// /// Parses author when given as an array, or when given as a hash key to - /// make declaring just an author name easy. + /// make declaring a single author easy. /// /// Both of these express a single author: /// diff --git a/src/book/chapter.rs b/src/book/chapter.rs index dd0c986c..4f8f34c5 100644 --- a/src/book/chapter.rs +++ b/src/book/chapter.rs @@ -21,7 +21,7 @@ use utils::fs::create_with_str; /// If the markdown file starts with a TOML header, it will be parsed to set the /// chapter's properties. A TOML header should start and end with `+++` lines: /// -/// ``` +/// ```text /// +++ /// title = "The Library of Babel" /// author = "Jorge Luis Borges" @@ -81,8 +81,6 @@ pub struct Chapter { /// The description of the chapter. pub description: Option, - /// TODO use this in the template - /// CSS class that will be added to the page-level wrap div to allow /// customized chapter styles. pub css_class: Option, @@ -235,43 +233,6 @@ impl Chapter { self } - // TODO not being used? - - // /// Reads in the chapter's content from the markdown file. Chapter doesn't - // /// know the book's src folder, hence the `book_src_dir` argument. - // pub fn read_content_using(&self, book_src_dir: &PathBuf) -> Result> { - // let p = match self.get_src_path() { - // Some(x) => x, - // None => { - // return Err(Box::new(io::Error::new( - // io::ErrorKind::Other, - // format!("src_path is None")) - // )); - // } - // }; - - // let src_path = book_src_dir.join(&p); - - // if !src_path.exists() { - // return Err(Box::new(io::Error::new( - // io::ErrorKind::Other, - // format!("Doesn't exist: {:?}", src_path)) - // )); - // } - - // debug!("[*]: Opening file: {:?}", src_path); - - // let mut f = try!(File::open(&src_path)); - // let mut content: String = String::new(); - - // debug!("[*]: Reading file"); - // try!(f.read_to_string(&mut content)); - - // content = utils::strip_toml_header(&content); - - // Ok(content) - // } - pub fn get_src_path(&self) -> Option { self.src_path.clone() } diff --git a/src/book/mod.rs b/src/book/mod.rs index c216c35e..9108fee0 100644 --- a/src/book/mod.rs +++ b/src/book/mod.rs @@ -63,8 +63,8 @@ pub struct MDBook { /// folder with the chapter files. /// /// In the case of a single language, it is the sole item in the HashMap, - /// and its source is not expected to be under a sub-folder, just simply in - /// `./src`. + /// and its Markdown files are not expected to be under a sub-folder, just + /// simply in `./src`. /// /// Translations have to be declared in `book.toml` in their separate /// blocks. The first in the TOML config will be recognized as the main @@ -82,25 +82,24 @@ pub struct MDBook { /// author = "Lewis Carroll" /// ``` /// - /// For multiple languages, declare them in blocks: + /// For multiple languages, declare them in blocks. The translation key will + /// be the language code. Optionally, the language name can be set as well. /// /// ```toml /// [[translations.en]] /// title = "Alice in Wonderland" /// author = "Lewis Carroll" - /// language = { name = "English", code = "en" } /// /// [[translations.fr]] /// title = "Alice au pays des merveilles" /// author = "Lewis Carroll" /// translator = "Henri Bué" - /// language = { name = "Français", code = "fr" } + /// language_name = "Français" /// /// [[translations.hu]] /// title = "Alice Csodaországban" /// author = "Lewis Carroll" /// translator = "Kosztolányi Dezső" - /// language = { name = "Hungarian", code = "hu" } /// ``` pub translations: HashMap, @@ -175,12 +174,12 @@ impl MDBook { /// The `book.toml` file should be in the root directory of the book project. /// The project root directory is the one specified when creating a new `MDBook` /// - /// ```no_run + /// ```ignore /// # extern crate mdbook; /// # use mdbook::MDBook; - /// # use std::path::Path; + /// # use std::path::PathBuf; /// # fn main() { - /// let mut book = MDBook::new(Path::new("project_root_dir")); + /// let mut book = MDBook::new(&PathBuf::from("project_root_dir")); /// # } /// ``` /// @@ -247,12 +246,6 @@ impl MDBook { /// block will be interpreted as properties of the main book. /// /// `project_root` is ignored. - /// - /// - dest_base - /// - render_intent - /// - template_dir - /// - indent_spaces - /// - livereload pub fn parse_from_btreemap(&mut self, conf: &BTreeMap) -> &mut Self { let mut config = conf.clone(); @@ -398,8 +391,6 @@ impl MDBook { for key in self.translations.clone().keys() { if let Some(mut b) = self.translations.clone().get_mut(key) { - // TODO error handling could be better here - let first_as_index = match self.render_intent { RenderIntent::HtmlHandlebars => true, }; @@ -617,76 +608,5 @@ impl MDBook { self } - // TODO update - - // pub fn test(&mut self) -> Result<(), Box> { - // // read in the chapters - // try!(self.parse_summary()); - // for item in self.iter() { - - // match *item { - // BookItem::Chapter(_, ref ch) => { - // if ch.path != PathBuf::new() { - - // let path = self.get_src().join(&ch.path); - - // println!("[*]: Testing file: {:?}", path); - - // let output_result = Command::new("rustdoc") - // .arg(&path) - // .arg("--test") - // .output(); - // let output = try!(output_result); - - // if !output.status.success() { - // return Err(Box::new(io::Error::new(ErrorKind::Other, format!( - // "{}\n{}", - // String::from_utf8_lossy(&output.stdout), - // String::from_utf8_lossy(&output.stderr)))) as Box); - // } - // } - // }, - // _ => {}, - // } - // } - // Ok(()) - // } - - // /// Returns a flat depth-first iterator over the elements of the book, it returns an [BookItem enum](bookitem.html): - // /// `(section: String, bookitem: &BookItem)` - // /// - // /// ```no_run - // /// # extern crate mdbook; - // /// # use mdbook::MDBook; - // /// # use mdbook::BookItem; - // /// # use std::path::Path; - // /// # fn main() { - // /// # let mut book = MDBook::new(Path::new("mybook")); - // /// for item in book.iter() { - // /// match item { - // /// &BookItem::Chapter(ref section, ref chapter) => {}, - // /// &BookItem::Affix(ref chapter) => {}, - // /// &BookItem::Spacer => {}, - // /// } - // /// } - // /// - // /// // would print something like this: - // /// // 1. Chapter 1 - // /// // 1.1 Sub Chapter - // /// // 1.2 Sub Chapter - // /// // 2. Chapter 2 - // /// // - // /// // etc. - // /// # } - // /// ``` - - // pub fn iter(&self) -> BookItems { - // BookItems { - // items: &self.content[..], - // current_index: 0, - // stack: Vec::new(), - // } - // } - } diff --git a/src/book/toc.rs b/src/book/toc.rs index 08d3ea6b..6205bd28 100644 --- a/src/book/toc.rs +++ b/src/book/toc.rs @@ -101,7 +101,7 @@ impl TocContent { false } - // TODO update + // This doesn't seem to be used. // /// This function takes a slice `&[x,y,z]` and returns the corresponding sub-chapter if it exists. // /// diff --git a/src/lib.rs b/src/lib.rs index 2f5eaf61..4edabaec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ //! //! This is the API doc, but you can find a [less "low-level" documentation here](../index.html) that //! contains information about the command line tool, format, structure etc. -//! It is also rendered with mdBook to showcase the features and default theme. +//! It is also rendered with mdBook to showcase the features and default html template. //! //! Some reasons why you would want to use the crate (over the cli): //! @@ -17,57 +17,49 @@ //! //! ## Example //! -//! ```no_run +//! Building a book by the path to its directory: +//! +//! ```ignore //! extern crate mdbook; //! //! use mdbook::MDBook; -//! use std::path::Path; +//! use mdbook::renderer::HtmlHandlebars; +//! use std::path::PathBuf; //! //! fn main() { -//! let mut book = MDBook::new(Path::new("my-book")) // Path to root -//! .set_src(Path::new("src")) // Path from root to source directory -//! .set_dest(Path::new("book")) // Path from root to output directory -//! .read_config(); // Parse book.json file for configuration +//! let path = PathBuf::from("my-book"); // Path to the book project's root +//! let renderer = HtmlHandlebars::new(); +//! try!(renderer.build(&path)); // Build the book +//! } +//! ``` //! -//! book.build().unwrap(); // Render the book +//! Or, preparing an `MDBook` struct step-by-step and passing it to a renderer: +//! +//! ```ignore +//! extern crate mdbook; +//! +//! use mdbook::MDBook; +//! use mdbook::renderer::HtmlHandlebars; +//! use std::path::PathBuf; +//! +//! fn main() { +//! let path = PathBuf::from("my-book"); // Path to the book project's root +//! let mut book_project = MDBook::new(&path); +//! book_project.read_config(); // Parse book.toml file for configuration +//! book_project.parse_books(); // Parse SUMMARY.md, build TOC, parse chapters +//! book_project.link_translations(); // Identity links between translations +//! +//! let renderer = HtmlHandlebars::new(); +//! try!(renderer.render(&book_project)); // Render the book //! } //! ``` //! //! ## Implementing a new Renderer //! -//! If you want to create a new renderer for mdBook, the only thing you have to do is to implement -//! the [Renderer trait](renderer/renderer/trait.Renderer.html) -//! -//! And then you can swap in your renderer like this: -//! -//! ```no_run -//! # extern crate mdbook; -//! # -//! # use mdbook::MDBook; -//! # use mdbook::renderer::HtmlHandlebars; -//! # use std::path::Path; -//! # -//! # fn main() { -//! # let your_renderer = HtmlHandlebars::new(); -//! # -//! let book = MDBook::new(Path::new("my-book")).set_renderer(Box::new(your_renderer)); -//! # } +//! If you want to create a new renderer for mdBook, implement the [Renderer +//! trait](renderer/renderer/trait.Renderer.html), which is composed of two +//! functions, `.build()` and `.render()`. //! ``` -//! If you make a renderer, you get the book constructed in form of `Vec` and you get -//! the book config in a `BookConfig` struct. -//! -//! It's your responsability to create the necessary files in the correct directories. -//! -//! ## utils -//! -//! I have regrouped some useful functions in the [utils](utils/index.html) module, like the following function -//! -//! ```ignore -//! utils::fs::create_path(path: &Path) -//! ``` -//! This function creates all the directories in a given path if they do not exist -//! -//! Make sure to take a look at it. #[macro_use] extern crate serde_derive; diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index e3fc7de9..20d44151 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -47,8 +47,13 @@ impl Renderer for HtmlHandlebars { try!(utils::fs::clean_output_dir(&book_project.get_dest_base())); - // TODO talk to the user - try!(self.render(&book_project)); + match self.render(&book_project) { + Ok(_) => {}, + Err(e) => { + println!("Error: {:#?}", e); + return Err(e); + } + } Ok(()) } diff --git a/src/tests/fs_test.rs b/src/tests/fs_test.rs index c4a9dfda..a1874358 100644 --- a/src/tests/fs_test.rs +++ b/src/tests/fs_test.rs @@ -1,11 +1,14 @@ #[cfg(test)] +extern crate tempdir; + use std; use std::fs::{self, File}; use std::io::Read; use std::path::Path; use utils; +use utils::fs::copy_files_except_ext; #[test] fn it_copies_data_file() { @@ -79,3 +82,65 @@ fn it_doesnt_delete_toplevel_dotfiles() { fs::remove_dir_all(dest_base); } } + +#[test] +fn copy_files_except_ext_test() { + let tmp = match tempdir::TempDir::new("") { + Ok(t) => t, + Err(_) => panic!("Could not create a temp dir"), + }; + + // Create a couple of files + if let Err(_) = fs::File::create(&tmp.path().join("file.txt")) { + panic!("Could not create file.txt") + } + if let Err(_) = fs::File::create(&tmp.path().join("file.md")) { + panic!("Could not create file.md") + } + if let Err(_) = fs::File::create(&tmp.path().join("file.png")) { + panic!("Could not create file.png") + } + if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir")) { + panic!("Could not create sub_dir") + } + if let Err(_) = fs::File::create(&tmp.path().join("sub_dir/file.png")) { + panic!("Could not create sub_dir/file.png") + } + if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir_exists")) { + panic!("Could not create sub_dir_exists") + } + if let Err(_) = fs::File::create(&tmp.path().join("sub_dir_exists/file.txt")) { + panic!("Could not create sub_dir_exists/file.txt") + } + + // Create output dir + if let Err(_) = fs::create_dir(&tmp.path().join("output")) { + panic!("Could not create output") + } + if let Err(_) = fs::create_dir(&tmp.path().join("output/sub_dir_exists")) { + panic!("Could not create output/sub_dir_exists") + } + + match copy_files_except_ext(&tmp.path(), &tmp.path().join("output"), true, &["md"]) { + Err(e) => panic!("Error while executing the function:\n{:?}", e), + Ok(_) => {}, + } + + // Check if the correct files where created + if !(&tmp.path().join("output/file.txt")).exists() { + panic!("output/file.txt should exist") + } + if (&tmp.path().join("output/file.md")).exists() { + panic!("output/file.md should not exist") + } + if !(&tmp.path().join("output/file.png")).exists() { + panic!("output/file.png should exist") + } + if !(&tmp.path().join("output/sub_dir/file.png")).exists() { + panic!("output/sub_dir/file.png should exist") + } + if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() { + panic!("output/sub_dir/file.png should exist") + } + +} diff --git a/src/utils/fs.rs b/src/utils/fs.rs index 6a0a90e4..d07002a9 100644 --- a/src/utils/fs.rs +++ b/src/utils/fs.rs @@ -68,7 +68,7 @@ pub fn copy_data_file(src_path: &str, dest_path: &Path) -> Result<(), Box /// I.e. "data/_html-template/css/book.css" will be written to /// "assets/css/book.css". /// -/// ```no_run +/// ```ignore /// utils::fs::copy_data("data/_html-template/**/*", /// "data/_html-template/", /// vec!["data/_html-template/_*"], @@ -378,78 +378,3 @@ pub fn create_gitignore(proj: &MDBook) { f.write_all(&text.into_bytes()).expect("Could not write to file."); } - -// ------------------------------------------------------------------------------------------------ -// ------------------------------------------------------------------------------------------------ - -// tests - -#[cfg(test)] -mod tests { - extern crate tempdir; - - use super::copy_files_except_ext; - use std::fs; - - #[test] - fn copy_files_except_ext_test() { - let tmp = match tempdir::TempDir::new("") { - Ok(t) => t, - Err(_) => panic!("Could not create a temp dir"), - }; - - // Create a couple of files - if let Err(_) = fs::File::create(&tmp.path().join("file.txt")) { - panic!("Could not create file.txt") - } - if let Err(_) = fs::File::create(&tmp.path().join("file.md")) { - panic!("Could not create file.md") - } - if let Err(_) = fs::File::create(&tmp.path().join("file.png")) { - panic!("Could not create file.png") - } - if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir")) { - panic!("Could not create sub_dir") - } - if let Err(_) = fs::File::create(&tmp.path().join("sub_dir/file.png")) { - panic!("Could not create sub_dir/file.png") - } - if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir_exists")) { - panic!("Could not create sub_dir_exists") - } - if let Err(_) = fs::File::create(&tmp.path().join("sub_dir_exists/file.txt")) { - panic!("Could not create sub_dir_exists/file.txt") - } - - // Create output dir - if let Err(_) = fs::create_dir(&tmp.path().join("output")) { - panic!("Could not create output") - } - if let Err(_) = fs::create_dir(&tmp.path().join("output/sub_dir_exists")) { - panic!("Could not create output/sub_dir_exists") - } - - match copy_files_except_ext(&tmp.path(), &tmp.path().join("output"), true, &["md"]) { - Err(e) => panic!("Error while executing the function:\n{:?}", e), - Ok(_) => {}, - } - - // Check if the correct files where created - if !(&tmp.path().join("output/file.txt")).exists() { - panic!("output/file.txt should exist") - } - if (&tmp.path().join("output/file.md")).exists() { - panic!("output/file.md should not exist") - } - if !(&tmp.path().join("output/file.png")).exists() { - panic!("output/file.png should exist") - } - if !(&tmp.path().join("output/sub_dir/file.png")).exists() { - panic!("output/sub_dir/file.png should exist") - } - if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() { - panic!("output/sub_dir/file.png should exist") - } - - } -}