Skip to content

Commit c89245b

Browse files
Recursively apply replace_all() when running the links preprocessor (#564)
* Looks like we forgot to recursively apply replace_all() in #532 * Removed some print statements * Made sure we ignore the rendered dummy_book
1 parent 05e4157 commit c89245b

File tree

7 files changed

+404
-267
lines changed

7 files changed

+404
-267
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@ target
77
book-test
88
book-example/book
99

10-
.vscode
10+
.vscode
11+
tests/dummy_book/book/
12+

src/book/book.rs

+72-7
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use super::summary::{parse_summary, Link, SectionNumber, Summary, SummaryItem};
88
use config::BuildConfig;
99
use errors::*;
1010

11-
1211
/// Load a book into memory from its `src/` directory.
1312
pub fn load_book<P: AsRef<Path>>(src_dir: P, cfg: &BuildConfig) -> Result<Book> {
1413
let src_dir = src_dir.as_ref();
@@ -60,14 +59,19 @@ fn create_missing(src_dir: &Path, summary: &Summary) -> Result<()> {
6059
Ok(())
6160
}
6261

63-
6462
/// A dumb tree structure representing a book.
6563
///
66-
/// For the moment a book is just a collection of `BookItems`.
64+
/// For the moment a book is just a collection of `BookItems` which are
65+
/// accessible by either iterating (immutably) over the book with [`iter()`], or
66+
/// recursively applying a closure to each section to mutate the chapters, using
67+
/// [`for_each_mut()`].
68+
///
69+
/// [`iter()`]: #method.iter
70+
/// [`for_each_mut()`]: #method.for_each_mut
6771
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
6872
pub struct Book {
6973
/// The sections in this book.
70-
pub sections: Vec<BookItem>,
74+
sections: Vec<BookItem>,
7175
}
7276

7377
impl Book {
@@ -82,6 +86,35 @@ impl Book {
8286
items: self.sections.iter().collect(),
8387
}
8488
}
89+
90+
/// Recursively apply a closure to each item in the book, allowing you to
91+
/// mutate them.
92+
///
93+
/// # Note
94+
///
95+
/// Unlike the `iter()` method, this requires a closure instead of returning
96+
/// an iterator. This is because using iterators can possibly allow you
97+
/// to have iterator invalidation errors.
98+
pub fn for_each_mut<F>(&mut self, mut func: F)
99+
where
100+
F: FnMut(&mut BookItem),
101+
{
102+
for_each_mut(&mut func, &mut self.sections);
103+
}
104+
}
105+
106+
pub fn for_each_mut<'a, F, I>(func: &mut F, items: I)
107+
where
108+
F: FnMut(&mut BookItem),
109+
I: IntoIterator<Item = &'a mut BookItem>,
110+
{
111+
for item in items {
112+
if let &mut BookItem::Chapter(ref mut ch) = item {
113+
for_each_mut(func, &mut ch.sub_items);
114+
}
115+
116+
func(item);
117+
}
85118
}
86119

87120
/// Enum representing any type of item which can be added to a book.
@@ -224,7 +257,6 @@ impl Display for Chapter {
224257
}
225258
}
226259

227-
228260
#[cfg(test)]
229261
mod tests {
230262
use super::*;
@@ -266,7 +298,6 @@ And here is some \
266298
.write_all("Hello World!".as_bytes())
267299
.unwrap();
268300

269-
270301
let mut second = Link::new("Nested Chapter 1", &second_path);
271302
second.number = Some(SectionNumber(vec![1, 2]));
272303

@@ -391,7 +422,6 @@ And here is some \
391422
],
392423
};
393424

394-
395425
let got: Vec<_> = book.iter().collect();
396426

397427
assert_eq!(got.len(), 5);
@@ -411,4 +441,39 @@ And here is some \
411441

412442
assert_eq!(chapter_names, should_be);
413443
}
444+
445+
#[test]
446+
fn for_each_mut_visits_all_items() {
447+
let mut book = Book {
448+
sections: vec![
449+
BookItem::Chapter(Chapter {
450+
name: String::from("Chapter 1"),
451+
content: String::from(DUMMY_SRC),
452+
number: None,
453+
path: PathBuf::from("Chapter_1/index.md"),
454+
sub_items: vec![
455+
BookItem::Chapter(Chapter::new(
456+
"Hello World",
457+
String::new(),
458+
"Chapter_1/hello.md",
459+
)),
460+
BookItem::Separator,
461+
BookItem::Chapter(Chapter::new(
462+
"Goodbye World",
463+
String::new(),
464+
"Chapter_1/goodbye.md",
465+
)),
466+
],
467+
}),
468+
BookItem::Separator,
469+
],
470+
};
471+
472+
let num_items = book.iter().count();
473+
let mut visited = 0;
474+
475+
book.for_each_mut(|_| visited += 1);
476+
477+
assert_eq!(visited, num_items);
478+
}
414479
}

0 commit comments

Comments
 (0)