duster/src/bin.rs
Tom Alexander 273f6204d8
Rendering my first template with actually following paths.
Before I was hard-coding the path to the reference. Now I am following the full path programmatically using the new ContextElement and Walkable traits.
2020-04-11 22:52:20 -04:00

105 lines
3.4 KiB
Rust

extern crate nom;
use renderer::compile_template;
use renderer::CompiledTemplate;
use renderer::ContextElement;
use renderer::DustRenderer;
use renderer::Renderable;
use renderer::Walkable;
use std::env;
use std::fs;
use std::io::{self, Read};
use std::path::Path;
mod parser;
mod renderer;
fn main() {
let context = read_context_from_stdin();
let argv: Vec<String> = env::args().collect();
if argv.len() < 2 {
panic!("Need to pass templates");
}
let template_paths = &argv[1..];
let template_contents: Vec<(String, String)> = template_paths
.iter()
.map(|p| {
let template_content = fs::read_to_string(&p).unwrap();
(p.to_string(), template_content)
})
.collect();
let compiled_templates: Vec<CompiledTemplate> = template_contents
.iter()
.map(|(p, contents)| template_from_file(p, contents))
.collect();
let mut dust_renderer = DustRenderer::new();
compiled_templates.iter().for_each(|template| {
dust_renderer.load_source(template);
});
let main_template_name = &compiled_templates
.first()
.expect("There should be more than 1 template")
.name;
println!(
"{}",
dust_renderer
.render(main_template_name, &context)
.expect("Failed to render")
);
}
fn template_from_file<'a>(file_path: &str, file_contents: &'a str) -> CompiledTemplate<'a> {
let path: &Path = Path::new(file_path);
let name = path.file_stem().unwrap();
compile_template(file_contents, name.to_string_lossy().to_string())
.expect("Failed to compile template")
}
fn read_context_from_stdin() -> serde_json::Value {
let mut buffer = String::new();
io::stdin()
.read_to_string(&mut buffer)
.expect("Failed to read stdin");
let parsed: serde_json::Value = serde_json::from_str(&buffer).expect("Failed to parse json");
match parsed {
serde_json::Value::Object(obj) => serde_json::value::Value::Object(obj),
_ => panic!("Expected context to be an object"),
}
}
impl ContextElement for serde_json::Value {}
impl Renderable for serde_json::Value {
fn render(&self) -> String {
match self {
serde_json::Value::Null => "".to_owned(),
serde_json::Value::Bool(boolean) => boolean.to_string(),
serde_json::Value::Number(num) => num.to_string(),
serde_json::Value::String(string) => string.to_string(),
serde_json::Value::Array(_arr) => panic!("Attempted to render an array"),
serde_json::Value::Object(_obj) => panic!("Attempted to render an object"),
}
}
}
impl Walkable for serde_json::Value {
fn walk(&self, segment: &str) -> &dyn ContextElement {
match self {
serde_json::Value::Null => panic!("Attempted to walk to {} on a null value", segment),
serde_json::Value::Bool(_boolean) => {
panic!("Attempted to walk to {} on a boolean value", segment)
}
serde_json::Value::Number(_num) => {
panic!("Attempted to walk to {} on a number value", segment)
}
serde_json::Value::String(_string) => {
panic!("Attempted to walk to {} on a string value", segment)
}
serde_json::Value::Array(_arr) => todo!("Arrays not supported yet"),
serde_json::Value::Object(obj) => obj.get(segment).unwrap(),
}
}
}