go_template/
template.rs

1use std::collections::HashMap;
2
3use crate::error::{ParseError, TemplateError};
4use crate::funcs::BUILTINS;
5use crate::parse::{parse, Tree};
6
7use gtmpl_value::Func;
8
9/// The main template structure.
10#[derive(Clone)]
11pub struct Template {
12    pub name: String,
13    pub text: String,
14    pub funcs: HashMap<String, Func>,
15    pub tree_set: HashMap<String, Tree>,
16}
17
18impl Default for Template {
19    fn default() -> Template {
20        Template {
21            name: String::default(),
22            text: String::from(""),
23            funcs: BUILTINS.iter().map(|&(k, v)| (k.to_owned(), v)).collect(),
24            tree_set: HashMap::default(),
25        }
26    }
27}
28
29impl Template {
30    /// Creates a new empty template with a given `name`.
31    pub fn with_name<T: Into<String>>(name: T) -> Template {
32        Template {
33            name: name.into(),
34            ..Default::default()
35        }
36    }
37
38    /// Adds a single custom function to the template.
39    ///
40    /// ## Example
41    ///
42    /// ```rust
43    /// use gtmpl::{Context, Func, FuncError, Value};
44    ///
45    /// fn hello_world(_args: &[Value]) -> Result<Value, FuncError> {
46    ///   Ok(Value::from("Hello World!"))
47    /// }
48    ///
49    /// let mut tmpl = gtmpl::Template::default();
50    /// tmpl.add_func("helloWorld", hello_world);
51    /// tmpl.parse("{{ helloWorld }}").unwrap();
52    /// let output = tmpl.render(&Context::empty());
53    /// assert_eq!(&output.unwrap(), "Hello World!");
54    /// ```
55    pub fn add_func(&mut self, name: &str, func: Func) {
56        self.funcs.insert(name.to_owned(), func);
57    }
58
59    /// Adds custom functions to the template.
60    ///
61    /// ## Example
62    ///
63    /// ```rust
64    /// use std::collections::HashMap;
65    ///
66    /// use gtmpl::{Context, Func, FuncError, Value};
67    ///
68    /// fn hello_world(_args: &[Value]) -> Result<Value, FuncError> {
69    ///   Ok(Value::from("Hello World!"))
70    /// }
71    ///
72    /// let funcs = vec![("helloWorld", hello_world as Func)];
73    /// let mut tmpl = gtmpl::Template::default();
74    /// tmpl.add_funcs(&funcs);
75    /// tmpl.parse("{{ helloWorld }}").unwrap();
76    /// let output = tmpl.render(&Context::empty());
77    /// assert_eq!(&output.unwrap(), "Hello World!");
78    /// ```
79    pub fn add_funcs<T: Into<String> + Clone>(&mut self, funcs: &[(T, Func)]) {
80        self.funcs
81            .extend(funcs.iter().cloned().map(|(k, v)| (k.into(), v)));
82    }
83
84    /// Parse the given `text` as template body.
85    ///
86    /// ## Example
87    ///
88    /// ```rust
89    /// let mut tmpl = gtmpl::Template::default();
90    /// tmpl.parse("Hello World!").unwrap();
91    /// ```
92    pub fn parse<T: Into<String>>(&mut self, text: T) -> Result<(), ParseError> {
93        let tree_set = parse(
94            self.name.clone(),
95            text.into(),
96            self.funcs.keys().cloned().collect(),
97        )?;
98        self.tree_set.extend(tree_set);
99        Ok(())
100    }
101
102    /// Add the given `text` as a template with a `name`.
103    ///
104    /// ## Example
105    ///
106    /// ```rust
107    /// use gtmpl::Context;
108    ///
109    /// let mut tmpl = gtmpl::Template::default();
110    /// tmpl.add_template("fancy", "{{ . }}");
111    /// tmpl.parse(r#"{{ template "fancy" . }}!"#).unwrap();
112    /// let output = tmpl.render(&Context::from("Hello World"));
113    /// assert_eq!(&output.unwrap(), "Hello World!");
114    /// ```
115    pub fn add_template<N: Into<String>, T: Into<String>>(
116        &mut self,
117        name: N,
118        text: T,
119    ) -> Result<(), TemplateError> {
120        let tree_set = parse(
121            name.into(),
122            text.into(),
123            self.funcs.keys().cloned().collect(),
124        )?;
125        self.tree_set.extend(tree_set);
126        Ok(())
127    }
128}
129
130#[cfg(test)]
131mod tests_mocked {
132    use super::*;
133
134    #[test]
135    fn test_parse() {
136        let mut t = Template::with_name("foo");
137        assert!(t.parse(r#"{{ if eq "bar" "bar" }} 2000 {{ end }}"#).is_ok());
138        assert!(t.tree_set.contains_key("foo"));
139    }
140}