|
| 1 | +pub mod common; |
1 | 2 | pub mod filters;
|
2 | 3 | pub mod tags;
|
3 | 4 | pub mod types;
|
4 | 5 |
|
5 | 6 | use std::borrow::Cow;
|
6 |
| -use std::collections::HashMap; |
7 | 7 |
|
8 | 8 | use pyo3::prelude::*;
|
9 | 9 |
|
10 |
| -use crate::error::{PyRenderError, RenderError}; |
11 |
| -use crate::parse::{TagElement, TokenTree}; |
12 |
| -use crate::types::Argument; |
13 |
| -use crate::types::ArgumentType; |
| 10 | +use crate::error::PyRenderError; |
14 | 11 | use crate::types::TemplateString;
|
15 |
| -use crate::types::Text; |
16 |
| -use crate::types::Variable; |
17 | 12 | use types::{Content, Context};
|
18 | 13 |
|
19 | 14 | pub type ResolveResult<'t, 'py> = Result<Option<Content<'t, 'py>>, PyRenderError>;
|
@@ -58,256 +53,3 @@ where
|
58 | 53 | }
|
59 | 54 | }
|
60 | 55 | }
|
61 |
| - |
62 |
| -impl Resolve for Variable { |
63 |
| - fn resolve<'t, 'py>( |
64 |
| - &self, |
65 |
| - py: Python<'py>, |
66 |
| - template: TemplateString<'t>, |
67 |
| - context: &mut Context, |
68 |
| - ) -> ResolveResult<'t, 'py> { |
69 |
| - let mut parts = self.parts(template); |
70 |
| - let (first, mut object_at) = parts.next().expect("Variable names cannot be empty"); |
71 |
| - let mut variable = match context.context.get(first) { |
72 |
| - Some(variable) => variable.bind(py).clone(), |
73 |
| - None => return Ok(None), |
74 |
| - }; |
75 |
| - |
76 |
| - for (part, key_at) in parts { |
77 |
| - variable = match variable.get_item(part) { |
78 |
| - Ok(variable) => variable, |
79 |
| - Err(_) => match variable.getattr(part) { |
80 |
| - Ok(variable) => variable, |
81 |
| - Err(_) => { |
82 |
| - let int = match part.parse::<usize>() { |
83 |
| - Ok(int) => int, |
84 |
| - Err(_) => { |
85 |
| - return Err(RenderError::VariableDoesNotExist { |
86 |
| - key: part.to_string(), |
87 |
| - object: variable.str()?.to_string(), |
88 |
| - key_at: key_at.into(), |
89 |
| - object_at: Some(object_at.into()), |
90 |
| - } |
91 |
| - .into()) |
92 |
| - } |
93 |
| - }; |
94 |
| - match variable.get_item(int) { |
95 |
| - Ok(variable) => variable, |
96 |
| - Err(_) => todo!(), |
97 |
| - } |
98 |
| - } |
99 |
| - }, |
100 |
| - }; |
101 |
| - object_at.1 += key_at.1 + 1; |
102 |
| - } |
103 |
| - Ok(Some(Content::Py(variable))) |
104 |
| - } |
105 |
| -} |
106 |
| - |
107 |
| -impl Resolve for Text { |
108 |
| - fn resolve<'t, 'py>( |
109 |
| - &self, |
110 |
| - _py: Python<'py>, |
111 |
| - template: TemplateString<'t>, |
112 |
| - context: &mut Context, |
113 |
| - ) -> ResolveResult<'t, 'py> { |
114 |
| - let resolved = Cow::Borrowed(template.content(self.at)); |
115 |
| - Ok(Some(match context.autoescape { |
116 |
| - false => Content::String(resolved), |
117 |
| - true => Content::HtmlSafe(resolved), |
118 |
| - })) |
119 |
| - } |
120 |
| -} |
121 |
| - |
122 |
| -impl Resolve for Argument { |
123 |
| - fn resolve<'t, 'py>( |
124 |
| - &self, |
125 |
| - py: Python<'py>, |
126 |
| - template: TemplateString<'t>, |
127 |
| - context: &mut Context, |
128 |
| - ) -> ResolveResult<'t, 'py> { |
129 |
| - Ok(Some(match &self.argument_type { |
130 |
| - ArgumentType::Text(text) => return text.resolve(py, template, context), |
131 |
| - ArgumentType::TranslatedText(_text) => todo!(), |
132 |
| - ArgumentType::Variable(variable) => match variable.resolve(py, template, context)? { |
133 |
| - Some(content) => content, |
134 |
| - None => { |
135 |
| - let key = template.content(variable.at).to_string(); |
136 |
| - let context: HashMap<&String, &Bound<'py, PyAny>> = context |
137 |
| - .context |
138 |
| - .iter() |
139 |
| - .map(|(k, v)| (k, v.bind(py))) |
140 |
| - .collect(); |
141 |
| - let object = format!("{:?}", context); |
142 |
| - return Err(RenderError::VariableDoesNotExist { |
143 |
| - key, |
144 |
| - object, |
145 |
| - key_at: variable.at.into(), |
146 |
| - object_at: None, |
147 |
| - } |
148 |
| - .into()); |
149 |
| - } |
150 |
| - }, |
151 |
| - ArgumentType::Float(number) => Content::Float(*number), |
152 |
| - ArgumentType::Int(number) => Content::Int(number.clone()), |
153 |
| - })) |
154 |
| - } |
155 |
| -} |
156 |
| - |
157 |
| -impl Resolve for TagElement { |
158 |
| - fn resolve<'t, 'py>( |
159 |
| - &self, |
160 |
| - py: Python<'py>, |
161 |
| - template: TemplateString<'t>, |
162 |
| - context: &mut Context, |
163 |
| - ) -> ResolveResult<'t, 'py> { |
164 |
| - match self { |
165 |
| - Self::Text(text) => text.resolve(py, template, context), |
166 |
| - Self::TranslatedText(_text) => todo!(), |
167 |
| - Self::Variable(variable) => variable.resolve(py, template, context), |
168 |
| - Self::Filter(filter) => filter.resolve(py, template, context), |
169 |
| - Self::Int(int) => Ok(Some(Content::Int(int.clone()))), |
170 |
| - Self::Float(float) => Ok(Some(Content::Float(*float))), |
171 |
| - } |
172 |
| - } |
173 |
| -} |
174 |
| - |
175 |
| -impl Render for TokenTree { |
176 |
| - fn render<'t>( |
177 |
| - &self, |
178 |
| - py: Python<'_>, |
179 |
| - template: TemplateString<'t>, |
180 |
| - context: &mut Context, |
181 |
| - ) -> RenderResult<'t> { |
182 |
| - match self { |
183 |
| - Self::Text(text) => text.render(py, template, context), |
184 |
| - Self::TranslatedText(_text) => todo!(), |
185 |
| - Self::Tag(tag) => tag.render(py, template, context), |
186 |
| - Self::Variable(variable) => variable.render(py, template, context), |
187 |
| - Self::Filter(filter) => filter.render(py, template, context), |
188 |
| - } |
189 |
| - } |
190 |
| -} |
191 |
| - |
192 |
| -#[cfg(test)] |
193 |
| -mod tests { |
194 |
| - use super::*; |
195 |
| - |
196 |
| - use pyo3::types::{PyDict, PyList, PyString}; |
197 |
| - |
198 |
| - #[test] |
199 |
| - fn test_render_variable() { |
200 |
| - pyo3::prepare_freethreaded_python(); |
201 |
| - |
202 |
| - Python::with_gil(|py| { |
203 |
| - let name = PyString::new(py, "Lily").into_any(); |
204 |
| - let context = HashMap::from([("name".to_string(), name.unbind())]); |
205 |
| - let mut context = Context { |
206 |
| - context, |
207 |
| - request: None, |
208 |
| - autoescape: false, |
209 |
| - }; |
210 |
| - let template = TemplateString("{{ name }}"); |
211 |
| - let variable = Variable::new((3, 4)); |
212 |
| - |
213 |
| - let rendered = variable.render(py, template, &mut context).unwrap(); |
214 |
| - assert_eq!(rendered, "Lily"); |
215 |
| - }) |
216 |
| - } |
217 |
| - |
218 |
| - #[test] |
219 |
| - fn test_render_dict_lookup() { |
220 |
| - pyo3::prepare_freethreaded_python(); |
221 |
| - |
222 |
| - Python::with_gil(|py| { |
223 |
| - let data = PyDict::new(py); |
224 |
| - let name = PyString::new(py, "Lily"); |
225 |
| - data.set_item("name", name).unwrap(); |
226 |
| - let context = HashMap::from([("data".to_string(), data.into_any().unbind())]); |
227 |
| - let mut context = Context { |
228 |
| - context, |
229 |
| - request: None, |
230 |
| - autoescape: false, |
231 |
| - }; |
232 |
| - let template = TemplateString("{{ data.name }}"); |
233 |
| - let variable = Variable::new((3, 9)); |
234 |
| - |
235 |
| - let rendered = variable.render(py, template, &mut context).unwrap(); |
236 |
| - assert_eq!(rendered, "Lily"); |
237 |
| - }) |
238 |
| - } |
239 |
| - |
240 |
| - #[test] |
241 |
| - fn test_render_list_lookup() { |
242 |
| - pyo3::prepare_freethreaded_python(); |
243 |
| - |
244 |
| - Python::with_gil(|py| { |
245 |
| - let name = PyString::new(py, "Lily"); |
246 |
| - let names = PyList::new(py, [name]).unwrap(); |
247 |
| - let context = HashMap::from([("names".to_string(), names.into_any().unbind())]); |
248 |
| - let mut context = Context { |
249 |
| - context, |
250 |
| - request: None, |
251 |
| - autoescape: false, |
252 |
| - }; |
253 |
| - let template = TemplateString("{{ names.0 }}"); |
254 |
| - let variable = Variable::new((3, 7)); |
255 |
| - |
256 |
| - let rendered = variable.render(py, template, &mut context).unwrap(); |
257 |
| - assert_eq!(rendered, "Lily"); |
258 |
| - }) |
259 |
| - } |
260 |
| - |
261 |
| - #[test] |
262 |
| - fn test_render_attribute_lookup() { |
263 |
| - pyo3::prepare_freethreaded_python(); |
264 |
| - |
265 |
| - Python::with_gil(|py| { |
266 |
| - let locals = PyDict::new(py); |
267 |
| - py.run( |
268 |
| - c" |
269 |
| -class User: |
270 |
| - def __init__(self, name): |
271 |
| - self.name = name |
272 |
| -
|
273 |
| -user = User('Lily') |
274 |
| -", |
275 |
| - None, |
276 |
| - Some(&locals), |
277 |
| - ) |
278 |
| - .unwrap(); |
279 |
| - |
280 |
| - let context = locals.extract().unwrap(); |
281 |
| - let mut context = Context { |
282 |
| - context, |
283 |
| - request: None, |
284 |
| - autoescape: false, |
285 |
| - }; |
286 |
| - let template = TemplateString("{{ user.name }}"); |
287 |
| - let variable = Variable::new((3, 9)); |
288 |
| - |
289 |
| - let rendered = variable.render(py, template, &mut context).unwrap(); |
290 |
| - assert_eq!(rendered, "Lily"); |
291 |
| - }) |
292 |
| - } |
293 |
| - |
294 |
| - #[test] |
295 |
| - fn test_render_html_autoescape() { |
296 |
| - pyo3::prepare_freethreaded_python(); |
297 |
| - |
298 |
| - Python::with_gil(|py| { |
299 |
| - let html = PyString::new(py, "<p>Hello World!</p>").into_any().unbind(); |
300 |
| - let context = HashMap::from([("html".to_string(), html)]); |
301 |
| - let mut context = Context { |
302 |
| - context, |
303 |
| - request: None, |
304 |
| - autoescape: true, |
305 |
| - }; |
306 |
| - let template = TemplateString("{{ html }}"); |
307 |
| - let html = Variable::new((3, 4)); |
308 |
| - |
309 |
| - let rendered = html.render(py, template, &mut context).unwrap(); |
310 |
| - assert_eq!(rendered, "<p>Hello World!</p>"); |
311 |
| - }) |
312 |
| - } |
313 |
| -} |
0 commit comments