Cleaning up and factoring out reused code in the renderer.

This commit is contained in:
Tom Alexander 2020-05-16 17:17:43 -04:00
parent 0f90fa2c7e
commit b53a9e1837
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE

View File

@ -77,6 +77,18 @@ impl<'a> DustRenderer<'a> {
self.render_body(&main_template.contents, breadcrumbs, &new_blocks) self.render_body(&main_template.contents, breadcrumbs, &new_blocks)
} }
fn render_maybe_body(
&'a self,
body: &'a Option<Body>,
breadcrumbs: &Vec<&'a dyn ContextElement>,
blocks: &'a InlinePartialTreeElement<'a>,
) -> Result<String, RenderError> {
match body {
None => Ok("".to_owned()),
Some(body) => Ok(self.render_body(body, breadcrumbs, blocks)?),
}
}
fn render_body( fn render_body(
&'a self, &'a self,
body: &'a Body, body: &'a Body,
@ -130,16 +142,13 @@ impl<'a> DustRenderer<'a> {
} }
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); let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val);
if loop_elements.is_empty() { if loop_elements.is_empty() {
// Oddly enough if the value is falsey (like // Oddly enough if the value is falsey (like
// an empty array or null), Dust uses the // an empty array or null), Dust uses the
// original context before walking the path as // original context before walking the path as
// the context for rendering the else block // the context for rendering the else block
return match &container.else_contents { return self.render_maybe_body(&container.else_contents, breadcrumbs, blocks);
Some(body) => self.render_body(&body, breadcrumbs, blocks),
None => Ok("".to_owned()),
};
} else { } else {
match &container.contents { match &container.contents {
None => return Ok("".to_owned()), None => return Ok("".to_owned()),
@ -160,34 +169,22 @@ impl<'a> DustRenderer<'a> {
} }
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); let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val);
if loop_elements.is_empty() { return if loop_elements.is_empty() {
return match &container.else_contents { self.render_maybe_body(&container.else_contents, breadcrumbs, blocks)
Some(body) => self.render_body(&body, breadcrumbs, blocks),
None => Ok("".to_owned()),
};
} else { } else {
return match &container.contents { self.render_maybe_body(&container.contents, breadcrumbs, blocks)
None => Ok("".to_owned()),
Some(body) => self.render_body(&body, 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); let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val);
if !loop_elements.is_empty() { return if !loop_elements.is_empty() {
return match &container.else_contents { self.render_maybe_body(&container.else_contents, breadcrumbs, blocks)
Some(body) => self.render_body(&body, breadcrumbs, blocks),
None => Ok("".to_owned()),
};
} else { } else {
return match &container.contents { self.render_maybe_body(&container.contents, breadcrumbs, blocks)
None => Ok("".to_owned()),
Some(body) => self.render_body(&body, breadcrumbs, blocks),
}; };
} }
}
DustTag::DTPartial(partial) => { DustTag::DTPartial(partial) => {
if partial.params.is_empty() { if partial.params.is_empty() {
let rendered_content = let rendered_content =
@ -202,34 +199,19 @@ impl<'a> DustRenderer<'a> {
return Ok(rendered_content); return Ok(rendered_content);
} }
} }
DustTag::DTInlinePartial(named_block) => { DustTag::DTInlinePartial(_named_block) => {
// Inline partials are blank during rendering (they get injected into blocks) // Inline partials are blank during rendering (they get injected into blocks)
return Ok("".to_owned()); return Ok("".to_owned());
} }
DustTag::DTBlock(named_block) => { DustTag::DTBlock(named_block) => {
match blocks.get_block(named_block.name) { return match blocks.get_block(named_block.name) {
None => match &named_block.contents { None => self.render_maybe_body(&named_block.contents, breadcrumbs, blocks),
None => return Ok("".to_owned()), Some(interior) => self.render_maybe_body(interior, breadcrumbs, blocks),
Some(body) => {
let rendered_content = self.render_body(body, breadcrumbs, blocks)?;
return Ok(rendered_content);
}
},
Some(interior) => match interior {
None => return Ok("".to_owned()),
Some(body) => {
let rendered_content = self.render_body(body, breadcrumbs, blocks)?;
return Ok(rendered_content);
}
},
}; };
} }
DustTag::DTHelperEquals(parameterized_block) => { DustTag::DTHelperEquals(parameterized_block) => {
let param_map: HashMap<&str, &RValue<'a>> = parameterized_block let param_map: HashMap<&str, &RValue<'a>> =
.params Self::get_rval_map(&parameterized_block.params);
.iter()
.map(|pair: &KVPair<'a>| (pair.key, &pair.value))
.collect();
// Special case: when comparing two RVPaths, if the // Special case: when comparing two RVPaths, if the
// path is equal then dust assumes the values are // path is equal then dust assumes the values are
// equal (otherwise, non-scalar values are // equal (otherwise, non-scalar values are
@ -244,47 +226,31 @@ impl<'a> DustRenderer<'a> {
}; };
} }
let left_side: Result<&dyn ContextElement, WalkError> = match param_map.get("key") { let left_side: Result<&dyn ContextElement, WalkError> =
match Self::get_rval(breadcrumbs, &param_map, "key") {
None => return Ok("".to_owned()), None => return Ok("".to_owned()),
Some(rval) => match rval { Some(res) => res,
RValue::RVString(text) => Ok(text),
RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys),
RValue::RVPositiveInteger(num) => Ok(num),
},
}; };
let right_side: Result<&dyn ContextElement, WalkError> = let right_side: Result<&dyn ContextElement, WalkError> =
match param_map.get("value") { Self::get_rval(breadcrumbs, &param_map, "value")
None => Err(WalkError::CantWalk), .unwrap_or(Err(WalkError::CantWalk));
Some(rval) => match rval {
RValue::RVString(text) => Ok(text),
RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys),
RValue::RVPositiveInteger(num) => Ok(num),
},
};
if left_side == right_side { if left_side == right_side {
match &parameterized_block.contents { return self.render_maybe_body(
None => return Ok("".to_owned()), &parameterized_block.contents,
Some(body) => { breadcrumbs,
let rendered_content = self.render_body(body, breadcrumbs, blocks)?; blocks,
return Ok(rendered_content); );
}
}
} else { } else {
match &parameterized_block.else_contents { return self.render_maybe_body(
None => return Ok("".to_owned()), &parameterized_block.else_contents,
Some(body) => { breadcrumbs,
let rendered_content = self.render_body(body, breadcrumbs, blocks)?; blocks,
return Ok(rendered_content); );
}
}
} }
} }
DustTag::DTHelperNotEquals(parameterized_block) => { DustTag::DTHelperNotEquals(parameterized_block) => {
let param_map: HashMap<&str, &RValue<'a>> = parameterized_block let param_map: HashMap<&str, &RValue<'a>> =
.params Self::get_rval_map(&parameterized_block.params);
.iter()
.map(|pair: &KVPair<'a>| (pair.key, &pair.value))
.collect();
// Special case: when comparing two RVPaths, if the // Special case: when comparing two RVPaths, if the
// path is equal then dust assumes the values are // path is equal then dust assumes the values are
// equal (otherwise, non-scalar values are // equal (otherwise, non-scalar values are
@ -299,64 +265,39 @@ impl<'a> DustRenderer<'a> {
}; };
} }
let left_side: Result<&dyn ContextElement, WalkError> = match param_map.get("key") { let left_side: Result<&dyn ContextElement, WalkError> =
match Self::get_rval(breadcrumbs, &param_map, "key") {
None => return Ok("".to_owned()), None => return Ok("".to_owned()),
Some(rval) => match rval { Some(res) => res,
RValue::RVString(text) => Ok(text),
RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys),
RValue::RVPositiveInteger(num) => Ok(num),
},
}; };
let right_side: Result<&dyn ContextElement, WalkError> = let right_side: Result<&dyn ContextElement, WalkError> =
match param_map.get("value") { Self::get_rval(breadcrumbs, &param_map, "value")
None => Err(WalkError::CantWalk), .unwrap_or(Err(WalkError::CantWalk));
Some(rval) => match rval {
RValue::RVString(text) => Ok(text),
RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys),
RValue::RVPositiveInteger(num) => Ok(num),
},
};
if left_side != right_side { if left_side != right_side {
match &parameterized_block.contents { return self.render_maybe_body(
None => return Ok("".to_owned()), &parameterized_block.contents,
Some(body) => { breadcrumbs,
let rendered_content = self.render_body(body, breadcrumbs, blocks)?; blocks,
return Ok(rendered_content); );
}
}
} else { } else {
match &parameterized_block.else_contents { return self.render_maybe_body(
None => return Ok("".to_owned()), &parameterized_block.else_contents,
Some(body) => { breadcrumbs,
let rendered_content = self.render_body(body, breadcrumbs, blocks)?; blocks,
return Ok(rendered_content); );
}
}
} }
} }
DustTag::DTHelperGreaterThan(parameterized_block) => { DustTag::DTHelperGreaterThan(parameterized_block) => {
let param_map: HashMap<&str, &RValue<'a>> = parameterized_block let param_map: HashMap<&str, &RValue<'a>> =
.params Self::get_rval_map(&parameterized_block.params);
.iter() let left_side: Result<&dyn ContextElement, WalkError> =
.map(|pair: &KVPair<'a>| (pair.key, &pair.value)) match Self::get_rval(breadcrumbs, &param_map, "key") {
.collect();
let left_side: Result<&dyn ContextElement, WalkError> = match param_map.get("key") {
None => return Ok("".to_owned()), None => return Ok("".to_owned()),
Some(rval) => match rval { Some(res) => res,
RValue::RVString(text) => Ok(text),
RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys),
RValue::RVPositiveInteger(num) => Ok(num),
},
}; };
let right_side: Result<&dyn ContextElement, WalkError> = let right_side: Result<&dyn ContextElement, WalkError> =
match param_map.get("value") { Self::get_rval(breadcrumbs, &param_map, "value")
None => Err(WalkError::CantWalk), .unwrap_or(Err(WalkError::CantWalk));
Some(rval) => match rval {
RValue::RVString(text) => Ok(text),
RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys),
RValue::RVPositiveInteger(num) => Ok(num),
},
};
match (left_side, right_side) { match (left_side, right_side) {
(Err(_), _) | (_, Err(_)) => match &parameterized_block.else_contents { (Err(_), _) | (_, Err(_)) => match &parameterized_block.else_contents {
None => return Ok("".to_owned()), None => return Ok("".to_owned()),
@ -367,23 +308,17 @@ impl<'a> DustRenderer<'a> {
}, },
(Ok(left_side_unwrapped), Ok(right_side_unwrapped)) => { (Ok(left_side_unwrapped), Ok(right_side_unwrapped)) => {
if left_side_unwrapped > right_side_unwrapped { if left_side_unwrapped > right_side_unwrapped {
match &parameterized_block.contents { return self.render_maybe_body(
None => return Ok("".to_owned()), &parameterized_block.contents,
Some(body) => { breadcrumbs,
let rendered_content = blocks,
self.render_body(body, breadcrumbs, blocks)?; );
return Ok(rendered_content);
}
}
} else { } else {
match &parameterized_block.else_contents { return self.render_maybe_body(
None => return Ok("".to_owned()), &parameterized_block.else_contents,
Some(body) => { breadcrumbs,
let rendered_content = blocks,
self.render_body(body, breadcrumbs, blocks)?; );
return Ok(rendered_content);
}
}
} }
} }
} }
@ -398,7 +333,6 @@ impl<'a> DustRenderer<'a> {
/// If the value is falsey, and therefore should render the else /// If the value is falsey, and therefore should render the else
/// block, this will return an empty vector. /// block, this will return an empty vector.
fn get_loop_elements<'b>( fn get_loop_elements<'b>(
&'a self,
walk_result: Result<&'b dyn ContextElement, WalkError>, walk_result: Result<&'b dyn ContextElement, WalkError>,
) -> Vec<&'b dyn ContextElement> { ) -> Vec<&'b dyn ContextElement> {
match walk_result { match walk_result {
@ -419,6 +353,28 @@ impl<'a> DustRenderer<'a> {
}, },
} }
} }
fn get_rval_map<'b>(params: &'b Vec<KVPair<'b>>) -> HashMap<&'b str, &'b RValue<'b>> {
params
.iter()
.map(|pair: &KVPair<'b>| (pair.key, &pair.value))
.collect()
}
fn get_rval<'b>(
breadcrumbs: &Vec<&'b dyn ContextElement>,
param_map: &HashMap<&str, &'b RValue<'b>>,
key: &str,
) -> Option<Result<&'b dyn ContextElement, WalkError>> {
match param_map.get(key) {
None => None,
Some(rval) => match rval {
RValue::RVString(text) => Some(Ok(text)),
RValue::RVPath(path) => Some(walk_path(breadcrumbs, &path.keys)),
RValue::RVPositiveInteger(num) => Some(Ok(num)),
},
}
}
} }
#[cfg(test)] #[cfg(test)]