From ebd075af08ab022123b6b8cd0b9c56e96401a8be Mon Sep 17 00:00:00 2001 From: Mathieu David Date: Tue, 28 Jun 2016 16:38:12 +0200 Subject: [PATCH 1/5] Add structs holding metadata for the books --- src/book/metadata.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/book/metadata.rs diff --git a/src/book/metadata.rs b/src/book/metadata.rs new file mode 100644 index 00000000..0be79be7 --- /dev/null +++ b/src/book/metadata.rs @@ -0,0 +1,71 @@ +#[derive(Debug, Clone)] +pub struct BookMetadata { + pub title: String, + pub description: String, + + pub language: Language, + + authors: Vec, + translators: Vec, +} + +#[derive(Debug, Clone)] +pub struct Author { + name: String, + email: Option, +} + +#[derive(Debug, Clone)] +pub struct Language { + name: String, + code: String, +} + + +impl BookMetadata { + pub fn new(title: &str) -> Self { + BookMetadata { + title: title.to_owned(), + description: String::new(), + + language: Language::default(), + + authors: Vec::new(), + translators: Vec::new(), + } + } + + pub fn set_description(&mut self, description: &str) -> &mut Self { + self.description = description.to_owned(); + self + } + + pub fn add_author(&mut self, author: Author) -> &mut Self { + self.authors.push(author); + self + } +} + +impl Author { + pub fn new(name: &str) -> Self { + Author { + name: name.to_owned(), + email: None, + } + } + + pub fn with_email(mut self, email: &str) -> Self { + self.email = Some(email.to_owned()); + self + } +} + + +impl Default for Language { + fn default() -> Self { + Language { + name: String::from("English"), + code: String::from("en"), + } + } +} From e5848580ae476cf1a3aa2401a376f17e1d60de5b Mon Sep 17 00:00:00 2001 From: Mathieu David Date: Tue, 28 Jun 2016 17:02:49 +0200 Subject: [PATCH 2/5] Add a new Chapter struct for the new Book struct --- src/book/chapter.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/book/chapter.rs diff --git a/src/book/chapter.rs b/src/book/chapter.rs new file mode 100644 index 00000000..bd37ccac --- /dev/null +++ b/src/book/chapter.rs @@ -0,0 +1,52 @@ +use book::metadata::BookMetadata; + +use std::path; + +/// The Chapter struct holds the title of the chapter as written in the SUMMARY.md file, +/// the location of the markdown file containing the content and eventually sub-chapters +pub struct Chapter { + title: String, + file: path::PathBuf, + + sub_chapters: Vec, +} + + +impl Chapter { + /// Creates a new chapter with the given title and source file and no sub-chapters + pub fn new(title: &str, file: &path::Path) -> Self { + Chapter { + title: title.to_owned(), + file: file.to_owned(), + + sub_chapters: Vec::new(), + } + } + + /// This function takes a slice `&[x,y,z]` and returns the corresponding sub-chapter if it exists. + /// + /// For example: `chapter.get_sub_chapter(&[1,3])` will return the third sub-chapter of the first sub-chapter. + pub fn get_sub_chapter(&self, section: &[usize]) -> Option<&Chapter> { + match section.len() { + 0 => None, + 1 => self.sub_chapters.get(section[0]), + _ => { + // The lengt of the slice is more than one, this means that we want a sub-chapter of a sub-chapter + // We call `get_sub_chapter` recursively until we are deep enough and return the asked sub-chapter + self.sub_chapters + .get(section[0]) + .and_then(|ch| ch.get_sub_chapter(§ion[1..])) + }, + } + } + + pub fn title(&self) -> &str { + &self.title + } + pub fn file(&self) -> &path::Path { + &self.file + } + pub fn sub_chapters(&self) -> &[Chapter] { + &self.sub_chapters + } +} From c69161cef88baaf33fa0b20c4c855202cbb54ef8 Mon Sep 17 00:00:00 2001 From: Mathieu David Date: Tue, 28 Jun 2016 18:59:13 +0200 Subject: [PATCH 3/5] Add the new book struct --- src/book/book.rs | 77 +++++++++++++++++++++++++++++++++++++++++++++ src/book/chapter.rs | 2 -- src/book/mod.rs | 7 +++++ 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 src/book/book.rs diff --git a/src/book/book.rs b/src/book/book.rs new file mode 100644 index 00000000..c5e46de8 --- /dev/null +++ b/src/book/book.rs @@ -0,0 +1,77 @@ +use book::metadata::BookMetadata; +use book::chapter::Chapter; + + +/// The `Book` struct contains the metadata and chapters for one language of the book. +/// Multiple `Book` structs are combined in the `MDBook` struct to support multi-language books. +pub struct Book { + metadata: BookMetadata, + + preface: Vec, + chapters: Vec, + appendix: Vec, +} + +impl Book { + /// Creates a new book with the given title, chapters are added with the `add_chapter` method + pub fn new(title: &str) -> Self { + Book { + metadata: BookMetadata::new(title), + + preface: Vec::new(), + chapters: Vec::new(), + appendix: Vec::new(), + } + } + + /// Adds a new chapter at the end of the book + pub fn add_chapter(&mut self, chapter: Chapter) -> &mut Self { + self.chapters.push(chapter); + self + } + + /// Adds a new preface chapter to the book, the preface chapters are in the order they were added + pub fn add_preface_chapter(&mut self, chapter: Chapter) -> &mut Self { + self.preface.push(chapter); + self + } + + /// Adds a new appendix chapter to the book, they are in de order they are added + pub fn add_appendix_chapter(&mut self, chapter: Chapter) -> &mut Self { + self.appendix.push(chapter); + self + } + + + /// 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: + /// ``` + /// #extern crate mdbook; + /// #use mdbook::book::Book; + /// #fn main() { + /// #let book = Book::new("Test"); + /// let chapter_2_3 = book.get_chapter(&[2, 3]); + /// #} + /// ``` + pub fn get_chapter(&self, section: &[usize]) -> Option<&Chapter> { + match section.len() { + 0 => None, + 1 => self.chapters.get(section[0]), + _ => { + self.chapters + .get(section[0]) + .and_then(|ch| ch.get_sub_chapter(§ion[1..])) + }, + } + } + + /// Returns a mutable reference to the metadata for modification + pub fn mut_metadata(&mut self) -> &mut BookMetadata { + &mut self.metadata + } + + // Returns a reference to the metadata + pub fn metadata(&self) -> &BookMetadata { + &self.metadata + } +} diff --git a/src/book/chapter.rs b/src/book/chapter.rs index bd37ccac..23244cb5 100644 --- a/src/book/chapter.rs +++ b/src/book/chapter.rs @@ -1,5 +1,3 @@ -use book::metadata::BookMetadata; - use std::path; /// The Chapter struct holds the title of the chapter as written in the SUMMARY.md file, diff --git a/src/book/mod.rs b/src/book/mod.rs index 4e64092c..4ce695a1 100644 --- a/src/book/mod.rs +++ b/src/book/mod.rs @@ -1,5 +1,12 @@ pub mod bookitem; pub mod bookconfig; +pub mod metadata; +pub mod chapter; +pub mod book; + +pub use self::metadata::{Author, Language, BookMetadata}; +pub use self::chapter::Chapter; +pub use self::book::Book; pub use self::bookitem::{BookItem, BookItems}; pub use self::bookconfig::BookConfig; From d664618e9f307a401275144f3f07a0d4e03426a7 Mon Sep 17 00:00:00 2001 From: Mathieu David Date: Tue, 28 Jun 2016 19:36:06 +0200 Subject: [PATCH 4/5] Derive Clone and Debug for Chapter and Book --- src/book/book.rs | 1 + src/book/chapter.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/book/book.rs b/src/book/book.rs index c5e46de8..18572545 100644 --- a/src/book/book.rs +++ b/src/book/book.rs @@ -4,6 +4,7 @@ use book::chapter::Chapter; /// The `Book` struct contains the metadata and chapters for one language of the book. /// Multiple `Book` structs are combined in the `MDBook` struct to support multi-language books. +#[derive(Debug, Clone)] pub struct Book { metadata: BookMetadata, diff --git a/src/book/chapter.rs b/src/book/chapter.rs index 23244cb5..db8ce3ea 100644 --- a/src/book/chapter.rs +++ b/src/book/chapter.rs @@ -2,6 +2,7 @@ use std::path; /// The Chapter struct holds the title of the chapter as written in the SUMMARY.md file, /// the location of the markdown file containing the content and eventually sub-chapters +#[derive(Debug, Clone)] pub struct Chapter { title: String, file: path::PathBuf, From 3e0dca5ff63fbb8a338b61be283e1f8db3a3777d Mon Sep 17 00:00:00 2001 From: Mathieu David Date: Tue, 28 Jun 2016 22:54:26 +0200 Subject: [PATCH 5/5] Include the new Book struct in a hashmap alongside the old representation --- src/book/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/book/mod.rs b/src/book/mod.rs index 4ce695a1..c6c86129 100644 --- a/src/book/mod.rs +++ b/src/book/mod.rs @@ -18,12 +18,13 @@ use std::io; use std::io::Write; use std::io::ErrorKind; use std::process::Command; +use std::collections::HashMap; use {theme, parse, utils}; use renderer::{Renderer, HtmlHandlebars}; -pub struct MDBook { +pub struct MDBook<'a> { root: PathBuf, dest: PathBuf, src: PathBuf, @@ -33,12 +34,13 @@ pub struct MDBook { pub description: String, pub content: Vec, + books: HashMap<&'a str, Book>, renderer: Box, livereload: Option, } -impl MDBook { +impl<'a> MDBook<'a> { /// Create a new `MDBook` struct with root directory `root` /// /// - The default source directory is set to `root/src` @@ -62,6 +64,7 @@ impl MDBook { description: String::new(), content: vec![], + books: HashMap::new(), renderer: Box::new(HtmlHandlebars::new()), livereload: None,