mini_template 0.1.1

Small template engine with smarty like syntax
Documentation
use crate::{renderer::RenderContext, variable_container::VariableContainer};

#[cfg(feature = "condition")]
use super::condition::{Condition, ConditionEval};
use super::{Render, Statement};

#[derive(PartialEq, Debug)]
pub struct Loop {
    condition: Condition,
    template: Vec<Statement>,
}

impl Loop {
    pub fn new(condition: Condition, template: Vec<Statement>) -> Self {
        Self {
            condition,
            template,
        }
    }
}

impl Render for Loop {
    fn render<VC: VariableContainer>(
        &self,
        context: &mut RenderContext<VC>,
        buf: &mut String,
    ) -> crate::error::Result<()> {
        while self.condition.eval(context)? {
            self.template.render(context, buf)?
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    use crate::{
        renderer::RenderContext,
        template::{
            condition::Condition, Assign, CalculatedValue, Render, Statement, StorageMethod,
        },
        value::Value,
    };

    use super::Loop;

    #[test]
    fn loop_single_iteration() {
        let l = Loop::new(
            Condition::CalculatedValue(CalculatedValue::new(
                StorageMethod::Variable("var"),
                vec![],
            )),
            vec![
                Statement::Calculated(CalculatedValue::new(StorageMethod::Variable("var"), vec![])),
                Statement::Assign(Assign::new(
                    "var",
                    CalculatedValue::new(
                        StorageMethod::Variable("var"),
                        vec![("sub", vec![StorageMethod::Const(Value::Number(1.))])],
                    ),
                )),
            ],
        );

        let mut modifiers = HashMap::default();
        let sub: &'static crate::modifier::Modifier = &crate::modifier::sub;
        modifiers.insert("sub", sub);
        let mut ctx = RenderContext::new(
            &modifiers,
            HashMap::from_iter([("var".to_owned(), Value::Number(1.))]),
        );
        let mut buffer = String::new();
        assert!(l.render(&mut ctx, &mut buffer).is_ok());
        assert_eq!(buffer.as_str(), "1")
    }

    #[test]
    fn loop_multiple_iterations() {
        let l = Loop::new(
            Condition::CalculatedValue(CalculatedValue::new(
                StorageMethod::Variable("var"),
                vec![],
            )),
            vec![
                Statement::Calculated(CalculatedValue::new(StorageMethod::Variable("var"), vec![])),
                Statement::Assign(Assign::new(
                    "var",
                    CalculatedValue::new(
                        StorageMethod::Variable("var"),
                        vec![("sub", vec![StorageMethod::Const(Value::Number(1.))])],
                    ),
                )),
            ],
        );

        let mut modifiers = HashMap::default();
        let sub: &'static crate::modifier::Modifier = &crate::modifier::sub;
        modifiers.insert("sub", sub);
        let mut ctx = RenderContext::new(
            &modifiers,
            HashMap::from_iter([("var".to_owned(), Value::Number(5.))]),
        );
        let mut buffer = String::new();
        assert!(l.render(&mut ctx, &mut buffer).is_ok());
        assert_eq!(buffer.as_str(), "54321")
    }

    #[test]
    fn loop_no_iterations() {
        let l = Loop::new(
            Condition::CalculatedValue(CalculatedValue::new(
                StorageMethod::Const(Value::Bool(false)),
                vec![],
            )),
            vec![Statement::Literal("TEST")],
        );

        let modifiers = HashMap::new();
        let mut ctx = RenderContext::new(
            &modifiers,
            HashMap::from_iter([("var".to_owned(), Value::Number(5.))]),
        );
        let mut buffer = String::new();
        assert!(l.render(&mut ctx, &mut buffer).is_ok());
        assert!(buffer.is_empty())
    }
}