1use crate::context::Context;
2use crate::error::RenderError;
3use crate::registry::Registry;
4use crate::render::{Decorator, RenderContext};
5
6pub use self::inline::INLINE_DECORATOR;
7
8pub type DecoratorResult = Result<(), RenderError>;
9
10pub trait DecoratorDef {
60 fn call<'reg: 'rc, 'rc>(
61 &'reg self,
62 d: &Decorator<'rc>,
63 r: &'reg Registry<'reg>,
64 ctx: &'rc Context,
65 rc: &mut RenderContext<'reg, 'rc>,
66 ) -> DecoratorResult;
67}
68
69impl<
71 F: for<'reg, 'rc> Fn(
72 &Decorator<'rc>,
73 &'reg Registry<'reg>,
74 &'rc Context,
75 &mut RenderContext<'reg, 'rc>,
76 ) -> DecoratorResult,
77 > DecoratorDef for F
78{
79 fn call<'reg: 'rc, 'rc>(
80 &'reg self,
81 d: &Decorator<'rc>,
82 reg: &'reg Registry<'reg>,
83 ctx: &'rc Context,
84 rc: &mut RenderContext<'reg, 'rc>,
85 ) -> DecoratorResult {
86 (*self)(d, reg, ctx, rc)
87 }
88}
89
90mod inline;
91
92#[cfg(test)]
93mod test {
94 use crate::context::Context;
95 use crate::error::RenderError;
96 use crate::json::value::{as_string, to_json};
97 use crate::output::Output;
98 use crate::registry::Registry;
99 use crate::render::{Decorator, Helper, RenderContext};
100
101 #[test]
102 fn test_register_decorator() {
103 let mut handlebars = Registry::new();
104 handlebars
105 .register_template_string("t0", "{{*foo}}")
106 .unwrap();
107
108 let data = json!({
109 "hello": "world"
110 });
111
112 assert!(handlebars.render("t0", &data).is_err());
113
114 handlebars.register_decorator(
115 "foo",
116 Box::new(
117 |_: &Decorator<'_>,
118 _: &Registry<'_>,
119 _: &Context,
120 _: &mut RenderContext<'_, '_>|
121 -> Result<(), RenderError> { Ok(()) },
122 ),
123 );
124 assert_eq!(handlebars.render("t0", &data).ok().unwrap(), String::new());
125 }
126
127 #[test]
129 fn test_update_data_with_decorator() {
130 let mut handlebars = Registry::new();
131 handlebars
132 .register_template_string("t0", "{{hello}}{{*foo}}{{hello}}")
133 .unwrap();
134
135 let data = json!({
136 "hello": "world"
137 });
138
139 handlebars.register_decorator(
140 "foo",
141 Box::new(
142 |_: &Decorator<'_>,
143 _: &Registry<'_>,
144 ctx: &Context,
145 rc: &mut RenderContext<'_, '_>|
146 -> Result<(), RenderError> {
147 let mut new_ctx = ctx.clone();
149 {
150 let data = new_ctx.data_mut();
151 if let Some(ref mut m) = data.as_object_mut().as_mut() {
152 m.insert("hello".to_string(), to_json("war"));
153 }
154 }
155 rc.set_context(new_ctx);
156 Ok(())
157 },
158 ),
159 );
160
161 assert_eq!(
162 handlebars.render("t0", &data).ok().unwrap(),
163 "worldwar".to_string()
164 );
165
166 let data2 = 0;
167 handlebars.register_decorator(
168 "bar",
169 Box::new(
170 |d: &Decorator<'_>,
171 _: &Registry<'_>,
172 _: &Context,
173 rc: &mut RenderContext<'_, '_>|
174 -> Result<(), RenderError> {
175 let v = d
177 .param(0)
178 .and_then(|v| Context::wraps(v.value()).ok())
179 .unwrap_or(Context::null());
180 rc.set_context(v);
181 Ok(())
182 },
183 ),
184 );
185 handlebars
186 .register_template_string("t1", "{{this}}{{*bar 1}}{{this}}")
187 .unwrap();
188 assert_eq!(
189 handlebars.render("t1", &data2).ok().unwrap(),
190 "01".to_string()
191 );
192
193 handlebars
194 .register_template_string("t2", "{{this}}{{*bar \"string_literal\"}}{{this}}")
195 .unwrap();
196 assert_eq!(
197 handlebars.render("t2", &data2).ok().unwrap(),
198 "0string_literal".to_string()
199 );
200
201 handlebars
202 .register_template_string("t3", "{{this}}{{*bar}}{{this}}")
203 .unwrap();
204 assert_eq!(
205 handlebars.render("t3", &data2).ok().unwrap(),
206 "0".to_string()
207 );
208 }
209
210 #[test]
211 fn test_local_helper_with_decorator() {
212 let mut handlebars = Registry::new();
213 handlebars
214 .register_template_string(
215 "t0",
216 "{{distance 4.5}},{{*foo \"miles\"}}{{distance 10.1}},{{*bar}}{{distance 3.4}}",
217 )
218 .unwrap();
219
220 handlebars.register_helper(
221 "distance",
222 Box::new(
223 |h: &Helper<'_>,
224 _: &Registry<'_>,
225 _: &Context,
226 _: &mut RenderContext<'_, '_>,
227 out: &mut dyn Output|
228 -> Result<(), RenderError> {
229 write!(
230 out,
231 "{}m",
232 h.param(0).as_ref().map_or(&to_json(0), |v| v.value())
233 )?;
234 Ok(())
235 },
236 ),
237 );
238 handlebars.register_decorator(
239 "foo",
240 Box::new(
241 |d: &Decorator<'_>,
242 _: &Registry<'_>,
243 _: &Context,
244 rc: &mut RenderContext<'_, '_>|
245 -> Result<(), RenderError> {
246 let new_unit = d
247 .param(0)
248 .as_ref()
249 .and_then(|v| as_string(v.value()))
250 .unwrap_or("")
251 .to_owned();
252 let new_helper = move |h: &Helper<'_>,
253 _: &Registry<'_>,
254 _: &Context,
255 _: &mut RenderContext<'_, '_>,
256 out: &mut dyn Output|
257 -> Result<(), RenderError> {
258 write!(
259 out,
260 "{}{}",
261 h.param(0).as_ref().map_or(&to_json(0), |v| v.value()),
262 new_unit
263 )?;
264 Ok(())
265 };
266
267 rc.register_local_helper("distance", Box::new(new_helper));
268 Ok(())
269 },
270 ),
271 );
272 handlebars.register_decorator(
273 "bar",
274 Box::new(
275 |_: &Decorator<'_>,
276 _: &Registry<'_>,
277 _: &Context,
278 rc: &mut RenderContext<'_, '_>|
279 -> Result<(), RenderError> {
280 rc.unregister_local_helper("distance");
281 Ok(())
282 },
283 ),
284 );
285 assert_eq!(
286 handlebars.render("t0", &0).ok().unwrap(),
287 "4.5m,10.1miles,3.4m".to_owned()
288 );
289 }
290}