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()
.map(|(p, contents)| template_from_file(p, contents))
.collect();
let mut dust_context = DustRenderer::new();
let mut dust_renderer = DustRenderer::new();
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> {
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::map::Map<String, serde_json::Value> {

View File

@ -8,3 +8,4 @@ pub use node_invoker::NodeError;
pub use node_invoker::Result;
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;
#[derive(Clone, Debug, PartialEq)]
enum DustTag<'a> {
pub enum DustTag<'a> {
DTSpecial(Special),
DTComment(Comment<'a>),
DTReference(Reference<'a>),
@ -79,8 +79,8 @@ enum Filter {
}
#[derive(Clone, Debug, PartialEq)]
struct Span<'a> {
contents: &'a str,
pub struct Span<'a> {
pub contents: &'a str,
}
#[derive(Clone, Debug, PartialEq)]
@ -123,17 +123,17 @@ struct KVPair<'a> {
}
#[derive(Clone, Debug, PartialEq)]
struct Body<'a> {
elements: Vec<TemplateElement<'a>>,
pub struct Body<'a> {
pub elements: Vec<TemplateElement<'a>>,
}
#[derive(Clone, Debug)]
pub struct Template<'a> {
contents: Body<'a>,
pub contents: Body<'a>,
}
#[derive(Clone, Debug, PartialEq)]
enum TemplateElement<'a> {
pub enum TemplateElement<'a> {
TESpan(Span<'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
mod errors;
mod renderer;
pub use renderer::compile_template;

View File

@ -1,41 +1,73 @@
use crate::parser::template;
use crate::parser::Template;
use nom::IResult;
use std::collections::BTreeMap;
use crate::parser::TemplateElement;
use crate::renderer::errors::CompileError;
use crate::renderer::errors::RenderError;
use std::collections::HashMap;
use std::ops::Index;
#[derive(Clone, Debug)]
pub struct CompiledTemplate<'a> {
template: Template<'a>,
name: String,
pub name: String,
}
#[derive(Clone, Debug)]
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> {
// TODO: Make this function return a result with a custom error type. Break the nom IResult chain
pub fn compile_template<'a>(
source: &'a str,
name: String,
) -> Result<CompiledTemplate<'a>, CompileError> {
// TODO: Make this all consuming
// TODO: This could use better error management
let (_remaining, parsed_template) = template(source).expect("Failed to compile template");
CompiledTemplate {
Ok(CompiledTemplate {
template: parsed_template,
name: name,
}
})
}
impl<'a> DustRenderer<'a> {
pub fn new() -> DustRenderer<'a> {
DustRenderer {
templates: BTreeMap::new(),
templates: HashMap::new(),
}
}
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)
}
}