+impl ParsedTemplate {
+ pub fn render(&self, context: &TemplateContext) -> Result<String> {
+ ParsedTemplate::render_tokens(&self.tokens, context)
+ }
+
+ pub fn render_tokens(tokens: &Vec<Token>, context: &TemplateContext) -> Result<String> {
+ let mut rendered_template: String = String::new();
+ for token in tokens {
+ match token {
+ Token::Text(contents) => rendered_template.push_str(&contents),
+ Token::DisplayDirective { content } => {
+ let value = TemplateContextGetter::get(context, &content)
+ .ok_or_else(|| Error::new(Other, format!("{} is not a valid key", content)))?;
+ rendered_template.push_str(&value.render());
+ },
+ Token::ConditionalDirective { condition, children} => {
+ let mut negator = false;
+ let mut condition = condition.to_string();
+ if condition.starts_with('!') {
+ negator = true;
+ condition = condition[1..].to_string();
+ }
+
+ let value = TemplateContextGetter::get(context, &condition)
+ .ok_or_else(|| Error::new(Other, format!("{} is not a valid key", condition)))?;
+
+ match value {
+ TemplateValue::Bool(value) => {
+ if negator ^ value {
+ rendered_template.push_str(&ParsedTemplate::render_tokens(children, context)?)
+ }
+ Ok(())
+ },
+ _ => Err(Error::new(Other, format!("{} is not a boolean value", condition))),
+ }?;
+ },
+ Token::IteratorDirective { collection, member_label, children } => {
+ let value = TemplateContextGetter::get(context, &collection)
+ .ok_or_else(|| Error::new(Other, format!("{} is not a valid key", collection)))?;
+
+ match value {
+ TemplateValue::Collection(collection) => {
+ for member in collection {
+ let mut child_context = context.clone();
+ child_context.insert(
+ member_label.to_string(),
+ TemplateValue::Context(member)
+ );
+ rendered_template.push_str(&ParsedTemplate::render_tokens(&children, &child_context)?)
+ }
+ Ok(())
+ },
+ _ => Err(Error::new(Other, format!("{} is not a collection", collection))),
+ }?;
+ }
+ }
+ }
+ Ok(rendered_template)
+ }
+}
+
+pub fn parse(template: &str) -> Option<ParsedTemplate> {