///|
/// A compiled template, ready to render any number of times.
pub struct Template {
priv env : Env
priv name : String
priv format : Format
priv nodes : Array[@syntax.Node]
}
///|
/// The name the template was compiled under.
pub fn Template::name(self : Template) -> String {
self.name
}
///|
/// Render with a context of data: a `Json` object, or any value whose
/// `to_json` gives one.
pub fn[C : ToJson] Template::render(
self : Template,
context : C,
) -> String raise @spec.Refused {
match @spec.Value::of_json(Json(context)) {
Dict(fields) => self.render_values(fields)
other =>
raise Invalid(
template=self.name,
line=0,
reason="the context must be a mapping, not \{other.kind()}",
)
}
}
///|
/// Render with values that may hold functions and objects as well as data.
pub fn Template::render_values(
self : Template,
values : Map[String, @spec.Value],
) -> String raise @spec.Refused {
let run = Run::new(self.env, self.name, self.format.autoescape, values.copy())
run.scopes[0]["self"] = Object(Blocks::{ run, })
run.render_chain(self.nodes)
run.out.to_string()
}
///|
/// Compile and render `source` in one call. `format` and `force` override
/// the settings' own; `load`, `translate` and `cache` are the seams
/// `Env::new` takes.
pub fn[C : ToJson] render(
source : StringView,
context : C,
settings~ : Settings = settings,
format? : Format,
force? : Bool,
load? : (String) -> String?,
translate? : (String, String?, Int32?) -> String?,
cache? : (String, () -> String raise @spec.Refused) -> String raise @spec.Refused,
) -> String raise @spec.Refused {
let settings = match force {
Some(f) => { ..settings, force: f, }
None => settings
}
Env::new(settings~, load?, translate?, cache?)
.compile(source, format?)
.render(context)
}