Skip to content

[WIP] New book struct #147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions src/book/book.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
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.
#[derive(Debug, Clone)]
pub struct Book {
metadata: BookMetadata,

preface: Vec<Chapter>,
chapters: Vec<Chapter>,
appendix: Vec<Chapter>,
}

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(&section[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
}
}
51 changes: 51 additions & 0 deletions src/book/chapter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
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,

sub_chapters: Vec<Chapter>,
}


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(&section[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
}
}
71 changes: 71 additions & 0 deletions src/book/metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#[derive(Debug, Clone)]
pub struct BookMetadata {
pub title: String,
pub description: String,

pub language: Language,

authors: Vec<Author>,
translators: Vec<Author>,
}

#[derive(Debug, Clone)]
pub struct Author {
name: String,
email: Option<String>,
}

#[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"),
}
}
}
14 changes: 12 additions & 2 deletions src/book/mod.rs
Original file line number Diff line number Diff line change
@@ -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 mod bookconfig_test;

Expand All @@ -13,12 +20,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,
Expand All @@ -29,12 +37,13 @@ pub struct MDBook {
pub description: String,

pub content: Vec<BookItem>,
books: HashMap<&'a str, Book>,
renderer: Box<Renderer>,

livereload: Option<String>,
}

impl MDBook {
impl<'a> MDBook<'a> {
/// Create a new `MDBook` struct with root directory `root`
///
/// Default directory paths:
Expand Down Expand Up @@ -62,6 +71,7 @@ impl MDBook {
description: String::new(),

content: vec![],
books: HashMap::new(),
renderer: Box::new(HtmlHandlebars::new()),

livereload: None,
Expand Down