blob: 7dc926a4260b50d88f6c6e2a9d7f52d2f26a08b7 [file] [log] [blame]
extern crate env_logger;
extern crate handlebars;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use std::error::Error;
use serde_json::value::{Map, Value as Json};
use handlebars::{
to_json, Context, Decorator, Handlebars, Helper, JsonRender, Output, RenderContext,
RenderError, RenderErrorReason,
};
// default format helper
fn format_helper(
h: &Helper,
_: &Handlebars,
_: &Context,
_: &mut RenderContext,
out: &mut dyn Output,
) -> Result<(), RenderError> {
// get parameter from helper or throw an error
let param = h
.param(0)
.ok_or(RenderErrorReason::ParamNotFoundForIndex("format", 0))?;
write!(out, "{} pts", param.value().render())?;
Ok(())
}
// a decorator registers helpers
fn format_decorator(
d: &Decorator,
_: &Handlebars,
_: &Context,
rc: &mut RenderContext,
) -> Result<(), RenderError> {
let suffix = d
.param(0)
.map(|v| v.value().render())
.unwrap_or("".to_owned());
rc.register_local_helper(
"format",
Box::new(
move |h: &Helper,
_: &Handlebars,
_: &Context,
_: &mut RenderContext,
out: &mut dyn Output| {
// get parameter from helper or throw an error
let param = h
.param(0)
.ok_or(RenderErrorReason::ParamNotFoundForIndex("format", 0))?;
write!(out, "{} {}", param.value().render(), suffix)?;
Ok(())
},
),
);
Ok(())
}
// a decorator mutates current context data
fn set_decorator(
d: &Decorator,
_: &Handlebars,
ctx: &Context,
rc: &mut RenderContext,
) -> Result<(), RenderError> {
// get the input of decorator
let data_to_set = d.hash();
// retrieve the json value in current context
let ctx_data = ctx.data();
if let Json::Object(m) = ctx_data {
let mut new_ctx_data = m.clone();
for (k, v) in data_to_set {
new_ctx_data.insert(k.to_string(), v.value().clone());
}
rc.set_context(Context::wraps(new_ctx_data)?);
Ok(())
} else {
Err(RenderErrorReason::Other("Cannot extend non-object data".to_owned()).into())
}
}
// another custom helper
fn rank_helper(
h: &Helper,
_: &Handlebars,
_: &Context,
_: &mut RenderContext,
out: &mut dyn Output,
) -> Result<(), RenderError> {
let rank = h.param(0).and_then(|v| v.value().as_u64()).ok_or(
RenderErrorReason::ParamTypeMismatchForName("rank", "0".to_string(), "u64".to_string()),
)? as usize;
let total = h
.param(1)
.as_ref()
.and_then(|v| v.value().as_array())
.map(|arr| arr.len())
.ok_or(RenderErrorReason::ParamTypeMismatchForName(
"rank",
"1".to_string(),
"array".to_string(),
))?;
if rank == 0 {
out.write("champion")?;
} else if rank >= total - 2 {
out.write("relegation")?;
} else if rank <= 2 {
out.write("acl")?;
}
Ok(())
}
static TYPES: &'static str = "serde_json";
// define some data
#[derive(Serialize)]
pub struct Team {
name: String,
pts: u16,
}
// produce some data
pub fn make_data() -> Map<String, Json> {
let mut data = Map::new();
data.insert("year".to_string(), to_json("2015"));
let teams = vec![
Team {
name: "Jiangsu Suning".to_string(),
pts: 43u16,
},
Team {
name: "Shanghai SIPG".to_string(),
pts: 39u16,
},
Team {
name: "Hebei CFFC".to_string(),
pts: 27u16,
},
Team {
name: "Guangzhou Evergrand".to_string(),
pts: 22u16,
},
Team {
name: "Shandong Luneng".to_string(),
pts: 12u16,
},
Team {
name: "Beijing Guoan".to_string(),
pts: 7u16,
},
Team {
name: "Hangzhou Greentown".to_string(),
pts: 7u16,
},
Team {
name: "Shanghai Shenhua".to_string(),
pts: 4u16,
},
];
data.insert("teams".to_string(), to_json(&teams));
data.insert("engine".to_string(), to_json(TYPES));
data
}
fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
// create the handlebars registry
let mut handlebars = Handlebars::new();
// register template from a file and assign a name to it
// deal with errors
handlebars.register_template_file("table", "./examples/decorator/template.hbs")?;
// register some custom helpers
handlebars.register_helper("format", Box::new(format_helper));
handlebars.register_helper("ranking_label", Box::new(rank_helper));
handlebars.register_decorator("format_suffix", Box::new(format_decorator));
handlebars.register_decorator("set", Box::new(set_decorator));
// make data and render it
let data = make_data();
println!("{}", handlebars.render("table", &data)?);
Ok(())
}