]>
Commit | Line | Data |
---|---|---|
3dfed10e XL |
1 | use super::block_util::create_block; |
2 | use crate::block::BlockParams; | |
f9f354fc | 3 | use crate::context::Context; |
416331ca XL |
4 | use crate::error::RenderError; |
5 | use crate::helpers::{HelperDef, HelperResult}; | |
f9f354fc | 6 | use crate::json::value::JsonTruthy; |
416331ca XL |
7 | use crate::output::Output; |
8 | use crate::registry::Registry; | |
9 | use crate::render::{Helper, RenderContext, Renderable}; | |
8bb4bdeb XL |
10 | |
11 | #[derive(Clone, Copy)] | |
12 | pub struct WithHelper; | |
13 | ||
14 | impl HelperDef for WithHelper { | |
9fa01778 XL |
15 | fn call<'reg: 'rc, 'rc>( |
16 | &self, | |
f9f354fc | 17 | h: &Helper<'reg, 'rc>, |
3dfed10e | 18 | r: &'reg Registry<'reg>, |
f9f354fc XL |
19 | ctx: &'rc Context, |
20 | rc: &mut RenderContext<'reg, 'rc>, | |
416331ca | 21 | out: &mut dyn Output, |
9fa01778 XL |
22 | ) -> HelperResult { |
23 | let param = h | |
24 | .param(0) | |
25 | .ok_or_else(|| RenderError::new("Param not found for helper \"with\""))?; | |
8bb4bdeb | 26 | |
94222f64 XL |
27 | if param.value().is_truthy(false) { |
28 | let mut block = create_block(¶m); | |
416331ca | 29 | |
f9f354fc XL |
30 | if let Some(block_param) = h.block_param() { |
31 | let mut params = BlockParams::new(); | |
3dfed10e | 32 | if param.context_path().is_some() { |
f9f354fc XL |
33 | params.add_path(block_param, Vec::with_capacity(0))?; |
34 | } else { | |
35 | params.add_value(block_param, param.value().clone())?; | |
8bb4bdeb | 36 | } |
8bb4bdeb | 37 | |
f9f354fc | 38 | block.set_block_params(params); |
8bb4bdeb XL |
39 | } |
40 | ||
f9f354fc | 41 | rc.push_block(block); |
8bb4bdeb | 42 | |
94222f64 XL |
43 | if let Some(t) = h.template() { |
44 | t.render(r, ctx, rc, out)?; | |
45 | }; | |
8bb4bdeb | 46 | |
f9f354fc | 47 | rc.pop_block(); |
94222f64 XL |
48 | Ok(()) |
49 | } else if let Some(t) = h.inverse() { | |
50 | t.render(r, ctx, rc, out) | |
51 | } else if r.strict_mode() { | |
52 | Err(RenderError::strict_error(param.relative_path())) | |
53 | } else { | |
54 | Ok(()) | |
f9f354fc | 55 | } |
8bb4bdeb XL |
56 | } |
57 | } | |
58 | ||
59 | pub static WITH_HELPER: WithHelper = WithHelper; | |
60 | ||
61 | #[cfg(test)] | |
8bb4bdeb | 62 | mod test { |
f9f354fc | 63 | use crate::json::value::to_json; |
416331ca | 64 | use crate::registry::Registry; |
8bb4bdeb | 65 | |
041b39d2 | 66 | #[derive(Serialize)] |
8bb4bdeb XL |
67 | struct Address { |
68 | city: String, | |
69 | country: String, | |
70 | } | |
71 | ||
041b39d2 | 72 | #[derive(Serialize)] |
8bb4bdeb XL |
73 | struct Person { |
74 | name: String, | |
75 | age: i16, | |
76 | addr: Address, | |
77 | titles: Vec<String>, | |
78 | } | |
79 | ||
8bb4bdeb XL |
80 | #[test] |
81 | fn test_with() { | |
82 | let addr = Address { | |
83 | city: "Beijing".to_string(), | |
84 | country: "China".to_string(), | |
85 | }; | |
86 | ||
87 | let person = Person { | |
88 | name: "Ning Sun".to_string(), | |
89 | age: 27, | |
416331ca | 90 | addr, |
8bb4bdeb XL |
91 | titles: vec!["programmer".to_string(), "cartographier".to_string()], |
92 | }; | |
93 | ||
94 | let mut handlebars = Registry::new(); | |
416331ca XL |
95 | assert!(handlebars |
96 | .register_template_string("t0", "{{#with addr}}{{city}}{{/with}}") | |
97 | .is_ok()); | |
98 | assert!(handlebars | |
99 | .register_template_string("t1", "{{#with notfound}}hello{{else}}world{{/with}}") | |
100 | .is_ok()); | |
101 | assert!(handlebars | |
102 | .register_template_string("t2", "{{#with addr/country}}{{this}}{{/with}}") | |
103 | .is_ok()); | |
8bb4bdeb XL |
104 | |
105 | let r0 = handlebars.render("t0", &person); | |
106 | assert_eq!(r0.ok().unwrap(), "Beijing".to_string()); | |
107 | ||
108 | let r1 = handlebars.render("t1", &person); | |
109 | assert_eq!(r1.ok().unwrap(), "world".to_string()); | |
110 | ||
111 | let r2 = handlebars.render("t2", &person); | |
112 | assert_eq!(r2.ok().unwrap(), "China".to_string()); | |
113 | } | |
114 | ||
115 | #[test] | |
116 | fn test_with_block_param() { | |
117 | let addr = Address { | |
118 | city: "Beijing".to_string(), | |
119 | country: "China".to_string(), | |
120 | }; | |
121 | ||
122 | let person = Person { | |
123 | name: "Ning Sun".to_string(), | |
124 | age: 27, | |
416331ca | 125 | addr, |
8bb4bdeb XL |
126 | titles: vec!["programmer".to_string(), "cartographier".to_string()], |
127 | }; | |
128 | ||
129 | let mut handlebars = Registry::new(); | |
416331ca XL |
130 | assert!(handlebars |
131 | .register_template_string("t0", "{{#with addr as |a|}}{{a.city}}{{/with}}") | |
132 | .is_ok()); | |
133 | assert!(handlebars | |
134 | .register_template_string("t1", "{{#with notfound as |c|}}hello{{else}}world{{/with}}") | |
135 | .is_ok()); | |
136 | assert!(handlebars | |
137 | .register_template_string("t2", "{{#with addr/country as |t|}}{{t}}{{/with}}") | |
138 | .is_ok()); | |
8bb4bdeb XL |
139 | |
140 | let r0 = handlebars.render("t0", &person); | |
141 | assert_eq!(r0.ok().unwrap(), "Beijing".to_string()); | |
142 | ||
143 | let r1 = handlebars.render("t1", &person); | |
144 | assert_eq!(r1.ok().unwrap(), "world".to_string()); | |
145 | ||
146 | let r2 = handlebars.render("t2", &person); | |
147 | assert_eq!(r2.ok().unwrap(), "China".to_string()); | |
148 | } | |
149 | ||
150 | #[test] | |
151 | fn test_with_in_each() { | |
152 | let addr = Address { | |
153 | city: "Beijing".to_string(), | |
154 | country: "China".to_string(), | |
155 | }; | |
156 | ||
157 | let person = Person { | |
158 | name: "Ning Sun".to_string(), | |
159 | age: 27, | |
416331ca | 160 | addr, |
8bb4bdeb XL |
161 | titles: vec!["programmer".to_string(), "cartographier".to_string()], |
162 | }; | |
163 | ||
164 | let addr2 = Address { | |
165 | city: "Beijing".to_string(), | |
166 | country: "China".to_string(), | |
167 | }; | |
168 | ||
169 | let person2 = Person { | |
170 | name: "Ning Sun".to_string(), | |
171 | age: 27, | |
172 | addr: addr2, | |
173 | titles: vec!["programmer".to_string(), "cartographier".to_string()], | |
174 | }; | |
175 | ||
176 | let people = vec![person, person2]; | |
177 | ||
178 | let mut handlebars = Registry::new(); | |
416331ca XL |
179 | assert!(handlebars |
180 | .register_template_string( | |
181 | "t0", | |
182 | "{{#each this}}{{#with addr}}{{city}}{{/with}}{{/each}}" | |
183 | ) | |
184 | .is_ok()); | |
185 | assert!(handlebars | |
186 | .register_template_string( | |
187 | "t1", | |
188 | "{{#each this}}{{#with addr}}{{../age}}{{/with}}{{/each}}" | |
189 | ) | |
190 | .is_ok()); | |
191 | assert!(handlebars | |
192 | .register_template_string( | |
193 | "t2", | |
194 | "{{#each this}}{{#with addr}}{{@../index}}{{/with}}{{/each}}" | |
195 | ) | |
196 | .is_ok()); | |
8bb4bdeb XL |
197 | |
198 | let r0 = handlebars.render("t0", &people); | |
199 | assert_eq!(r0.ok().unwrap(), "BeijingBeijing".to_string()); | |
200 | ||
201 | let r1 = handlebars.render("t1", &people); | |
202 | assert_eq!(r1.ok().unwrap(), "2727".to_string()); | |
203 | ||
204 | let r2 = handlebars.render("t2", &people); | |
205 | assert_eq!(r2.ok().unwrap(), "01".to_string()); | |
206 | } | |
207 | ||
208 | #[test] | |
209 | fn test_path_up() { | |
210 | let mut handlebars = Registry::new(); | |
416331ca XL |
211 | assert!(handlebars |
212 | .register_template_string("t0", "{{#with a}}{{#with b}}{{../../d}}{{/with}}{{/with}}") | |
213 | .is_ok()); | |
83c7162d | 214 | let data = btreemap! { |
8bb4bdeb XL |
215 | "a".to_string() => to_json(&btreemap! { |
216 | "b".to_string() => vec![btreemap!{"c".to_string() => vec![1]}] | |
217 | }), | |
9fa01778 | 218 | "d".to_string() => to_json(1) |
8bb4bdeb XL |
219 | }; |
220 | ||
221 | let r0 = handlebars.render("t0", &data); | |
222 | assert_eq!(r0.ok().unwrap(), "1".to_string()); | |
8bb4bdeb | 223 | } |
3dfed10e XL |
224 | |
225 | #[test] | |
226 | fn test_else_context() { | |
227 | let reg = Registry::new(); | |
228 | let template = "{{#with list}}A{{else}}{{foo}}{{/with}}"; | |
229 | let input = json!({"list": [], "foo": "bar"}); | |
230 | let rendered = reg.render_template(template, &input).unwrap(); | |
231 | assert_eq!("bar", rendered); | |
232 | } | |
233 | ||
234 | #[test] | |
235 | fn test_derived_value() { | |
236 | let hb = Registry::new(); | |
237 | let data = json!({"a": {"b": {"c": "d"}}}); | |
238 | let template = "{{#with (lookup a.b \"c\")}}{{this}}{{/with}}"; | |
239 | assert_eq!("d", hb.render_template(template, &data).unwrap()); | |
240 | } | |
241 | ||
242 | #[test] | |
243 | fn test_nested_derived_value() { | |
244 | let hb = Registry::new(); | |
245 | let data = json!({"a": {"b": {"c": "d"}}}); | |
246 | let template = "{{#with (lookup a \"b\")}}{{#with this}}{{c}}{{/with}}{{/with}}"; | |
247 | assert_eq!("d", hb.render_template(template, &data).unwrap()); | |
248 | } | |
94222f64 XL |
249 | |
250 | #[test] | |
251 | fn test_strict_with() { | |
252 | let mut hb = Registry::new(); | |
253 | ||
254 | assert_eq!( | |
255 | hb.render_template("{{#with name}}yes{{/with}}", &json!({})) | |
256 | .unwrap(), | |
257 | "" | |
258 | ); | |
259 | assert_eq!( | |
260 | hb.render_template("{{#with name}}yes{{else}}no{{/with}}", &json!({})) | |
261 | .unwrap(), | |
262 | "no" | |
263 | ); | |
264 | ||
265 | hb.set_strict_mode(true); | |
266 | ||
267 | assert!(hb | |
268 | .render_template("{{#with name}}yes{{/with}}", &json!({})) | |
269 | .is_err()); | |
270 | assert_eq!( | |
271 | hb.render_template("{{#with name}}yes{{else}}no{{/with}}", &json!({})) | |
272 | .unwrap(), | |
273 | "no" | |
274 | ); | |
275 | } | |
8bb4bdeb | 276 | } |