1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#![crate_name = "liquid"]
#![doc(html_root_url = "https://cobalt-org.github.io/liquid-rust/")]

extern crate regex;

use std::collections::HashMap;
use template::Template;
use lexer::Token;
use lexer::Element;
use tags::{IfBlock, ForBlock, RawBlock, CommentBlock};
use std::string::ToString;
use std::default::Default;
pub use value::Value;
pub use context::Context;

mod template;
mod output;
mod text;
pub mod lexer;
mod parser;
mod tags;
mod filters;
mod value;
mod variable;
mod context;

/// The ErrorMode to use.
/// This currently does not have an effect, until
/// ErrorModes are properly implemented.
#[derive(Clone, Copy)]
pub enum ErrorMode{
    Strict,
    Warn,
    Lax
}

impl Default for ErrorMode {
   fn default() -> ErrorMode { ErrorMode::Warn }
}

/// A trait for creating custom tags.
pub trait Tag {
    fn initialize(&self, tag_name: &str, arguments: &[Token], options : &LiquidOptions) -> Box<Renderable>;
}

/// The trait to use when implementing custom block-size tags ({% if something %})
pub trait Block {
    fn initialize<'a>(&'a self, tag_name: &str, arguments: &[Token], tokens: Vec<Element>, options : &'a LiquidOptions<'a>) -> Result<Box<Renderable +'a>, String>;
}

/// Any object (tag/block) that can be rendered by liquid must implement this trait.
pub trait Renderable{
    fn render(&self, context: &mut Context) -> Option<String>;
}

#[derive(Default)]
pub struct LiquidOptions<'a> {
    pub blocks : HashMap<String, Box<Block + 'a>>,
    pub tags : HashMap<String, Box<Tag + 'a>>,
    pub error_mode : ErrorMode
}

/// Parses a liquid template, returning a Template object.
/// # Examples
///
/// ## Minimal Template
///
/// ```
/// use std::default::Default;
/// use liquid::Renderable;
/// use liquid::LiquidOptions;
/// use liquid::Context;
/// let mut options : LiquidOptions = Default::default();
/// let template = liquid::parse("Liquid!", &mut options).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), "Liquid!".to_string());
/// ```
///
pub fn parse<'a, 'b> (text: &str, options: &'b mut LiquidOptions<'a>) -> Result<Template<'b>, String>{
    let tokens = lexer::tokenize(&text);
    options.blocks.insert("raw".to_string(), Box::new(RawBlock) as Box<Block>);
    options.blocks.insert("if".to_string(), Box::new(IfBlock) as Box<Block>);
    options.blocks.insert("for".to_string(), Box::new(ForBlock) as Box<Block>);
    options.blocks.insert("comment".to_string(), Box::new(CommentBlock) as Box<Block>);
    match parser::parse(&tokens, options) {
        Ok(renderables) => Ok(Template::new(renderables)),
        Err(e) => Err(e)
    }
}