Rendering spans

This commit is contained in:
Tom Alexander 2020-04-11 18:25:48 -04:00
parent 13934e8699
commit 2459d7b418
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
6 changed files with 114 additions and 21 deletions

View File

@ -30,16 +30,27 @@ fn main() {
.iter() .iter()
.map(|(p, contents)| template_from_file(p, contents)) .map(|(p, contents)| template_from_file(p, contents))
.collect(); .collect();
let mut dust_context = DustRenderer::new(); let mut dust_renderer = DustRenderer::new();
compiled_templates.iter().for_each(|template| { compiled_templates.iter().for_each(|template| {
dust_context.load_source(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> { fn template_from_file<'a>(file_path: &str, file_contents: &'a str) -> CompiledTemplate<'a> {
let path: &Path = Path::new(file_path); let path: &Path = Path::new(file_path);
let name = path.file_stem().unwrap(); let name = path.file_stem().unwrap();
compile_template(file_contents, name.to_string_lossy().to_string()) compile_template(file_contents, name.to_string_lossy().to_string())
.expect("Failed to compile template")
} }
fn read_context_from_stdin() -> serde_json::map::Map<String, serde_json::Value> { fn read_context_from_stdin() -> serde_json::map::Map<String, serde_json::Value> {

View File

@ -8,3 +8,4 @@ pub use node_invoker::NodeError;
pub use node_invoker::Result; pub use node_invoker::Result;
pub use parser::template; pub use parser::template;
pub use parser::Template; pub use parser::Template;
pub use parser::TemplateElement;

View File

@ -24,7 +24,7 @@ use nom::sequence::tuple;
use nom::IResult; use nom::IResult;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
enum DustTag<'a> { pub enum DustTag<'a> {
DTSpecial(Special), DTSpecial(Special),
DTComment(Comment<'a>), DTComment(Comment<'a>),
DTReference(Reference<'a>), DTReference(Reference<'a>),
@ -79,8 +79,8 @@ enum Filter {
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
struct Span<'a> { pub struct Span<'a> {
contents: &'a str, pub contents: &'a str,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -123,17 +123,17 @@ struct KVPair<'a> {
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
struct Body<'a> { pub struct Body<'a> {
elements: Vec<TemplateElement<'a>>, pub elements: Vec<TemplateElement<'a>>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Template<'a> { pub struct Template<'a> {
contents: Body<'a>, pub contents: Body<'a>,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
enum TemplateElement<'a> { pub enum TemplateElement<'a> {
TESpan(Span<'a>), TESpan(Span<'a>),
TETag(DustTag<'a>), TETag(DustTag<'a>),
} }

48
src/renderer/errors.rs Normal file
View File

@ -0,0 +1,48 @@
use std::error;
use std::fmt;
#[derive(Clone)]
pub struct RenderError {
pub message: String,
}
#[derive(Clone)]
pub struct CompileError {
pub message: String,
}
impl fmt::Display for RenderError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error rendering: {}", self.message)
}
}
impl fmt::Debug for RenderError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error rendering: {}", self.message)
}
}
impl error::Error for RenderError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}
}
impl fmt::Display for CompileError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error rendering: {}", self.message)
}
}
impl fmt::Debug for CompileError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error rendering: {}", self.message)
}
}
impl error::Error for CompileError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}
}

View File

@ -1,5 +1,6 @@
//! This module contains a renderer for a rust implementation of LinkedIn Dust //! This module contains a renderer for a rust implementation of LinkedIn Dust
mod errors;
mod renderer; mod renderer;
pub use renderer::compile_template; pub use renderer::compile_template;

View File

@ -1,41 +1,73 @@
use crate::parser::template; use crate::parser::template;
use crate::parser::Template; use crate::parser::Template;
use nom::IResult; use crate::parser::TemplateElement;
use std::collections::BTreeMap; use crate::renderer::errors::CompileError;
use crate::renderer::errors::RenderError;
use std::collections::HashMap;
use std::ops::Index;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct CompiledTemplate<'a> { pub struct CompiledTemplate<'a> {
template: Template<'a>, template: Template<'a>,
name: String, pub name: String,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct DustRenderer<'a> { pub struct DustRenderer<'a> {
templates: BTreeMap<&'a String, &'a Template<'a>>, templates: HashMap<String, &'a Template<'a>>,
} }
pub fn compile_template<'a>(source: &'a str, name: String) -> CompiledTemplate<'a> { pub fn compile_template<'a>(
// TODO: Make this function return a result with a custom error type. Break the nom IResult chain source: &'a str,
name: String,
) -> Result<CompiledTemplate<'a>, CompileError> {
// TODO: Make this all consuming // TODO: Make this all consuming
// TODO: This could use better error management
let (_remaining, parsed_template) = template(source).expect("Failed to compile template"); let (_remaining, parsed_template) = template(source).expect("Failed to compile template");
CompiledTemplate { Ok(CompiledTemplate {
template: parsed_template, template: parsed_template,
name: name, name: name,
} })
} }
impl<'a> DustRenderer<'a> { impl<'a> DustRenderer<'a> {
pub fn new() -> DustRenderer<'a> { pub fn new() -> DustRenderer<'a> {
DustRenderer { DustRenderer {
templates: BTreeMap::new(), templates: HashMap::new(),
} }
} }
pub fn load_source(&mut self, template: &'a CompiledTemplate) { pub fn load_source(&mut self, template: &'a CompiledTemplate) {
self.templates.insert(&template.name, &template.template); self.templates
.insert(template.name.clone(), &template.template);
} }
// pub fn render(&self, context) { pub fn render<C>(&self, name: &str, context: C) -> Result<String, RenderError>
where
C: Index<&'a str>,
{
let main_template = match self.templates.get(name) {
Some(tmpl) => tmpl,
None => {
return Err(RenderError {
message: format!("No template named {} in context", name),
});
}
};
self.render_template(main_template, context)
}
// } fn render_template<C>(&self, template: &Template, context: C) -> Result<String, RenderError>
where
C: Index<&'a str>,
{
let mut output = String::new();
for elem in &template.contents.elements {
match elem {
TemplateElement::TESpan(span) => output.push_str(span.contents),
TemplateElement::TETag(dt) => (),
}
}
Ok(output)
}
} }