use anyhow::{anyhow, Result};
use std::collections::HashMap;
pub fn render(template: &str, vars: &HashMap<String, String>) -> Result<String> {
let mut out = String::with_capacity(template.len());
let mut rest = template;
while let Some(start) = rest.find("{{") {
out.push_str(&rest[..start]);
let after_open = &rest[start + 2..];
let end = after_open
.find("}}")
.ok_or_else(|| anyhow!("Unclosed placeholder in template"))?;
let key = after_open[..end].trim();
let value = vars
.get(key)
.ok_or_else(|| anyhow!("Unknown template variable: {}", key))?;
out.push_str(value);
rest = &after_open[end + 2..];
}
out.push_str(rest);
Ok(out)
}
#[cfg(test)]
mod tests {
use super::*;
fn vars(pairs: &[(&str, &str)]) -> HashMap<String, String> {
pairs
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect()
}
#[test]
fn renders_simple() {
let v = vars(&[("name", "alice")]);
assert_eq!(render("hello {{ name }}", &v).unwrap(), "hello alice");
}
#[test]
fn renders_no_whitespace() {
let v = vars(&[("name", "bob")]);
assert_eq!(render("hi {{name}}!", &v).unwrap(), "hi bob!");
}
#[test]
fn fails_on_unknown_var() {
let v = vars(&[]);
assert!(render("{{ missing }}", &v).is_err());
}
}