rustache/build.rs
1use std::collections::HashMap;
2use std::convert::Into;
3
4use Data;
5use Data::{Hash, Vector};
6
7/// `HashBuilder` is a helper type that constructs `Data` types in a `HashMap`
8#[derive(Debug)]
9pub struct HashBuilder<'a> {
10 #[doc(hidden)]
11 pub data: HashMap<String, Data<'a>>,
12 #[doc(hidden)]
13 pub partials_path: &'a str,
14}
15
16impl<'a> HashBuilder<'a> {
17 /// Create a new `HashBuilder` instance
18 pub fn new() -> HashBuilder<'a> {
19 HashBuilder {
20 data: HashMap::new(),
21 partials_path: "",
22 }
23 }
24
25 /// Add a `Into<Data>` to the `HashBuilder`
26 ///
27 /// ```rust
28 /// use rustache::HashBuilder;
29 /// use std::convert::Into;
30 /// let data = HashBuilder::new()
31 /// .insert("game", "Hearthstone: Heroes of Warcraft");
32 /// ```
33 /// ```rust
34 /// use rustache::{HashBuilder, VecBuilder};
35 /// let data = HashBuilder::new()
36 /// .insert("classes",
37 /// VecBuilder::new()
38 /// .push("Mage".to_string())
39 /// .push("Druid".to_string())
40 /// );
41 /// ```
42 /// ```rust
43 /// use rustache::HashBuilder;
44 /// let data = HashBuilder::new()
45 /// .insert("hero1",
46 /// HashBuilder::new()
47 /// .insert("first_name", "Anduin")
48 /// .insert("last_name", "Wrynn")
49 /// )
50 /// .insert("hero2",
51 /// HashBuilder::new()
52 /// .insert("first_name", "Jaina")
53 /// .insert("last_name", "Proudmoore")
54 /// );
55 /// ```
56 pub fn insert<K, V>(mut self, key: K, value: V) -> HashBuilder<'a>
57 where K: ToString,
58 V: Into<Data<'a>>
59 {
60 self.data.insert(key.to_string(), value.into());
61 self
62 }
63
64 /// Add a `Lambda` that accepts a String and returns a String to the `HashBuilder`
65 ///
66 /// ```rust
67 /// use rustache::HashBuilder;
68 /// let mut f = |_| { "world".to_string() };
69 /// let data = HashBuilder::new()
70 /// .insert_lambda("lambda", &mut f);
71 /// ```
72 pub fn insert_lambda<K: ToString>(self,
73 key: K,
74 f: &'a mut FnMut(String) -> String)
75 -> HashBuilder<'a> {
76 self.insert(key, f)
77 }
78
79 /// Set a path to partials data
80 pub fn set_partials_path(self, path: &'a str) -> HashBuilder<'a> {
81 HashBuilder {
82 data: self.data,
83 partials_path: path,
84 }
85 }
86
87 /// Return the built `Data`
88 fn build(self) -> Data<'a> {
89 Hash(self.data)
90 }
91}
92
93impl<'a> From<HashBuilder<'a>> for Data<'a> {
94 fn from(v: HashBuilder<'a>) -> Data<'a> {
95 v.build()
96 }
97}
98
99/// `VecBuilder` is a helper type that constructs `Data` types in a Vector
100pub struct VecBuilder<'a> {
101 data: Vec<Data<'a>>,
102}
103
104impl<'a> VecBuilder<'a> {
105 /// Create a new `VecBuilder` instance
106 pub fn new() -> VecBuilder<'a> {
107 VecBuilder { data: Vec::new() }
108 }
109
110 /// Add a `Into<Data>` to the `VecBuilder`
111 ///
112 /// ```rust
113 /// use rustache::VecBuilder;
114 /// use std::convert::Into;
115 /// let data = VecBuilder::new()
116 /// .push("Mage")
117 /// .push("Druid");
118 /// ```
119 /// ```rust
120 /// use rustache::VecBuilder;
121 /// let data = VecBuilder::new()
122 /// .push(VecBuilder::new()
123 /// .push("Anduin Wrynn".to_string())
124 /// .push("Jaina Proudmoore".to_string())
125 /// );
126 /// ```
127 /// ```rust
128 /// use rustache::{HashBuilder, VecBuilder};
129 /// let data = VecBuilder::new()
130 /// .push(HashBuilder::new()
131 /// .insert("first_name".to_string(), "Garrosh".to_string())
132 /// .insert("last_name".to_string(), "Hellscream".to_string())
133 /// )
134 /// .push(HashBuilder::new()
135 /// .insert("first_name".to_string(), "Malfurion".to_string())
136 /// .insert("last_name".to_string(), "Stormrage".to_string())
137 /// );
138 /// ```
139 pub fn push<V>(mut self, value: V) -> VecBuilder<'a>
140 where V: Into<Data<'a>>
141 {
142 self.data.push(value.into());
143 self
144 }
145
146 /// Add a `Lambda` to the `VecBuilder`
147 ///
148 /// ```rust
149 /// use rustache::VecBuilder;
150 /// let mut f = |_| { "world".to_string() };
151 /// let data = VecBuilder::new()
152 /// .push_lambda(&mut f);
153 /// ```
154 pub fn push_lambda(self, f: &'a mut FnMut(String) -> String) -> VecBuilder<'a> {
155 self.push(f)
156 }
157
158 /// Return the built `Data`
159 fn build(self) -> Data<'a> {
160 Vector(self.data)
161 }
162}
163
164impl<'a> From<VecBuilder<'a>> for Data<'a> {
165 fn from(v: VecBuilder<'a>) -> Data<'a> {
166 v.build()
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use std::collections::HashMap;
173
174 use {HashBuilder, VecBuilder};
175 use Data::{Strng, Bool, Integer, Float, Vector, Hash, Lambda};
176
177 #[test]
178 fn test_new_builders() {
179 assert_eq!(HashBuilder::new().build(), Hash(HashMap::new()));
180 assert_eq!(VecBuilder::new().build(), Vector(Vec::new()));
181 }
182
183 #[test]
184 fn test_set_partials_path() {
185 let hash = HashBuilder::new().set_partials_path("/path");
186 assert_eq!(hash.partials_path, "/path");
187 }
188
189 #[test]
190 fn test_builders() {
191 let test_string = String::from("Conan the Sorcerian");
192
193 let mut hearthstone = HashMap::new();
194 hearthstone.insert("name".to_string(),
195 Strng("Hearthstone: Heroes of Warcraft".to_string()));
196 hearthstone.insert("release_date".to_string(),
197 Strng("December, 2014".to_string()));
198
199 let mut hash1 = HashMap::new();
200 hash1.insert("first_name".to_string(), Strng("Anduin".to_string()));
201 hash1.insert("last_name".to_string(), Strng("Wrynn".to_string()));
202 hash1.insert("age".to_string(), Integer(21i32));
203 hash1.insert("weight".to_string(), Float(120.16f64));
204 hash1.insert("class".to_string(), Strng("Priest".to_string()));
205 hash1.insert("died".to_string(), Bool(false));
206 hash1.insert("class_cards".to_string(),
207 Vector(vec![Strng(test_string.clone()),
208 Strng("Prophet Velen".to_string()),
209 Hash(hearthstone)]));
210
211 let hash2 = HashBuilder::new()
212 .set_partials_path("/hearthstone")
213 .insert("first_name", "Anduin")
214 .insert("last_name", "Wrynn")
215 .insert("age", 21i32)
216 .insert("weight", 120.16f64)
217 .insert("class", "Priest")
218 .insert("died", false)
219 .insert("class_cards",
220 VecBuilder::new()
221 .push(test_string)
222 .push("Prophet Velen")
223 .push(HashBuilder::new()
224 .insert("name", "Hearthstone: Heroes of Warcraft")
225 .insert("release_date", "December, 2014")));
226
227 assert_eq!(Hash(hash1), Hash(hash2.data));
228 assert_eq!(hash2.partials_path, "/hearthstone");
229 }
230
231 // #[test]
232 // fn test_hash_lambda_builder() {
233 // // Since we can't directly compare closures, just make
234 // // sure we're threading through the builder
235
236 // let mut num = 10u;
237 // let data = HashBuilder::new()
238 // .insert_lambda("double", |x| {
239 // num *= 2u;
240 // x + num.to_string()
241 // })
242 // .build();
243
244 // match data {
245 // Hash(m) => {
246 // match *m.find_equiv(&("double")).unwrap() {
247 // Lambda(ref f) => {
248 // let f = &mut *f.borrow_mut();
249 // assert_eq!((*f)("double: ".to_string()), "double: 20".to_string());
250 // assert_eq!((*f)("double: ".to_string()), "double: 40".to_string());
251 // assert_eq!((*f)("double: ".to_string()), "double: 80".to_string());
252 // }
253 // _ => panic!(),
254 // }
255 // }
256 // _ => panic!(),
257 // }
258 // }
259
260 #[test]
261 fn test_vec_lambda_builder() {
262 // Since we can't directly compare closures, just make
263 // sure we're threading through the builder
264
265 let mut num = 10u32;
266 let mut f = |x: String| -> String {
267 num *= 2u32;
268 x + &num.to_string()[..]
269 };
270 let data = VecBuilder::new()
271 .push_lambda(&mut f)
272 .build();
273
274 match data {
275 Vector(m) => {
276 match m[0] {
277 Lambda(ref f) => {
278 let f = &mut *f.borrow_mut();
279 assert_eq!((*f)("double: ".to_string()), "double: 20".to_string());
280 assert_eq!((*f)("double: ".to_string()), "double: 40".to_string());
281 assert_eq!((*f)("double: ".to_string()), "double: 80".to_string());
282 }
283 _ => panic!(),
284 }
285 }
286 _ => panic!(),
287 }
288 }
289}