From be4654c9c295dac15fad7315bb1b760f1700055c Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Mon, 11 Dec 2017 11:24:43 +1100 Subject: [PATCH] Fleshed out the docs for the book module --- src/bin/watch.rs | 4 +- src/book/init.rs | 46 +++++++++++----- src/book/mod.rs | 55 +++++++++++++++++++- src/renderer/html_handlebars/hbs_renderer.rs | 2 +- 4 files changed, 89 insertions(+), 18 deletions(-) diff --git a/src/bin/watch.rs b/src/bin/watch.rs index 8055034d..eb9c5b62 100644 --- a/src/bin/watch.rs +++ b/src/bin/watch.rs @@ -69,8 +69,8 @@ where }; // Add the source directory to the watcher - if let Err(e) = watcher.watch(book.get_source(), Recursive) { - println!("Error while watching {:?}:\n {:?}", book.get_source(), e); + if let Err(e) = watcher.watch(book.source_dir(), Recursive) { + println!("Error while watching {:?}:\n {:?}", book.source_dir(), e); ::std::process::exit(0); }; diff --git a/src/book/init.rs b/src/book/init.rs index c97b533b..69dd4490 100644 --- a/src/book/init.rs +++ b/src/book/init.rs @@ -19,6 +19,8 @@ pub struct BookBuilder { } impl BookBuilder { + /// Create a new `BookBuilder` which will generate a book in the provided + /// root directory. pub fn new>(root: P) -> BookBuilder { BookBuilder { root: root.into(), @@ -34,20 +36,32 @@ impl BookBuilder { self } + /// Get the config used by the `BookBuilder`. + pub fn config(&self) -> &Config { + &self.config + } + + /// Should the theme be copied into the generated book (so users can tweak + /// it)? pub fn copy_theme(&mut self, copy: bool) -> &mut BookBuilder { self.copy_theme = copy; self } + /// Should we create a `.gitignore` file? pub fn create_gitignore(&mut self, create: bool) -> &mut BookBuilder { self.create_gitignore = create; self } - pub fn config(&self) -> &Config { - &self.config - } - + /// Generate the actual book. This will: + /// + /// - Create the directory structure. + /// - Stub out some dummy chapters and the `SUMMARY.md`. + /// - Create a `.gitignore` (if applicable) + /// - Create a themes directory and populate it (if applicable) + /// - Generate a `book.toml` file, + /// - Then load the book so we can pub fn build(&self) -> Result { info!("Creating a new book with stub content"); @@ -69,18 +83,23 @@ impl BookBuilder { self.write_book_toml()?; - let book = MDBook::load(&self.root) - .expect("The BookBuilder should always create a valid book. \ - If you are seeing this it is a bug and should be reported."); + match MDBook::load(&self.root) { + Ok(book) => Ok(book), + Err(e) => { + error!("{}", e); - Ok(book) + panic!( + "The BookBuilder should always create a valid book. If you are seeing this it \ + is a bug and should be reported." + ); + } + } } fn write_book_toml(&self) -> Result<()> { debug!("[*] Writing book.toml"); let book_toml = self.root.join("book.toml"); - let cfg = toml::to_vec(&self.config) - .chain_err(|| "Unable to serialize the config")?; + let cfg = toml::to_vec(&self.config).chain_err(|| "Unable to serialize the config")?; File::create(book_toml) .chain_err(|| "Couldn't create book.toml")? @@ -92,14 +111,15 @@ impl BookBuilder { fn copy_across_theme(&self) -> Result<()> { debug!("[*] Copying theme"); - let themedir = self.config.html_config() + let themedir = self.config + .html_config() .and_then(|html| html.theme) .unwrap_or_else(|| self.config.book.src.join("theme")); let themedir = self.root.join(themedir); if !themedir.exists() { - debug!("[*]: {:?} does not exist, creating the directory", - themedir); fs::create_dir(&themedir)?; + debug!("[*]: {:?} does not exist, creating the directory", themedir); + fs::create_dir(&themedir)?; } let mut index = File::create(themedir.join("index.hbs"))?; diff --git a/src/book/mod.rs b/src/book/mod.rs index 58f19dae..557dc713 100644 --- a/src/book/mod.rs +++ b/src/book/mod.rs @@ -1,3 +1,42 @@ +//! The internal representation of a book and infrastructure for loading it from +//! disk and building it. +//! +//! # Examples +//! +//! If creating a new book from scratch, you'll want to get a `BookBuilder` via +//! the `MDBook::init()` method. +//! +//! ```rust,no_run +//! use mdbook::MDBook; +//! use mdbook::config::Config; +//! +//! let root_dir = "/path/to/book/root"; +//! +//! let mut cfg = Config::default(); +//! cfg.book.title = Some("My Book".to_string()); +//! cfg.book.authors.push("Michael-F-Bryan".to_string()); +//! +//! MDBook::init(root_dir) +//! .create_gitignore(true) +//! .with_config(cfg) +//! .build() +//! .expect("Book generation failed"); +//! ``` +//! +//! You can also load an existing book and build it. +//! +//! ```rust,no_run +//! use mdbook::MDBook; +//! +//! let root_dir = "/path/to/book/root"; +//! +//! let mut md = MDBook::load(root_dir) +//! .expect("Unable to load the book"); +//! md.build().expect("Building failed"); +//! ``` + +#![deny(missing_docs)] + mod summary; mod book; mod init; @@ -18,13 +57,17 @@ use errors::*; use config::Config; +/// The object used to manage and build a book. pub struct MDBook { + /// The book's root directory. pub root: PathBuf, + /// The configuration used to tweak now a book is built. pub config: Config, book: Book, renderer: Box, + /// The URL used for live reloading when serving up the book. pub livereload: Option, } @@ -123,6 +166,8 @@ impl MDBook { self.renderer.render(self) } + // FIXME: This doesn't belong as part of `MDBook`. It is only used by the HTML renderer + #[doc(hidden)] pub fn write_file>(&self, filename: P, content: &[u8]) -> Result<()> { let path = self.get_destination().join(filename); @@ -139,6 +184,7 @@ impl MDBook { self } + /// Run `rustdoc` tests on the book, linking against the provided libraries. pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> { let library_args: Vec<&str> = (0..library_paths.len()) .map(|_| "-L") @@ -151,7 +197,7 @@ impl MDBook { for item in self.iter() { if let BookItem::Chapter(ref ch) = *item { if !ch.path.as_os_str().is_empty() { - let path = self.get_source().join(&ch.path); + let path = self.source_dir().join(&ch.path); let base = path.parent() .ok_or_else(|| String::from("Invalid bookitem path!"))?; let content = utils::fs::file_to_string(&path)?; @@ -182,14 +228,19 @@ impl MDBook { Ok(()) } + // FIXME: This doesn't belong under `MDBook`, it should really be passed to the renderer directly. + #[doc(hidden)] pub fn get_destination(&self) -> PathBuf { self.root.join(&self.config.build.build_dir) } - pub fn get_source(&self) -> PathBuf { + /// Get the directory containing this book's source files. + pub fn source_dir(&self) -> PathBuf { self.root.join(&self.config.book.src) } + // FIXME: This belongs as part of the `HtmlConfig`. + #[doc(hidden)] pub fn theme_dir(&self) -> PathBuf { match self.config.html_config().and_then(|h| h.theme) { Some(d) => self.root.join(d), diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index d7f47858..71b6091e 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -318,7 +318,7 @@ impl Renderer for HtmlHandlebars { self.copy_additional_css_and_js(book)?; // Copy all remaining files - let src = book.get_source(); + let src = book.source_dir(); utils::fs::copy_files_except_ext(&src, &destination, true, &["md"])?; Ok(())