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 /// The data contained within
102 pub data: Vec<Data<'a>>,
103}
104
105impl<'a> VecBuilder<'a> {
106 /// Create a new `VecBuilder` instance
107 pub fn new() -> VecBuilder<'a> {
108 VecBuilder { data: Vec::new() }
109 }
110
111 /// Add a `Into<Data>` to the `VecBuilder`
112 ///
113 /// ```rust
114 /// use rustache::VecBuilder;
115 /// use std::convert::Into;
116 /// let data = VecBuilder::new()
117 /// .push("Mage")
118 /// .push("Druid");
119 /// ```
120 /// ```rust
121 /// use rustache::VecBuilder;
122 /// let data = VecBuilder::new()
123 /// .push(VecBuilder::new()
124 /// .push("Anduin Wrynn".to_string())
125 /// .push("Jaina Proudmoore".to_string())
126 /// );
127 /// ```
128 /// ```rust
129 /// use rustache::{HashBuilder, VecBuilder};
130 /// let data = VecBuilder::new()
131 /// .push(HashBuilder::new()
132 /// .insert("first_name".to_string(), "Garrosh".to_string())
133 /// .insert("last_name".to_string(), "Hellscream".to_string())
134 /// )
135 /// .push(HashBuilder::new()
136 /// .insert("first_name".to_string(), "Malfurion".to_string())
137 /// .insert("last_name".to_string(), "Stormrage".to_string())
138 /// );
139 /// ```
140 pub fn push<V>(mut self, value: V) -> VecBuilder<'a>
141 where V: Into<Data<'a>>
142 {
143 self.data.push(value.into());
144 self
145 }
146
147 /// Add a `Lambda` to the `VecBuilder`
148 ///
149 /// ```rust
150 /// use rustache::VecBuilder;
151 /// let mut f = |_| { "world".to_string() };
152 /// let data = VecBuilder::new()
153 /// .push_lambda(&mut f);
154 /// ```
155 pub fn push_lambda(self, f: &'a mut FnMut(String) -> String) -> VecBuilder<'a> {
156 self.push(f)
157 }
158
159 /// Return the built `Data`
160 fn build(self) -> Data<'a> {
161 Vector(self.data)
162 }
163}
164
165impl<'a> From<VecBuilder<'a>> for Data<'a> {
166 fn from(v: VecBuilder<'a>) -> Data<'a> {
167 v.build()
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use std::collections::HashMap;
174
175 use {HashBuilder, VecBuilder};
176 use Data;
177 use Data::{Bool, Integer, Float, Vector, Hash, Lambda};
178
179 #[test]
180 fn test_new_builders() {
181 assert_eq!(HashBuilder::new().build(), Hash(HashMap::new()));
182 assert_eq!(VecBuilder::new().build(), Vector(Vec::new()));
183 }
184
185 #[test]
186 fn test_set_partials_path() {
187 let hash = HashBuilder::new().set_partials_path("/path");
188 assert_eq!(hash.partials_path, "/path");
189 }
190
191 #[test]
192 fn test_builders() {
193 let test_string = String::from("Conan the Sorcerian");
194
195 let mut hearthstone = HashMap::new();
196 hearthstone.insert("name".to_string(),
197 Data::String("Hearthstone: Heroes of Warcraft".to_string()));
198 hearthstone.insert("release_date".to_string(),
199 Data::String("December, 2014".to_string()));
200
201 let mut hash1 = HashMap::new();
202 hash1.insert("first_name".to_string(), Data::String("Anduin".to_string()));
203 hash1.insert("last_name".to_string(), Data::String("Wrynn".to_string()));
204 hash1.insert("age".to_string(), Integer(21i32));
205 hash1.insert("weight".to_string(), Float(120.16f64));
206 hash1.insert("class".to_string(), Data::String("Priest".to_string()));
207 hash1.insert("died".to_string(), Bool(false));
208 hash1.insert("class_cards".to_string(),
209 Vector(vec![Data::String(test_string.clone()),
210 Data::String("Prophet Velen".to_string()),
211 Hash(hearthstone)]));
212
213 let hash2 = HashBuilder::new()
214 .set_partials_path("/hearthstone")
215 .insert("first_name", "Anduin")
216 .insert("last_name", "Wrynn")
217 .insert("age", 21i32)
218 .insert("weight", 120.16f64)
219 .insert("class", "Priest")
220 .insert("died", false)
221 .insert("class_cards",
222 VecBuilder::new()
223 .push(test_string)
224 .push("Prophet Velen")
225 .push(HashBuilder::new()
226 .insert("name", "Hearthstone: Heroes of Warcraft")
227 .insert("release_date", "December, 2014")));
228
229 assert_eq!(Hash(hash1), Hash(hash2.data));
230 assert_eq!(hash2.partials_path, "/hearthstone");
231 }
232
233 // #[test]
234 // fn test_hash_lambda_builder() {
235 // // Since we can't directly compare closures, just make
236 // // sure we're threading through the builder
237
238 // let mut num = 10u;
239 // let data = HashBuilder::new()
240 // .insert_lambda("double", |x| {
241 // num *= 2u;
242 // x + num.to_string()
243 // })
244 // .build();
245
246 // match data {
247 // Hash(m) => {
248 // match *m.find_equiv(&("double")).unwrap() {
249 // Lambda(ref f) => {
250 // let f = &mut *f.borrow_mut();
251 // assert_eq!((*f)("double: ".to_string()), "double: 20".to_string());
252 // assert_eq!((*f)("double: ".to_string()), "double: 40".to_string());
253 // assert_eq!((*f)("double: ".to_string()), "double: 80".to_string());
254 // }
255 // _ => panic!(),
256 // }
257 // }
258 // _ => panic!(),
259 // }
260 // }
261
262 #[test]
263 fn test_vec_lambda_builder() {
264 // Since we can't directly compare closures, just make
265 // sure we're threading through the builder
266
267 let mut num = 10u32;
268 let mut f = |x: String| -> String {
269 num *= 2u32;
270 x + &num.to_string()[..]
271 };
272 let data = VecBuilder::new()
273 .push_lambda(&mut f)
274 .build();
275
276 match data {
277 Vector(m) => {
278 match m[0] {
279 Lambda(ref f) => {
280 let f = &mut *f.borrow_mut();
281 assert_eq!((*f)("double: ".to_string()), "double: 20".to_string());
282 assert_eq!((*f)("double: ".to_string()), "double: 40".to_string());
283 assert_eq!((*f)("double: ".to_string()), "double: 80".to_string());
284 }
285 _ => panic!(),
286 }
287 }
288 _ => panic!(),
289 }
290 }
291}