-
Notifications
You must be signed in to change notification settings - Fork 1.8k
implementing preprocessors #532
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
implementing preprocessors #532
Conversation
src/preprocess/links.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you need to use mem::replace() here. You could store the replaced text in a temporary (let replaced = replace_all(&ch.content, base)) then update ch.content on the next line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, thanks
|
@JaimeValdemoros I just had another skim through what you've done so far and it looks pretty good 👍 You may want to add a couple tests for the preprocessor discovery, because I feel like there are a couple edge cases we haven't accounted for. For example, what happens if the user passes in an unknown preprocessor, if you specify a preprocessor twice, or if one of the elements in the The easiest way to write the test is probably to create a bunch of dummy configs (just raw strings), run |
|
Hi @JaimeValdemoros, this is just a friendly ping to see how you're going with everything 😀 How far through this issue would you say you are? And is there anything I can do to help? |
|
Hey - sorry about the delay, I've been away and haven't been able to get a
free evening to get it finished. Will have it done tomorrow afternoon if
that's ok.
On 14 Jan 2018 10:34 am, "Michael Bryan" <[email protected]> wrote:
Hi @JaimeValdemoros <https://github.com/jaimevaldemoros>, this is just a
friendly ping to see how you're going with everything 😀 How far through
this issue would you say you are? And is there anything I can do to help?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#532 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AH7W0_BHAkA06LRP6Oqx3GL52QNGy6X9ks5tKcoZgaJpZM4RVrx6>
.
|
|
@Michael-F-Bryan I've made a couple of small changes that felt a bit more sensible:
Is there anything you think is still missing? |
Michael-F-Bryan
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall I'm really happy with this PR, it looks clean and well thought-out and easily testable 👍
I've made a couple comments/questions, but they're mainly to throw around ideas or ask your opinion.
We may also want to add an integration test which makes sure the preprocessors actually get called.
This could be as simple as creating a dummy Preprocessor which contains a Rc<AtomicBool> and will toggle the bool when it gets called. The test then does a build of the dummy book and asserts the bool is now true.
src/book/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reckon we may want to pull this bit out into its own default_preprocessors() function, where we immediately return vec![Box::new(LinkPreprocessor::new())]. I imagine that'll make things easier to update in the future, and it's immediately obvious what the default preprocessors are.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done - you're right, makes it a bit cleaner
src/book/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are your thoughts on turning this if key == "links" {...} else { bail!() } into a match statement? Now that preprocessors are easier to work with, I imagine we'll be adding a bunch more in the future.
src/book/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that we're not mutating the original book here and instead preprocessing its clone 👍
src/book/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doc-comment should probably be reworded in the "imperative" tense to describe what it does. So something like "Register a [Preprocessor] to be used when rendering the book", with the word "Preprocessor" being a link to the relevant trait so people can see the required methods and what types already implement Preprocessor.
src/preprocess/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm tossing up whether to include the Book as part of the PreprocessorContext. Do you think the book to be processed should be part of the context or should we keep it as a second argument?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's helpful to distinguish the fact that you only expect the Book itself to be mutated, and that the PreprocessorContext is additional information it can use to help in that mutation. Having a single parameter &mut PreprocessorContext obscures that slightly and has fewer guarantees about what the Preprocessor is allowed to do to the context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yeah that's a good point. I completely forgot the Book is &mut while we pass an immutable reference for the PreprocessorContext.
src/preprocess/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably better for PreprocessorContext to contain a reference (or clone, if you don't want to deal with lifetimes) to the Config and the book's root. That way a preprocessor can hook into book.toml for configuration, and the src_dir can be discovered by combining config.book.src and the book root.
So something like this:
pub struct PreprocessorContext {
pub config: Config,
pub root: PathBuf,
// maybe also include the `Book` here... I dunno
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense, given the other fields of the MDBook shouldn't be needed by the preprocessor. I've made it a clone for now since a borrow would be problematic here:
since we'd have a reference to an inner field of self in the Context and additionally trying to take a reference to itself to pass into iter.
|
@JaimeValdemoros, I've made a temporary fix (#549) to CI so travis won't fail and erroneously say that this PR is broken. If you want, you can |
535890c to
90fa1b4
Compare
|
Thanks @Michael-F-Bryan - this is the first time I've rebased onto a fork so hopefully I've done it right |
tests/testing.rs
Outdated
| fn mdbook_runs_preprocessors() { | ||
|
|
||
| lazy_static! { | ||
| static ref HAS_RUN: Mutex<bool> = Mutex::new(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to use lazy_static!() here, an Arc<Mutex<bool>> should be enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I was trying to have a dummy option in the Config and have the book add the DummyPreprocessor to the list when it found the dummy option, which did require the lazy_static since the test wasn't constructing it directly. I should've rethought the design when I switched to using with_preprocessor and building the DummyPreprocessor directly.
Looks like everything's okay 👍 |
|
Just to list what I've done since the last checklist:
|
|
I just had another look through the code and I'm happy with it. I think I'll merge this now and then we can do a follow-up PR to document how preprocessors work in the user guide. Awesome work @JaimeValdemoros, I'm really happy with this! |
…eprocessors implementing preprocessors
…ust-lang#564) * Looks like we forgot to recursively apply replace_all() in rust-lang#532 * Removed some print statements * Made sure we ignore the rendered dummy_book
No description provided.