llm_config_templates/
engine.rs

1//! Template engine for managing and rendering templates
2
3use crate::{parser, Result, Template, TemplateError};
4use std::collections::HashMap;
5
6/// Template engine for rendering templates
7pub struct TemplateEngine {
8    templates: HashMap<String, Template>,
9}
10
11impl TemplateEngine {
12    /// Create a new template engine
13    pub fn new() -> Self {
14        Self {
15            templates: HashMap::new(),
16        }
17    }
18
19    /// Register a template
20    pub fn register(&mut self, template: Template) {
21        self.templates.insert(template.name.clone(), template);
22    }
23
24    /// Get a template by name
25    pub fn get(&self, name: &str) -> Option<&Template> {
26        self.templates.get(name)
27    }
28
29    /// Remove a template
30    pub fn remove(&mut self, name: &str) -> Option<Template> {
31        self.templates.remove(name)
32    }
33
34    /// Render a template by name
35    pub fn render_template(
36        &self,
37        name: &str,
38        vars: &HashMap<String, String>,
39    ) -> Result<String> {
40        let template = self
41            .templates
42            .get(name)
43            .ok_or_else(|| TemplateError::InvalidTemplate(format!("Template not found: {}", name)))?;
44
45        template.render(vars)
46    }
47
48    /// Render a template string directly (without registration)
49    pub fn render(&self, template_str: &str, vars: &HashMap<String, String>) -> Result<String> {
50        let tokens = parser::parse(template_str)?;
51        let mut result = String::new();
52
53        for token in tokens {
54            match token {
55                parser::Token::Literal(text) => result.push_str(&text),
56                parser::Token::Variable(var_name) => {
57                    let value = vars
58                        .get(&var_name)
59                        .ok_or_else(|| TemplateError::VariableNotFound(var_name))?;
60                    result.push_str(value);
61                }
62            }
63        }
64
65        Ok(result)
66    }
67
68    /// List all registered templates
69    pub fn list_templates(&self) -> Vec<&str> {
70        self.templates.keys().map(|s| s.as_str()).collect()
71    }
72
73    /// Get the number of registered templates
74    pub fn count(&self) -> usize {
75        self.templates.len()
76    }
77}
78
79impl Default for TemplateEngine {
80    fn default() -> Self {
81        Self::new()
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88
89    #[test]
90    fn test_engine_creation() {
91        let engine = TemplateEngine::new();
92        assert_eq!(engine.count(), 0);
93    }
94
95    #[test]
96    fn test_register_template() {
97        let mut engine = TemplateEngine::new();
98        let template = Template::new("test", "Hello, {{name}}!").unwrap();
99
100        engine.register(template);
101        assert_eq!(engine.count(), 1);
102    }
103
104    #[test]
105    fn test_get_template() {
106        let mut engine = TemplateEngine::new();
107        let template = Template::new("test", "Hello, {{name}}!").unwrap();
108
109        engine.register(template);
110
111        let retrieved = engine.get("test");
112        assert!(retrieved.is_some());
113        assert_eq!(retrieved.unwrap().name, "test");
114    }
115
116    #[test]
117    fn test_remove_template() {
118        let mut engine = TemplateEngine::new();
119        let template = Template::new("test", "Hello, {{name}}!").unwrap();
120
121        engine.register(template);
122        assert_eq!(engine.count(), 1);
123
124        let removed = engine.remove("test");
125        assert!(removed.is_some());
126        assert_eq!(engine.count(), 0);
127    }
128
129    #[test]
130    fn test_render_template() {
131        let mut engine = TemplateEngine::new();
132        let template = Template::new("greeting", "Hello, {{name}}!").unwrap();
133        engine.register(template);
134
135        let mut vars = HashMap::new();
136        vars.insert("name".to_string(), "Alice".to_string());
137
138        let result = engine.render_template("greeting", &vars).unwrap();
139        assert_eq!(result, "Hello, Alice!");
140    }
141
142    #[test]
143    fn test_render_direct() {
144        let engine = TemplateEngine::new();
145
146        let mut vars = HashMap::new();
147        vars.insert("name".to_string(), "Bob".to_string());
148        vars.insert("age".to_string(), "30".to_string());
149
150        let result = engine
151            .render("Name: {{name}}, Age: {{age}}", &vars)
152            .unwrap();
153        assert_eq!(result, "Name: Bob, Age: 30");
154    }
155
156    #[test]
157    fn test_list_templates() {
158        let mut engine = TemplateEngine::new();
159        engine.register(Template::new("t1", "{{var1}}").unwrap());
160        engine.register(Template::new("t2", "{{var2}}").unwrap());
161        engine.register(Template::new("t3", "{{var3}}").unwrap());
162
163        let templates = engine.list_templates();
164        assert_eq!(templates.len(), 3);
165        assert!(templates.contains(&"t1"));
166        assert!(templates.contains(&"t2"));
167        assert!(templates.contains(&"t3"));
168    }
169
170    #[test]
171    fn test_template_not_found() {
172        let engine = TemplateEngine::new();
173        let vars = HashMap::new();
174
175        let result = engine.render_template("nonexistent", &vars);
176        assert!(result.is_err());
177    }
178
179    #[test]
180    fn test_variable_not_found() {
181        let engine = TemplateEngine::new();
182        let vars = HashMap::new();
183
184        let result = engine.render("Hello, {{name}}!", &vars);
185        assert!(result.is_err());
186    }
187}