use {Context, Contexts, Function, Functions, utils};
use {Value, to_value};
use serde::Serialize;
use std::path::{Path, PathBuf};
use error::Error;
use tree::Tree;
use Compiled;
use ExpressionError;
#[derive(Default)]
pub struct Template {
template: Option<String>,
root: Option<PathBuf>,
extension: Option<String>,
context: Option<Context>,
compiled: Option<Compiled>,
contexts: Contexts,
functions: Functions,
}
impl Template {
pub fn new() -> Template {
Template { contexts: create_empty_contexts(), ..Default::default() }
}
pub fn template<T: Into<String>>(mut self, template: T) -> Template {
self.template = Some(template.into());
self
}
pub fn open<P: AsRef<Path>>(mut self, path: P) -> Result<Template, Error> {
self.template = Some(utils::read(self.resolve_view_path(path.as_ref()))?);
Ok(self)
}
pub fn context(mut self, context: Context) -> Template {
self.context = Some(context);
self
}
pub fn root<P: Into<PathBuf>>(mut self, root: P) -> Template {
self.root = Some(root.into());
self
}
pub fn extension<T: Into<String>>(mut self, extension: T) -> Template {
self.extension = Some(extension.into());
self
}
pub fn value<T, V>(mut self, name: T, value: V) -> Template
where T: Into<String>,
V: Serialize
{
self.contexts.first_mut().unwrap().insert(name.into(), to_value(&value));
self
}
pub fn function<T, F>(mut self, name: T, function: F) -> Template
where T: Into<String>,
F: 'static + Fn(Vec<Value>) -> Result<Value, ExpressionError> + Sync + Send
{
self.functions.insert(name.into(), Function::new(function));
self
}
pub fn compile(mut self) -> Result<Template, Error> {
self.compiled = Some(Tree::new(self.template.clone().unwrap(),
self.root.clone(),
self.extension.clone()).compile()?);
Ok(self)
}
pub fn render(&self) -> Result<String, Error> {
let mut contexts = self.contexts.clone();
if self.context.is_some() {
contexts.push(self.context.clone().unwrap());
}
if self.compiled.is_none() {
Tree::new(self.template.clone().unwrap(),
self.root.clone(),
self.extension.clone()).compile()?(contexts, &self.functions)
} else {
(self.compiled.as_ref().unwrap())(contexts, &self.functions)
}
}
fn resolve_view_path(&self, view: &Path) -> PathBuf {
let mut absolute_path = if self.root.is_some() {
utils::resolve(self.root.as_ref().unwrap(), view)
} else {
PathBuf::from(view)
};
if self.extension.is_some() {
absolute_path.set_extension(self.extension.as_ref().unwrap());
}
absolute_path
}
fn get_compiled(&self) -> Option<&Compiled> {
self.compiled.as_ref()
}
}
pub struct RenderOptions<'a> {
template: &'a Template,
context: Option<Context>,
functions: Option<&'a Functions>,
}
impl<'a> RenderOptions<'a> {
pub fn new(template: &'a Template) -> RenderOptions<'a> {
RenderOptions {
template: template,
context: None,
functions: None,
}
}
pub fn context(&mut self, context: Context) -> &mut RenderOptions<'a> {
self.context = Some(context);
self
}
pub fn functions(&mut self, functions: &'a Functions) -> &mut RenderOptions<'a> {
self.functions = Some(functions);
self
}
pub fn render(&mut self) -> Result<String, Error> {
let contexts = if self.context.is_some() {
vec![self.context.take().unwrap()]
} else {
create_empty_contexts()
};
let empty_functions = Functions::new();
let functions = if self.functions.is_some() {
self.functions.unwrap()
} else {
&empty_functions
};
self.template.get_compiled().unwrap()(contexts, functions)
}
}
fn create_empty_contexts() -> Contexts {
let mut contexts = Contexts::new();
contexts.push(Context::new());
contexts
}