use super::{Template, iter::Iter};
use crate::{
error::{Error, ErrorKind},
handlebars_registry,
prelude::*,
properties::Properties,
};
use handlebars::Handlebars;
use std::io;
macro_rules! template {
($path:expr) => {
($path, include_str!(concat!("../../template/", $path)))
};
}
const DEFAULT_TEMPLATE_FILES: &[(&str, &str)] = &[
template!(".gitignore.hbs"),
template!("Cargo.toml.hbs"),
template!("README.md.hbs"),
template!("src/application.rs.hbs"),
template!("src/bin/app/main.rs.hbs"),
template!("src/commands.rs.hbs"),
template!("src/commands/start.rs.hbs"),
template!("src/config.rs.hbs"),
template!("src/error.rs.hbs"),
template!("src/lib.rs.hbs"),
template!("src/prelude.rs.hbs"),
template!("tests/acceptance.rs.hbs"),
];
#[derive(Debug)]
pub struct Collection<'a>(Handlebars<'a>);
impl Default for Collection<'_> {
fn default() -> Collection<'static> {
Collection::new(
DEFAULT_TEMPLATE_FILES
.iter()
.map(|(name, contents)| (*name, *contents)),
)
.unwrap()
}
}
impl Collection<'_> {
pub fn new<'a, I>(template_files: I) -> Result<Collection<'static>, Error>
where
I: Iterator<Item = (&'a str, &'a str)>,
{
let mut hbs = handlebars_registry!();
for (name, contents) in template_files {
debug!("registering template: {}", name);
hbs.register_template_string(name, contents).map_err(|e| {
format_err!(
ErrorKind::Template,
"couldn't register template '{}': {}",
name,
e
)
})?;
}
Ok(Collection(hbs))
}
pub fn iter(&self) -> Iter<'_> {
Iter::new(
self.0
.get_templates()
.iter()
.map(|(path, template)| Template::new(path.as_ref(), template))
.collect(),
)
}
pub fn render<W>(
&self,
template: &Template<'_>,
properties: &Properties,
output: W,
) -> Result<(), Error>
where
W: io::Write,
{
let ctx = handlebars::Context::wraps(properties)?;
let mut render_context = handlebars::RenderContext::new(template.inner.name.as_ref());
let mut output = Output::new(output);
use handlebars::Renderable;
template
.inner
.render(&self.0, &ctx, &mut render_context, &mut output)
.map_err(|e| format_err!(ErrorKind::Template, "render error: {}", e).into())
}
}
struct Output<W: io::Write>(W);
impl<W: io::Write> Output<W> {
pub fn new(writeable: W) -> Output<W> {
Output(writeable)
}
}
impl<W: io::Write> handlebars::Output for Output<W> {
fn write(&mut self, seg: &str) -> Result<(), io::Error> {
self.0.write_all(seg.as_bytes())
}
}