Add a Loopable trait for dust sections.
This commit is contained in:
parent
c961cf7ab8
commit
e5c4ba8c82
32
src/bin.rs
32
src/bin.rs
@ -5,6 +5,7 @@ use renderer::compile_template;
|
|||||||
use renderer::CompiledTemplate;
|
use renderer::CompiledTemplate;
|
||||||
use renderer::ContextElement;
|
use renderer::ContextElement;
|
||||||
use renderer::DustRenderer;
|
use renderer::DustRenderer;
|
||||||
|
use renderer::Loopable;
|
||||||
use renderer::RenderError;
|
use renderer::RenderError;
|
||||||
use renderer::Renderable;
|
use renderer::Renderable;
|
||||||
use renderer::Walkable;
|
use renderer::Walkable;
|
||||||
@ -123,3 +124,34 @@ impl Walkable for serde_json::Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Loopable for serde_json::Value {
|
||||||
|
fn get_loop_elements(&self) -> Result<Vec<&dyn ContextElement>, RenderError> {
|
||||||
|
match self {
|
||||||
|
serde_json::Value::Null => Ok(Vec::new()),
|
||||||
|
serde_json::Value::Bool(boolean) => {
|
||||||
|
if *boolean {
|
||||||
|
Ok(vec![self])
|
||||||
|
} else {
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serde_json::Value::Number(_num) => Ok(vec![self]),
|
||||||
|
serde_json::Value::String(string_value) => {
|
||||||
|
if string_value.is_empty() {
|
||||||
|
Ok(Vec::new())
|
||||||
|
} else {
|
||||||
|
Ok(vec![self])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serde_json::Value::Array(array_value) => {
|
||||||
|
if array_value.is_empty() {
|
||||||
|
Ok(Vec::new())
|
||||||
|
} else {
|
||||||
|
Ok(array_value.iter().map(|x| x as _).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serde_json::Value::Object(_obj) => Ok(vec![self]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,7 +2,7 @@ use crate::parser::Filter;
|
|||||||
use crate::renderer::errors::RenderError;
|
use crate::renderer::errors::RenderError;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
pub trait ContextElement: Walkable + Renderable + Debug {}
|
pub trait ContextElement: Debug + Walkable + Renderable + Loopable {}
|
||||||
|
|
||||||
pub trait Walkable {
|
pub trait Walkable {
|
||||||
fn walk(&self, segment: &str) -> Result<&dyn ContextElement, RenderError>;
|
fn walk(&self, segment: &str) -> Result<&dyn ContextElement, RenderError>;
|
||||||
@ -11,3 +11,18 @@ pub trait Walkable {
|
|||||||
pub trait Renderable {
|
pub trait Renderable {
|
||||||
fn render(&self, filters: &Vec<Filter>) -> Result<String, RenderError>;
|
fn render(&self, filters: &Vec<Filter>) -> Result<String, RenderError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Loopable {
|
||||||
|
/// Return the elements for a Dust section
|
||||||
|
///
|
||||||
|
/// Sections in dust are accomplished with the {#path} syntax. A
|
||||||
|
/// section has a truthiness check performed on it. If that
|
||||||
|
/// truthiness check fails, then it will render the
|
||||||
|
/// else-block. Otherwise if its a scalar value it will render
|
||||||
|
/// once with the context being the element at that path. Finally,
|
||||||
|
/// if its an array-like value then it will render n-times, once
|
||||||
|
/// for each element of the array.
|
||||||
|
///
|
||||||
|
/// TODO: Should this return an iterator instead of a vec?
|
||||||
|
fn get_loop_elements(&self) -> Result<Vec<&dyn ContextElement>, RenderError>;
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@ mod errors;
|
|||||||
mod renderer;
|
mod renderer;
|
||||||
|
|
||||||
pub use context_element::ContextElement;
|
pub use context_element::ContextElement;
|
||||||
|
pub use context_element::Loopable;
|
||||||
pub use context_element::Renderable;
|
pub use context_element::Renderable;
|
||||||
pub use context_element::Walkable;
|
pub use context_element::Walkable;
|
||||||
pub use errors::CompileError;
|
pub use errors::CompileError;
|
||||||
|
@ -114,6 +114,7 @@ fn walk_path<'a>(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::parser::Filter;
|
use crate::parser::Filter;
|
||||||
|
use crate::renderer::context_element::Loopable;
|
||||||
use crate::renderer::context_element::Renderable;
|
use crate::renderer::context_element::Renderable;
|
||||||
use crate::renderer::context_element::Walkable;
|
use crate::renderer::context_element::Walkable;
|
||||||
|
|
||||||
@ -172,6 +173,28 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Loopable for &str {
|
||||||
|
fn get_loop_elements(&self) -> Result<Vec<&dyn ContextElement>, RenderError> {
|
||||||
|
if self.is_empty() {
|
||||||
|
Ok(Vec::new())
|
||||||
|
} else {
|
||||||
|
Ok(vec![self])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Loopable for u32 {
|
||||||
|
fn get_loop_elements(&self) -> Result<Vec<&dyn ContextElement>, RenderError> {
|
||||||
|
Ok(vec![self])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: ContextElement> Loopable for HashMap<&str, I> {
|
||||||
|
fn get_loop_elements(&self) -> Result<Vec<&dyn ContextElement>, RenderError> {
|
||||||
|
Ok(vec![self])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let context: HashMap<&str, &str> =
|
let context: HashMap<&str, &str> =
|
||||||
[("cat", "kitty"), ("dog", "doggy"), ("tiger", "murderkitty")]
|
[("cat", "kitty"), ("dog", "doggy"), ("tiger", "murderkitty")]
|
||||||
.iter()
|
.iter()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user