use std::collections::HashMap;
use std::path::Path;
use crate::error::{Result, TronError};
use crate::template::TronTemplate;
use crate::template_ref::TronRef;
#[derive(Debug, Default)]
pub struct TronTemplateBuilder {
content: Option<String>,
file_path: Option<String>,
placeholder_values: HashMap<String, String>,
}
impl TronTemplateBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn content<S: Into<String>>(mut self, content: S) -> Self {
self.content = Some(content.into());
self
}
pub fn from_file<P: AsRef<Path>>(mut self, path: P) -> Self {
self.file_path = Some(path.as_ref().to_string_lossy().to_string());
self
}
pub fn set<K, V>(mut self, placeholder: K, value: V) -> Self
where
K: Into<String>,
V: Into<String>,
{
self.placeholder_values.insert(placeholder.into(), value.into());
self
}
pub fn set_many<K, V, I>(mut self, values: I) -> Self
where
K: Into<String>,
V: Into<String>,
I: IntoIterator<Item = (K, V)>,
{
for (key, value) in values {
self.placeholder_values.insert(key.into(), value.into());
}
self
}
pub fn build(self) -> Result<TronTemplate> {
let mut template = match (self.content, self.file_path) {
(Some(content), None) => TronTemplate::new(&content)?,
(None, Some(file_path)) => TronTemplate::from_file(&file_path)?,
(Some(content), Some(_)) => {
TronTemplate::new(&content)?
},
(None, None) => {
return Err(TronError::InvalidSyntax(
"Must provide either content or file path".to_string()
));
}
};
for (key, value) in self.placeholder_values {
template.set(&key, &value)?;
}
Ok(template)
}
}
#[derive(Debug, Default)]
pub struct TronRefBuilder {
template_builder: TronTemplateBuilder,
dependencies: Vec<String>,
}
impl TronRefBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn content<S: Into<String>>(mut self, content: S) -> Self {
self.template_builder = self.template_builder.content(content);
self
}
pub fn from_file<P: AsRef<Path>>(mut self, path: P) -> Self {
self.template_builder = self.template_builder.from_file(path);
self
}
pub fn set<K, V>(mut self, placeholder: K, value: V) -> Self
where
K: Into<String>,
V: Into<String>,
{
self.template_builder = self.template_builder.set(placeholder, value);
self
}
pub fn set_many<K, V, I>(mut self, values: I) -> Self
where
K: Into<String>,
V: Into<String>,
I: IntoIterator<Item = (K, V)>,
{
self.template_builder = self.template_builder.set_many(values);
self
}
pub fn dependency<S: Into<String>>(mut self, dependency: S) -> Self {
self.dependencies.push(dependency.into());
self
}
pub fn dependencies<I, S>(mut self, dependencies: I) -> Self
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
for dep in dependencies {
self.dependencies.push(dep.as_ref().to_string());
}
self
}
pub fn build(self) -> Result<TronRef> {
let template = self.template_builder.build()?;
let mut template_ref = TronRef::new(template);
for dependency in self.dependencies {
template_ref.add_dependency(&dependency);
}
Ok(template_ref)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_template_builder_basic() -> Result<()> {
let template = TronTemplateBuilder::new()
.content("Hello @[name]@!")
.set("name", "World")
.build()?;
assert_eq!(template.render()?, "Hello World!");
Ok(())
}
#[test]
fn test_template_builder_multiple_placeholders() -> Result<()> {
let template = TronTemplateBuilder::new()
.content("@[greeting]@ @[name]@!")
.set("greeting", "Hello")
.set("name", "World")
.build()?;
assert_eq!(template.render()?, "Hello World!");
Ok(())
}
#[test]
fn test_template_builder_set_many() -> Result<()> {
let mut values = HashMap::new();
values.insert("greeting", "Hello");
values.insert("name", "World");
let template = TronTemplateBuilder::new()
.content("@[greeting]@ @[name]@!")
.set_many(values)
.build()?;
assert_eq!(template.render()?, "Hello World!");
Ok(())
}
#[test]
fn test_template_builder_no_content_error() {
let result = TronTemplateBuilder::new().build();
assert!(matches!(result, Err(TronError::InvalidSyntax(_))));
}
#[test]
fn test_template_builder_invalid_placeholder() {
let result = TronTemplateBuilder::new()
.content("Hello @[name]@!")
.set("nonexistent", "value")
.build();
assert!(matches!(result, Err(TronError::MissingPlaceholder(_))));
}
#[test]
fn test_template_ref_builder_basic() -> Result<()> {
let template_ref = TronRefBuilder::new()
.content("Hello @[name]@!")
.set("name", "World")
.build()?;
assert_eq!(template_ref.render()?, "Hello World!");
Ok(())
}
#[test]
fn test_template_ref_builder_with_dependencies() -> Result<()> {
let template_ref = TronRefBuilder::new()
.content("fn main() {}")
.dependency("serde = \"1.0\"")
.dependency("tokio = \"1.0\"")
.build()?;
assert_eq!(template_ref.dependencies().len(), 2);
assert!(template_ref.dependencies().contains(&"serde = \"1.0\"".to_string()));
assert!(template_ref.dependencies().contains(&"tokio = \"1.0\"".to_string()));
Ok(())
}
#[test]
fn test_template_ref_builder_dependencies_method() -> Result<()> {
let template_ref = TronRefBuilder::new()
.content("fn main() {}")
.dependencies(&["serde = \"1.0\"", "tokio = \"1.0\""])
.build()?;
assert_eq!(template_ref.dependencies().len(), 2);
Ok(())
}
#[test]
fn test_template_ref_builder_complex() -> Result<()> {
let mut values = HashMap::new();
values.insert("name", "greet");
values.insert("body", "println!(\"Hello!\");");
let template_ref = TronRefBuilder::new()
.content("fn @[name]@() {\n @[body]@\n}")
.dependencies(&["serde = \"1.0\"", "tokio = \"1.0\""])
.set_many(values)
.build()?;
let result = template_ref.render()?;
assert!(result.contains("fn greet()"));
assert!(result.contains("println!(\"Hello!\");"));
assert_eq!(template_ref.dependencies().len(), 2);
Ok(())
}
}