Created a SUMMARY.md parser and basic Loader
From the [pull request comment][pr], here's a rough summary of what
was done in the squashed commits.
---
\# Summary Parser
- Added a private submodule called `mdbook::loader::summary` which
contains all the code for parsing `SUMMARY.md`
- A `Summary` contains a title (optional), then some prefix, numbered,
and suffix chapters (technically `Vec<SummaryItem>`)
- A `SummaryItem` is either a `Link` (i.e. link to a chapter), or a
separator
- A `Link` contains the chapter name, its location relative to the
book's `src/` directory, and a list of nested `SummaryItems`
- The `SummaryParser` (a state machine-based parser) uses
`pulldown_cmark` to turn the `SUMMARY.md` string into a stream of
`Events`, it then iterates over those events changing its behaviour
depending on the current state,
- The states are `Start`, `PrefixChapters`, `NestedChapters(u32)` (the
`u32` represents your nesting level, because lists can contain lists),
`SuffixChapters`, and `End`
- Each state will read the appropriate link and build up the
`Summary`, skipping any events which aren't a link, horizontal rule
(separator), or a list
\# Loader
- Created a basic loader which can be used to load the `SUMMARY.md` in
a directory.
\# Tests
- Added a couple unit tests for each state in the parser's state
machine
- Added integration tests for parsing a dummy SUMMARY.md then asserting
the result is exactly what we expected
[pr]: https://github.com/azerupi/mdBook/pull/371#issuecomment-312636102
2017-06-24 22:47:03 +08:00
|
|
|
//! Integration tests for loading a book into memory
|
|
|
|
|
|
|
|
#[macro_use]
|
|
|
|
extern crate pretty_assertions;
|
|
|
|
extern crate mdbook;
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
2017-07-03 07:34:03 +08:00
|
|
|
File::create(&summary_md)
|
|
|
|
.unwrap()
|
|
|
|
.write_all(SUMMARY.as_bytes())
|
|
|
|
.unwrap();
|
Created a SUMMARY.md parser and basic Loader
From the [pull request comment][pr], here's a rough summary of what
was done in the squashed commits.
---
\# Summary Parser
- Added a private submodule called `mdbook::loader::summary` which
contains all the code for parsing `SUMMARY.md`
- A `Summary` contains a title (optional), then some prefix, numbered,
and suffix chapters (technically `Vec<SummaryItem>`)
- A `SummaryItem` is either a `Link` (i.e. link to a chapter), or a
separator
- A `Link` contains the chapter name, its location relative to the
book's `src/` directory, and a list of nested `SummaryItems`
- The `SummaryParser` (a state machine-based parser) uses
`pulldown_cmark` to turn the `SUMMARY.md` string into a stream of
`Events`, it then iterates over those events changing its behaviour
depending on the current state,
- The states are `Start`, `PrefixChapters`, `NestedChapters(u32)` (the
`u32` represents your nesting level, because lists can contain lists),
`SuffixChapters`, and `End`
- Each state will read the appropriate link and build up the
`Summary`, skipping any events which aren't a link, horizontal rule
(separator), or a list
\# Loader
- Created a basic loader which can be used to load the `SUMMARY.md` in
a directory.
\# Tests
- Added a couple unit tests for each state in the parser's state
machine
- Added integration tests for parsing a dummy SUMMARY.md then asserting
the result is exactly what we expected
[pr]: https://github.com/azerupi/mdBook/pull/371#issuecomment-312636102
2017-06-24 22:47:03 +08:00
|
|
|
|
|
|
|
let loader = Loader::new(temp.path());
|
|
|
|
|
2017-07-03 07:34:03 +08:00
|
|
|
let got = loader.parse_summary(&summary_md).unwrap();
|
Created a SUMMARY.md parser and basic Loader
From the [pull request comment][pr], here's a rough summary of what
was done in the squashed commits.
---
\# Summary Parser
- Added a private submodule called `mdbook::loader::summary` which
contains all the code for parsing `SUMMARY.md`
- A `Summary` contains a title (optional), then some prefix, numbered,
and suffix chapters (technically `Vec<SummaryItem>`)
- A `SummaryItem` is either a `Link` (i.e. link to a chapter), or a
separator
- A `Link` contains the chapter name, its location relative to the
book's `src/` directory, and a list of nested `SummaryItems`
- The `SummaryParser` (a state machine-based parser) uses
`pulldown_cmark` to turn the `SUMMARY.md` string into a stream of
`Events`, it then iterates over those events changing its behaviour
depending on the current state,
- The states are `Start`, `PrefixChapters`, `NestedChapters(u32)` (the
`u32` represents your nesting level, because lists can contain lists),
`SuffixChapters`, and `End`
- Each state will read the appropriate link and build up the
`Summary`, skipping any events which aren't a link, horizontal rule
(separator), or a list
\# Loader
- Created a basic loader which can be used to load the `SUMMARY.md` in
a directory.
\# Tests
- Added a couple unit tests for each state in the parser's state
machine
- Added integration tests for parsing a dummy SUMMARY.md then asserting
the result is exactly what we expected
[pr]: https://github.com/azerupi/mdBook/pull/371#issuecomment-312636102
2017-06-24 22:47:03 +08:00
|
|
|
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![],
|
|
|
|
}),
|
|
|
|
],
|
|
|
|
}
|
|
|
|
}
|
2017-07-03 07:34:03 +08:00
|
|
|
|
|
|
|
#[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();
|
|
|
|
println!("{:#?}", book);
|
|
|
|
}
|