Fleshed out the docs for the book module

This commit is contained in:
Michael Bryan 2017-12-11 11:24:43 +11:00
parent ace0b51fb6
commit be4654c9c2
No known key found for this signature in database
GPG Key ID: E9C602B0D9A998DC
4 changed files with 89 additions and 18 deletions

View File

@ -69,8 +69,8 @@ where
}; };
// Add the source directory to the watcher // Add the source directory to the watcher
if let Err(e) = watcher.watch(book.get_source(), Recursive) { if let Err(e) = watcher.watch(book.source_dir(), Recursive) {
println!("Error while watching {:?}:\n {:?}", book.get_source(), e); println!("Error while watching {:?}:\n {:?}", book.source_dir(), e);
::std::process::exit(0); ::std::process::exit(0);
}; };

View File

@ -19,6 +19,8 @@ pub struct BookBuilder {
} }
impl BookBuilder { impl BookBuilder {
/// Create a new `BookBuilder` which will generate a book in the provided
/// root directory.
pub fn new<P: Into<PathBuf>>(root: P) -> BookBuilder { pub fn new<P: Into<PathBuf>>(root: P) -> BookBuilder {
BookBuilder { BookBuilder {
root: root.into(), root: root.into(),
@ -34,20 +36,32 @@ impl BookBuilder {
self 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 { pub fn copy_theme(&mut self, copy: bool) -> &mut BookBuilder {
self.copy_theme = copy; self.copy_theme = copy;
self self
} }
/// Should we create a `.gitignore` file?
pub fn create_gitignore(&mut self, create: bool) -> &mut BookBuilder { pub fn create_gitignore(&mut self, create: bool) -> &mut BookBuilder {
self.create_gitignore = create; self.create_gitignore = create;
self self
} }
pub fn config(&self) -> &Config { /// Generate the actual book. This will:
&self.config ///
} /// - 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<MDBook> { pub fn build(&self) -> Result<MDBook> {
info!("Creating a new book with stub content"); info!("Creating a new book with stub content");
@ -69,18 +83,23 @@ impl BookBuilder {
self.write_book_toml()?; self.write_book_toml()?;
let book = MDBook::load(&self.root) match MDBook::load(&self.root) {
.expect("The BookBuilder should always create a valid book. \ Ok(book) => Ok(book),
If you are seeing this it is a bug and should be reported."); 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<()> { fn write_book_toml(&self) -> Result<()> {
debug!("[*] Writing book.toml"); debug!("[*] Writing book.toml");
let book_toml = self.root.join("book.toml"); let book_toml = self.root.join("book.toml");
let cfg = toml::to_vec(&self.config) let cfg = toml::to_vec(&self.config).chain_err(|| "Unable to serialize the config")?;
.chain_err(|| "Unable to serialize the config")?;
File::create(book_toml) File::create(book_toml)
.chain_err(|| "Couldn't create book.toml")? .chain_err(|| "Couldn't create book.toml")?
@ -92,14 +111,15 @@ impl BookBuilder {
fn copy_across_theme(&self) -> Result<()> { fn copy_across_theme(&self) -> Result<()> {
debug!("[*] Copying theme"); debug!("[*] Copying theme");
let themedir = self.config.html_config() let themedir = self.config
.html_config()
.and_then(|html| html.theme) .and_then(|html| html.theme)
.unwrap_or_else(|| self.config.book.src.join("theme")); .unwrap_or_else(|| self.config.book.src.join("theme"));
let themedir = self.root.join(themedir); let themedir = self.root.join(themedir);
if !themedir.exists() { if !themedir.exists() {
debug!("[*]: {:?} does not exist, creating the directory", debug!("[*]: {:?} does not exist, creating the directory", themedir);
themedir); fs::create_dir(&themedir)?; fs::create_dir(&themedir)?;
} }
let mut index = File::create(themedir.join("index.hbs"))?; let mut index = File::create(themedir.join("index.hbs"))?;

View File

@ -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 summary;
mod book; mod book;
mod init; mod init;
@ -18,13 +57,17 @@ use errors::*;
use config::Config; use config::Config;
/// The object used to manage and build a book.
pub struct MDBook { pub struct MDBook {
/// The book's root directory.
pub root: PathBuf, pub root: PathBuf,
/// The configuration used to tweak now a book is built.
pub config: Config, pub config: Config,
book: Book, book: Book,
renderer: Box<Renderer>, renderer: Box<Renderer>,
/// The URL used for live reloading when serving up the book.
pub livereload: Option<String>, pub livereload: Option<String>,
} }
@ -123,6 +166,8 @@ impl MDBook {
self.renderer.render(self) 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<P: AsRef<Path>>(&self, filename: P, content: &[u8]) -> Result<()> { pub fn write_file<P: AsRef<Path>>(&self, filename: P, content: &[u8]) -> Result<()> {
let path = self.get_destination().join(filename); let path = self.get_destination().join(filename);
@ -139,6 +184,7 @@ impl MDBook {
self self
} }
/// Run `rustdoc` tests on the book, linking against the provided libraries.
pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> { pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> {
let library_args: Vec<&str> = (0..library_paths.len()) let library_args: Vec<&str> = (0..library_paths.len())
.map(|_| "-L") .map(|_| "-L")
@ -151,7 +197,7 @@ impl MDBook {
for item in self.iter() { for item in self.iter() {
if let BookItem::Chapter(ref ch) = *item { if let BookItem::Chapter(ref ch) = *item {
if !ch.path.as_os_str().is_empty() { 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() let base = path.parent()
.ok_or_else(|| String::from("Invalid bookitem path!"))?; .ok_or_else(|| String::from("Invalid bookitem path!"))?;
let content = utils::fs::file_to_string(&path)?; let content = utils::fs::file_to_string(&path)?;
@ -182,14 +228,19 @@ impl MDBook {
Ok(()) 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 { pub fn get_destination(&self) -> PathBuf {
self.root.join(&self.config.build.build_dir) 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) self.root.join(&self.config.book.src)
} }
// FIXME: This belongs as part of the `HtmlConfig`.
#[doc(hidden)]
pub fn theme_dir(&self) -> PathBuf { pub fn theme_dir(&self) -> PathBuf {
match self.config.html_config().and_then(|h| h.theme) { match self.config.html_config().and_then(|h| h.theme) {
Some(d) => self.root.join(d), Some(d) => self.root.join(d),

View File

@ -318,7 +318,7 @@ impl Renderer for HtmlHandlebars {
self.copy_additional_css_and_js(book)?; self.copy_additional_css_and_js(book)?;
// Copy all remaining files // Copy all remaining files
let src = book.get_source(); let src = book.source_dir();
utils::fs::copy_files_except_ext(&src, &destination, true, &["md"])?; utils::fs::copy_files_except_ext(&src, &destination, true, &["md"])?;
Ok(()) Ok(())