Skip to content

Commit 185fab0

Browse files
committed
disincentivize usage of functions that expose toml::Table in Config
1 parent 23abd20 commit 185fab0

File tree

4 files changed

+61
-15
lines changed

4 files changed

+61
-15
lines changed

examples/nop-preprocessor.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ fn handle_supports(pre: &dyn Preprocessor, sub_args: &ArgMatches) -> ! {
7171
/// in your main `lib.rs` file.
7272
mod nop_lib {
7373
use super::*;
74+
use serde::Deserialize;
7475

7576
/// A no-op preprocessor.
7677
pub struct Nop;
@@ -87,10 +88,20 @@ mod nop_lib {
8788
}
8889

8990
fn run(&self, ctx: &PreprocessorContext, book: Book) -> Result<Book, Error> {
90-
// In testing we want to tell the preprocessor to blow up by setting a
91+
// The config options our preprocessor uses, deserialized from the book.toml that
92+
// mdbook uses
93+
#[derive(Deserialize)]
94+
struct Config {
95+
/// Indicate whether or not the preprocessor should return an error.
96+
#[serde(default)] // tell serde to use std::default::Default (false) as the default
97+
blow_up: bool,
98+
}
99+
100+
// In testing we can tell the preprocessor to blow up by setting a
91101
// particular config value
92-
if let Some(nop_cfg) = ctx.config.get_preprocessor(self.name()) {
93-
if nop_cfg.contains_key("blow-up") {
102+
let nop_cfg: Option<Config> = ctx.config.get_preprocessor_deserialized(self.name())?;
103+
if let Some(nop_cfg) = nop_cfg {
104+
if nop_cfg.blow_up {
94105
anyhow::bail!("Boom!!1!");
95106
}
96107
}

src/book/mod.rs

+24-11
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,11 @@ mod tests {
706706
let cfg = Config::from_str(cfg_str).unwrap();
707707

708708
// make sure the `preprocessor.random` table exists
709-
assert!(cfg.get_preprocessor("random").is_some());
709+
#[derive(serde::Deserialize)]
710+
struct Random {}
711+
let random: Result<Option<Random>> = cfg.get_preprocessor_deserialized("random");
712+
assert!(random.is_ok());
713+
assert!(random.unwrap().is_some());
710714

711715
let got = determine_preprocessors(&cfg).unwrap();
712716

@@ -722,11 +726,17 @@ mod tests {
722726

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

725-
// make sure the `preprocessor.random` table exists
726-
let random = cfg.get_preprocessor("random").unwrap();
727-
let random = get_custom_preprocessor_cmd("random", &Value::Table(random.clone()));
729+
// Deserialize the preproessor.random config section into a struct
730+
#[derive(serde::Deserialize)]
731+
struct Random {
732+
command: String,
733+
}
734+
let random: Random = cfg
735+
.get_preprocessor_deserialized("random")
736+
.unwrap()
737+
.unwrap();
728738

729-
assert_eq!(random, "python random.py");
739+
assert_eq!(random.command, "python random.py");
730740
}
731741

732742
#[test]
@@ -851,13 +861,16 @@ mod tests {
851861
let cfg = Config::from_str(cfg_str).unwrap();
852862

853863
// double-check that we can access preprocessor.links.renderers[0]
864+
#[derive(serde::Deserialize)]
865+
struct Links {
866+
renderers: Vec<String>,
867+
}
854868
let html = cfg
855-
.get_preprocessor("links")
856-
.and_then(|links| links.get("renderers"))
857-
.and_then(Value::as_array)
858-
.and_then(|renderers| renderers.get(0))
859-
.and_then(Value::as_str)
860-
.unwrap();
869+
.get_preprocessor_deserialized::<Links, _>("links")
870+
.unwrap()
871+
.unwrap()
872+
.renderers
873+
.remove(0);
861874
assert_eq!(html, "html");
862875
let html_renderer = HtmlHandlebars;
863876
let pre = LinkPreprocessor::new();

src/config.rs

+22
Original file line numberDiff line numberDiff line change
@@ -240,17 +240,39 @@ impl Config {
240240
}
241241

242242
/// Get the table associated with a particular renderer.
243+
#[deprecated = "prefer get_renderer_deserialized over get_renderer"]
243244
pub fn get_renderer<I: AsRef<str>>(&self, index: I) -> Option<&Table> {
244245
let key = format!("output.{}", index.as_ref());
245246
self.get(&key).and_then(Value::as_table)
246247
}
247248

249+
/// Convenience function to fetch the renderer section from the config and deserialize it
250+
/// into some arbitrary type.
251+
pub fn get_renderer_deserialized<'de, T: Deserialize<'de>, I: AsRef<str>>(
252+
&self,
253+
index: I,
254+
) -> Result<Option<T>> {
255+
let key = format!("output.{}", index.as_ref());
256+
self.get_deserialized_opt(key)
257+
}
258+
248259
/// Get the table associated with a particular preprocessor.
260+
#[deprecated = "prefer get_preprocessor_deserialized over get_preprocessor"]
249261
pub fn get_preprocessor<I: AsRef<str>>(&self, index: I) -> Option<&Table> {
250262
let key = format!("preprocessor.{}", index.as_ref());
251263
self.get(&key).and_then(Value::as_table)
252264
}
253265

266+
/// Convenience function to fetch the preprocessor section from the config and deserialize it
267+
/// into some arbitrary type.
268+
pub fn get_preprocessor_deserialized<'de, T: Deserialize<'de>, I: AsRef<str>>(
269+
&self,
270+
index: I,
271+
) -> Result<Option<T>> {
272+
let key = format!("preprocessor.{}", index.as_ref());
273+
self.get_deserialized_opt(key)
274+
}
275+
254276
fn from_legacy(mut table: Value) -> Config {
255277
let mut cfg = Config::default();
256278

Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[preprocessor.nop-preprocessor]
22
command = "cargo run --quiet --example nop-preprocessor --"
3-
blow-up = true
3+
blow_up = true
44

0 commit comments

Comments
 (0)