Switch the renderer over to using the new is_truthy value and add the injection of $idx and $len into the context tree.

This commit is contained in:
Tom Alexander 2020-05-24 16:57:24 -04:00
parent 966499db76
commit c09393da80
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
2 changed files with 76 additions and 38 deletions

View File

@ -6,6 +6,7 @@ use crate::renderer::Renderable;
use crate::renderer::Truthiness; use crate::renderer::Truthiness;
use crate::renderer::WalkError; use crate::renderer::WalkError;
use crate::{parser::Filter, parser::OwnedLiteral, renderer::Walkable}; use crate::{parser::Filter, parser::OwnedLiteral, renderer::Walkable};
use std::convert::TryInto;
use std::cmp::Ordering; use std::cmp::Ordering;
@ -21,10 +22,11 @@ pub struct IterationContext {
} }
impl IterationContext { impl IterationContext {
pub fn new(idx: u64, len: u64) -> Self { pub fn new(idx: usize, len: usize) -> Self {
// TODO: it would be nice to handle usize vs u64 better
IterationContext { IterationContext {
idx: OwnedLiteral::LPositiveInteger(idx), idx: OwnedLiteral::LPositiveInteger(idx.try_into().unwrap()),
len: OwnedLiteral::LPositiveInteger(len), len: OwnedLiteral::LPositiveInteger(len.try_into().unwrap()),
} }
} }
} }

View File

@ -13,6 +13,7 @@ use crate::renderer::errors::RenderError;
use crate::renderer::errors::WalkError; use crate::renderer::errors::WalkError;
use crate::renderer::inline_partial_tree::extract_inline_partials; use crate::renderer::inline_partial_tree::extract_inline_partials;
use crate::renderer::inline_partial_tree::InlinePartialTreeElement; use crate::renderer::inline_partial_tree::InlinePartialTreeElement;
use crate::renderer::iteration_context::IterationContext;
use crate::renderer::parameters_context::ParametersContext; use crate::renderer::parameters_context::ParametersContext;
use crate::renderer::walking::walk_path; use crate::renderer::walking::walk_path;
use std::collections::HashMap; use std::collections::HashMap;
@ -150,58 +151,93 @@ impl<'a> DustRenderer<'a> {
match val { match val {
Err(WalkError::CantWalk) => return Ok("".to_owned()), Err(WalkError::CantWalk) => return Ok("".to_owned()),
Ok(final_val) => { Ok(final_val) => {
let loop_elements = final_val.get_loop_elements(); return if final_val.is_truthy() {
if loop_elements.is_empty() { final_val.render(&Self::preprocess_filters(&reference.filters))
return Ok("".to_owned());
} else { } else {
return final_val.render(&Self::preprocess_filters(&reference.filters)); Ok("".to_owned())
} };
} }
} }
} }
DustTag::DTSection(container) => { DustTag::DTSection(container) => {
let val = walk_path(breadcrumbs, &container.path.keys); let val = walk_path(breadcrumbs, &container.path.keys);
let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val); match val {
if loop_elements.is_empty() { Err(WalkError::CantWalk) => {
// Oddly enough if the value is falsey (like return self.render_maybe_body(
// an empty array or null), Dust uses the &container.else_contents,
// original context before walking the path as breadcrumbs,
// the context for rendering the else block blocks,
return self.render_maybe_body(&container.else_contents, breadcrumbs, blocks); );
} else { }
match &container.contents { Ok(final_val) => {
None => return Ok("".to_owned()), return if final_val.is_truthy() {
Some(body) => { match &container.contents {
let rendered_results: Result<Vec<String>, RenderError> = loop_elements // If the body is empty, just shortcut
.into_iter() // to an empty string now rather than
.map(|array_elem| { // generating intermediate contexts
let mut new_breadcumbs = breadcrumbs.clone(); // and iterating for nothing.
new_breadcumbs.push(array_elem); None => Ok("".to_owned()),
self.render_body(&body, &new_breadcumbs, blocks) Some(body) => {
}) let loop_elements: Vec<&dyn ContextElement> =
.collect(); final_val.get_loop_elements();
let rendered_slice: &[String] = &rendered_results?; if loop_elements.is_empty() {
return Ok(rendered_slice.join("")); // Scalar value
} let mut new_breadcrumbs = breadcrumbs.clone();
new_breadcrumbs.push(final_val);
self.render_body(body, &new_breadcrumbs, blocks)
} else {
// Array-like value
let total_length = loop_elements.len();
let rendered_results: Result<Vec<String>, RenderError> =
loop_elements
.into_iter()
.enumerate()
.map(|(i, array_elem)| {
let injected_context =
IterationContext::new(i, total_length);
let mut new_breadcrumbs = breadcrumbs.clone();
new_breadcrumbs.push(&injected_context);
new_breadcrumbs.push(array_elem);
self.render_body(
&body,
&new_breadcrumbs,
blocks,
)
})
.collect();
let rendered_slice: &[String] = &rendered_results?;
return Ok(rendered_slice.join(""));
}
}
}
} else {
// Oddly enough if the value is falsey (like
// an empty array or null), Dust uses the
// original context before walking the path as
// the context for rendering the else block
return self.render_maybe_body(
&container.else_contents,
breadcrumbs,
blocks,
);
};
} }
} }
} }
DustTag::DTExists(container) => { DustTag::DTExists(container) => {
let val = walk_path(breadcrumbs, &container.path.keys); let val = walk_path(breadcrumbs, &container.path.keys);
let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val); return if val.map(|v| v.is_truthy()).unwrap_or(false) {
return if loop_elements.is_empty() {
self.render_maybe_body(&container.else_contents, breadcrumbs, blocks)
} else {
self.render_maybe_body(&container.contents, breadcrumbs, blocks) self.render_maybe_body(&container.contents, breadcrumbs, blocks)
} else {
self.render_maybe_body(&container.else_contents, breadcrumbs, blocks)
}; };
} }
DustTag::DTNotExists(container) => { DustTag::DTNotExists(container) => {
let val = walk_path(breadcrumbs, &container.path.keys); let val = walk_path(breadcrumbs, &container.path.keys);
let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val); return if !val.map(|v| v.is_truthy()).unwrap_or(false) {
return if !loop_elements.is_empty() {
self.render_maybe_body(&container.else_contents, breadcrumbs, blocks)
} else {
self.render_maybe_body(&container.contents, breadcrumbs, blocks) self.render_maybe_body(&container.contents, breadcrumbs, blocks)
} else {
self.render_maybe_body(&container.else_contents, breadcrumbs, blocks)
}; };
} }
DustTag::DTPartial(partial) => { DustTag::DTPartial(partial) => {