handlematters 0.2.1

Self-contained template system with Handlebars and inline shell scripts
Documentation
#![feature(exit_status_error)]

mod evaluate_context;
mod extract_blocks;

use std::io::{self, BufWriter, Read};

use anyhow::{Context as _, Result};
use handlebars::{Handlebars, Template};
use indoc::{formatdoc, indoc};
use serde_yaml::Value;

use evaluate_context::evaluate_context;
use extract_blocks::extract_blocks;

pub fn run<T: Read>(reader: &mut T) -> Result<()> {
    let registry = extract_blocks(reader)?;

    let ctx = parse_context(registry.context())?;
    let ctx = evaluate_context(ctx)?;

    let mut hbs = Handlebars::new();
    let tpl = parse_template(registry.template())?;

    hbs.register_template("main", tpl);

    let stdout = BufWriter::new(io::stdout());

    hbs.render_to_write("main", &ctx, stdout)?;

    Ok(())
}

fn parse_context(src: Option<&String>) -> Result<Value> {
    if let Some(src) = src {
        serde_yaml::from_str(src).with_context(|| {
            formatdoc! {"
                error while parsing context as YAML

                --- context ---
                {}", chomp(src)
            }
        })
    } else {
        Ok(Value::Null)
    }
}

fn parse_template(src: Option<&String>) -> Result<Template> {
    let src = src.with_context(|| {
        indoc! {"
            no template block found

            Example:

                --- context ---
                to: echo world

                --- template ---
                hello, {{to}}"
        }
    })?;

    Ok(Template::compile(src)?)
}

fn chomp(s: &str) -> &str {
    s.strip_suffix('\n').unwrap_or(s)
}