Skip to content

Commit

Permalink
Users can now manually specify whether a preprocessor should run for …
Browse files Browse the repository at this point in the history
…a renderer
  • Loading branch information
Michael-F-Bryan committed Aug 30, 2018
1 parent 995efc2 commit d0a6d7c
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 3 deletions.
79 changes: 76 additions & 3 deletions src/book/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,16 +156,19 @@ impl MDBook {
Ok(())
}

/// Run the entire build process for a particular `Renderer`.
fn execute_build_process(&self, renderer: &Renderer) -> Result<()> {
let mut preprocessed_book = self.book.clone();
let preprocess_ctx = PreprocessorContext::new(self.root.clone(),
self.config.clone(),
renderer.name().to_string());

for preprocessor in &self.preprocessors {
debug!("Running the {} preprocessor.", preprocessor.name());
preprocessed_book =
preprocessor.run(&preprocess_ctx, preprocessed_book)?;
if preprocessor_should_run(&**preprocessor, renderer, &self.config) {
debug!("Running the {} preprocessor.", preprocessor.name());
preprocessed_book =
preprocessor.run(&preprocess_ctx, preprocessed_book)?;
}
}

info!("Running the {} backend", renderer.name());
Expand Down Expand Up @@ -382,6 +385,23 @@ fn interpret_custom_renderer(key: &str, table: &Value) -> Box<Renderer> {
Box::new(CmdRenderer::new(key.to_string(), command.to_string()))
}

/// Check whether we should run a particular `Preprocessor` in combination
/// with the renderer, falling back to `Preprocessor::supports_renderer()`
/// method if the user doesn't say anything.
fn preprocessor_should_run(preprocessor: &Preprocessor, renderer: &Renderer, cfg: &Config) -> bool {
let key = format!("preprocessor.{}.renderers", preprocessor.name());
let renderer_name = renderer.name();

if let Some(Value::Array(ref explicit_renderers)) = cfg.get(&key) {
return explicit_renderers.into_iter()
.filter_map(|val| val.as_str())
.any(|name| name == renderer_name);
}

preprocessor.supports_renderer(renderer_name)
}


#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -484,4 +504,57 @@ mod tests {

assert!(got.is_err());
}

#[test]
fn config_respects_preprocessor_selection() {
let cfg_str: &'static str = r#"
[preprocessor.links]
renderers = ["html"]
"#;

let cfg = Config::from_str(cfg_str).unwrap();

// double-check that we can access preprocessor.links.renderers[0]
let html = cfg.get_preprocessor("links")
.and_then(|links| links.get("renderers"))
.and_then(|renderers| renderers.as_array())
.and_then(|renderers| renderers.get(0))
.and_then(|renderer| renderer.as_str())
.unwrap();
assert_eq!(html, "html");
let html_renderer = HtmlHandlebars::default();
let pre = LinkPreprocessor::new();

let should_run = preprocessor_should_run(&pre, &html_renderer, &cfg);
assert!(should_run);
}

struct BoolPreprocessor(bool);
impl Preprocessor for BoolPreprocessor {
fn name(&self) -> &str {
"bool-preprocessor"
}

fn run(&self, _ctx: &PreprocessorContext, _book: Book) -> Result<Book> {
unimplemented!()
}

fn supports_renderer(&self, _renderer: &str) -> bool {
self.0
}
}

#[test]
fn preprocessor_should_run_falls_back_to_supports_renderer_method() {
let cfg = Config::default();
let html = HtmlHandlebars::new();

let should_be = true;
let got = preprocessor_should_run(&BoolPreprocessor(should_be), &html, &cfg);
assert_eq!(got, should_be);

let should_be = false;
let got = preprocessor_should_run(&BoolPreprocessor(should_be), &html, &cfg);
assert_eq!(got, should_be);
}
}
12 changes: 12 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,18 @@ impl Config {
Ok(())
}

/// Get the table associated with a particular renderer.
pub fn get_renderer<I: AsRef<str>>(&self, index: I) -> Option<&Table> {
let key = format!("output.{}", index.as_ref());
self.get(&key).and_then(|v| v.as_table())
}

/// Get the table associated with a particular preprocessor.
pub fn get_preprocessor<I: AsRef<str>>(&self, index: I) -> Option<&Table> {
let key = format!("preprocessor.{}", index.as_ref());
self.get(&key).and_then(|v| v.as_table())
}

fn from_legacy(mut table: Value) -> Config {
let mut cfg = Config::default();

Expand Down
8 changes: 8 additions & 0 deletions src/preprocess/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,12 @@ pub trait Preprocessor {
/// Run this `Preprocessor`, allowing it to update the book before it is
/// given to a renderer.
fn run(&self, ctx: &PreprocessorContext, book: Book) -> Result<Book>;

/// A hint to `MDBook` whether this preprocessor is compatible with a
/// particular renderer.
///
/// By default, always returns `true`.
fn supports_renderer(&self, _renderer: &str) -> bool {
true
}
}

0 comments on commit d0a6d7c

Please sign in to comment.