1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
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(())
}
|