use serde::Serialize;
use tera::Context;
pub struct ContextBuilder {
context: Context,
}
impl ContextBuilder {
pub fn new() -> Self {
Self {
context: Context::new(),
}
}
pub fn insert<T: Serialize + ?Sized>(mut self, key: impl Into<String>, value: &T) -> Self {
self.context.insert(key.into(), value);
self
}
pub fn insert_if<T: Serialize + ?Sized, F>(
self,
key: impl Into<String>,
value: &T,
condition: F,
) -> Self
where
F: FnOnce(&T) -> bool,
{
if condition(value) {
self.insert(key, value)
} else {
self
}
}
pub fn insert_some<T: Serialize + ?Sized>(
self,
key: impl Into<String>,
value: Option<&T>,
) -> Self {
if let Some(v) = value {
self.insert(key, v)
} else {
self
}
}
pub fn extend<T: Serialize>(mut self, value: &T) -> Result<Self, tera::Error> {
let additional = Context::from_serialize(value)?;
self.context.extend(additional);
Ok(self)
}
pub fn build(self) -> Context {
self.context
}
}
impl Default for ContextBuilder {
fn default() -> Self {
Self::new()
}
}
impl From<ContextBuilder> for Context {
fn from(builder: ContextBuilder) -> Self {
builder.build()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_context_builder() {
let context = ContextBuilder::new()
.insert("name", &"Alice")
.insert("age", &30)
.build();
assert!(context.contains_key("name"));
assert!(context.contains_key("age"));
}
#[test]
fn test_insert_if() {
let show = true;
let context = ContextBuilder::new()
.insert_if("visible", &"yes", |_| show)
.insert_if("hidden", &"no", |_| !show)
.build();
assert!(context.contains_key("visible"));
assert!(!context.contains_key("hidden"));
}
#[test]
fn test_insert_some() {
let name: Option<&str> = Some("Alice");
let missing: Option<&str> = None;
let context = ContextBuilder::new()
.insert_some("name", name)
.insert_some("missing", missing)
.build();
assert!(context.contains_key("name"));
assert!(!context.contains_key("missing"));
}
}