Started integrating some of the feedback from budziq
This commit is contained in:
parent
b925c7c41c
commit
4202ead962
|
@ -1,5 +1,3 @@
|
|||
#![allow(missing_docs, unused_variables, unused_imports, dead_code)]
|
||||
|
||||
use std::path::Path;
|
||||
use std::collections::VecDeque;
|
||||
use std::fs::File;
|
||||
|
|
|
@ -9,30 +9,8 @@
|
|||
//!
|
||||
//! ```rust,no_run
|
||||
//! # fn run() -> mdbook::errors::Result<()> {
|
||||
//! use mdbook::loader::Loader;
|
||||
//! let loader = Loader::new("./src/");
|
||||
//! let book = loader.load()?;
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! # fn main() { run().unwrap() }
|
||||
//! ```
|
||||
//!
|
||||
//! Alternatively, if you are using the `mdbook` crate as a library and
|
||||
//! only want to read the `SUMMARY.md` file without having to load the
|
||||
//! entire book from disk, you can use the `parse_summary()` function.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # fn run() -> mdbook::errors::Result<()> {
|
||||
//! use mdbook::loader::parse_summary;
|
||||
//! let src = "# Book Summary
|
||||
//!
|
||||
//! [Introduction](./index.md)
|
||||
//! - [First Chapter](./first/index.md)
|
||||
//! - [Sub-Section](./first/subsection.md)
|
||||
//! - [Second Chapter](./second/index.md)
|
||||
//! ";
|
||||
//! let summary = parse_summary(src)?;
|
||||
//! println!("{:#?}", summary);
|
||||
//! use mdbook::loader::load_book;
|
||||
//! let book = load_book("./src/")?;
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! # fn main() { run().unwrap() }
|
||||
|
@ -48,51 +26,24 @@ use errors::*;
|
|||
mod summary;
|
||||
mod book;
|
||||
|
||||
pub use self::summary::{Summary, Link, SummaryItem, parse_summary, SectionNumber};
|
||||
pub use self::book::{Book, BookItems, load_book_from_disk, BookItem, Chapter};
|
||||
pub use self::book::{Book, BookItems, BookItem, Chapter};
|
||||
|
||||
use self::book::load_book_from_disk;
|
||||
use self::summary::parse_summary;
|
||||
|
||||
/// The object in charge of parsing the source directory into a usable
|
||||
/// `Book` struct.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Loader {
|
||||
source_directory: PathBuf,
|
||||
}
|
||||
/// Load a book into memory from its `src/` directory.
|
||||
pub fn load_book<P: AsRef<Path>>(src_dir: P) -> Result<Book> {
|
||||
let src_dir = src_dir.as_ref();
|
||||
let summary_md = src_dir.join("SUMMARY.md");
|
||||
|
||||
impl Loader {
|
||||
/// Create a new loader which uses the provided source directory.
|
||||
pub fn new<P: AsRef<Path>>(source_directory: P) -> Loader {
|
||||
Loader { source_directory: source_directory.as_ref().to_path_buf() }
|
||||
}
|
||||
let mut summary_content = String::new();
|
||||
File::open(summary_md)
|
||||
.chain_err(|| "Couldn't open SUMMARY.md")?
|
||||
.read_to_string(&mut summary_content)?;
|
||||
|
||||
/// Parse the summary file and use it to load a book from disk.
|
||||
pub fn load(&self) -> Result<Book> {
|
||||
let summary_md = self.find_summary().chain_err(
|
||||
|| "Couldn't find `SUMMARY.md`",
|
||||
let summary = parse_summary(&summary_content).chain_err(
|
||||
|| "Summary parsing failed",
|
||||
)?;
|
||||
|
||||
let summary = self.parse_summary(&summary_md).chain_err(
|
||||
|| "Couldn't parse `SUMMARY.md`",
|
||||
)?;
|
||||
|
||||
let src_dir = match summary_md.parent() {
|
||||
Some(parent) => parent,
|
||||
None => bail!("SUMMARY.md doesn't have a parent... wtf?"),
|
||||
};
|
||||
load_book_from_disk(&summary, src_dir)
|
||||
}
|
||||
|
||||
/// Parse a `SUMMARY.md` file.
|
||||
pub fn parse_summary<P: AsRef<Path>>(&self, summary_md: P) -> Result<Summary> {
|
||||
let mut summary_content = String::new();
|
||||
File::open(summary_md)?.read_to_string(&mut summary_content)?;
|
||||
|
||||
summary::parse_summary(&summary_content)
|
||||
}
|
||||
|
||||
fn find_summary(&self) -> Result<PathBuf> {
|
||||
// TODO: use Piston's find_folder to make locating SUMMARY.md easier.
|
||||
// https://github.com/PistonDevelopers/find_folder
|
||||
Ok(self.source_directory.join("SUMMARY.md"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
use std::fmt::{self, Formatter, Display};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
|
105
tests/loading.rs
105
tests/loading.rs
|
@ -7,117 +7,16 @@ extern crate env_logger;
|
|||
extern crate tempdir;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
||||
use mdbook::loader::{parse_summary, Link, SummaryItem, SectionNumber, Summary, Loader};
|
||||
use tempdir::TempDir;
|
||||
use mdbook::loader::load_book;
|
||||
|
||||
|
||||
const SUMMARY: &'static str = "
|
||||
# Summary
|
||||
|
||||
[Introduction](/intro.md)
|
||||
|
||||
---
|
||||
|
||||
[A Prefix Chapter](/some_prefix.md)
|
||||
|
||||
- [First Chapter](/chapter_1/index.md)
|
||||
- [Some Subsection](/chapter_1/subsection.md)
|
||||
|
||||
---
|
||||
|
||||
[Conclusion](/conclusion.md)
|
||||
";
|
||||
|
||||
#[test]
|
||||
fn parse_summary_md() {
|
||||
env_logger::init().ok();
|
||||
|
||||
let should_be = expected_summary();
|
||||
let got = parse_summary(SUMMARY).unwrap();
|
||||
|
||||
println!("{:#?}", got);
|
||||
assert_eq!(got, should_be);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_summary_using_loader() {
|
||||
env_logger::init().ok();
|
||||
|
||||
let temp = TempDir::new("book").unwrap();
|
||||
let summary_md = temp.path().join("SUMMARY.md");
|
||||
|
||||
File::create(&summary_md)
|
||||
.unwrap()
|
||||
.write_all(SUMMARY.as_bytes())
|
||||
.unwrap();
|
||||
|
||||
let loader = Loader::new(temp.path());
|
||||
|
||||
let got = loader.parse_summary(&summary_md).unwrap();
|
||||
let should_be = expected_summary();
|
||||
|
||||
assert_eq!(got, should_be);
|
||||
}
|
||||
|
||||
/// This is what the SUMMARY should be parsed as
|
||||
fn expected_summary() -> Summary {
|
||||
Summary {
|
||||
title: Some(String::from("Summary")),
|
||||
|
||||
prefix_chapters: vec![
|
||||
SummaryItem::Link(Link {
|
||||
name: String::from("Introduction"),
|
||||
location: PathBuf::from("/intro.md"),
|
||||
number: None,
|
||||
nested_items: vec![],
|
||||
}),
|
||||
SummaryItem::Separator,
|
||||
SummaryItem::Link(Link {
|
||||
name: String::from("A Prefix Chapter"),
|
||||
location: PathBuf::from("/some_prefix.md"),
|
||||
number: None,
|
||||
nested_items: vec![],
|
||||
}),
|
||||
],
|
||||
|
||||
numbered_chapters: vec![
|
||||
SummaryItem::Link(Link {
|
||||
name: String::from("First Chapter"),
|
||||
location: PathBuf::from("/chapter_1/index.md"),
|
||||
number: Some(SectionNumber(vec![1])),
|
||||
nested_items: vec![
|
||||
SummaryItem::Link(Link {
|
||||
name: String::from("Some Subsection"),
|
||||
location: PathBuf::from("/chapter_1/subsection.md"),
|
||||
number: Some(SectionNumber(vec![1, 1])),
|
||||
nested_items: vec![],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
|
||||
suffix_chapters: vec![
|
||||
SummaryItem::Separator,
|
||||
SummaryItem::Link(Link {
|
||||
name: String::from("Conclusion"),
|
||||
location: PathBuf::from("/conclusion.md"),
|
||||
number: None,
|
||||
nested_items: vec![],
|
||||
}),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_the_example_book() {
|
||||
let example_src_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("book-example")
|
||||
.join("src");
|
||||
let loader = Loader::new(example_src_dir);
|
||||
|
||||
let book = loader.load().unwrap();
|
||||
let book = load_book(example_src_dir).unwrap();
|
||||
println!("{:#?}", book);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue