Mercurial > genshi > genshi-test
comparison genshi/template/inline.py @ 905:bf20de18289c experimental-inline
inline branch: added preliminary implementation of compiled `py:attrs` directive.
author | cmlenz |
---|---|
date | Wed, 28 Apr 2010 21:29:14 +0000 |
parents | 95d62e239f60 |
children |
comparison
equal
deleted
inserted
replaced
903:95d62e239f60 | 905:bf20de18289c |
---|---|
11 # individuals. For the exact contribution history, see the revision | 11 # individuals. For the exact contribution history, see the revision |
12 # history and logs, available at http://genshi.edgewall.org/log/. | 12 # history and logs, available at http://genshi.edgewall.org/log/. |
13 | 13 |
14 import imp | 14 import imp |
15 | 15 |
16 from genshi.core import Attrs, Stream, _ensure, START, END, TEXT | 16 from genshi.core import Attrs, Stream, QName, _ensure, START, END, TEXT |
17 from genshi.template.astutil import _ast | 17 from genshi.template.astutil import _ast |
18 from genshi.template.base import EXEC, EXPR, SUB | 18 from genshi.template.base import EXEC, EXPR, SUB |
19 from genshi.template.directives import * | 19 from genshi.template.directives import * |
20 | 20 |
21 | 21 |
52 yield event | 52 yield event |
53 else: | 53 else: |
54 yield TEXT, unicode(obj), pos | 54 yield TEXT, unicode(obj), pos |
55 | 55 |
56 | 56 |
57 def _expand_attrs(obj): | |
58 if obj: | |
59 if isinstance(obj, Stream): | |
60 try: | |
61 obj = iter(obj).next() | |
62 except StopIteration: | |
63 obj = [] | |
64 elif not isinstance(obj, list): # assume it's a dict | |
65 obj = obj.items() | |
66 return [(QName(name), unicode(val).strip()) for name, val | |
67 in obj if val is not None] | |
68 return [] | |
69 | |
70 | |
57 def _expand_text(obj): | 71 def _expand_text(obj): |
58 if obj is not None: | 72 if obj is not None: |
59 if isinstance(obj, basestring): | 73 if isinstance(obj, basestring): |
60 return [obj] | 74 return [obj] |
61 elif isinstance(obj, (int, float, long)): | 75 elif isinstance(obj, (int, float, long)): |
85 yield w('from genshi.core import Attrs, QName') | 99 yield w('from genshi.core import Attrs, QName') |
86 yield w('from genshi.core import START, START_CDATA, START_NS, END, ' | 100 yield w('from genshi.core import START, START_CDATA, START_NS, END, ' |
87 'END_CDATA, END_NS, DOCTYPE, TEXT') | 101 'END_CDATA, END_NS, DOCTYPE, TEXT') |
88 yield w('from genshi.path import Path') | 102 yield w('from genshi.path import Path') |
89 yield w('from genshi.template.eval import Expression, Suite') | 103 yield w('from genshi.template.eval import Expression, Suite') |
90 yield w('from genshi.template.inline import _expand, _expand_text') | 104 yield w('from genshi.template.inline import _expand, _expand_attrs, _expand_text') |
91 yield w() | 105 yield w() |
92 | 106 |
93 def _declare_vars(stream): | 107 def _declare_vars(stream): |
94 for kind, data, pos in stream: | 108 for kind, data, pos in stream: |
95 | 109 |
147 yield line | 161 yield line |
148 yield w('pop()') | 162 yield w('pop()') |
149 w.unshift() | 163 w.unshift() |
150 | 164 |
151 # Recursively apply directives | 165 # Recursively apply directives |
152 def _apply(directives, stream): | 166 def _apply(directives, stream, **kwargs): |
153 if not directives: | 167 if not directives: |
154 for line in _generate(stream): | 168 for line in _generate(stream, **kwargs): |
155 yield line | 169 yield line |
156 return | 170 return |
157 | 171 |
158 d = directives[0] | 172 d = directives[0] |
159 rest = directives[1:] | 173 rest = directives[1:] |
188 else: | 202 else: |
189 yield w('strip.append(e[%d].evaluate(ctxt))', | 203 yield w('strip.append(e[%d].evaluate(ctxt))', |
190 index['E'][d.expr]) | 204 index['E'][d.expr]) |
191 yield w('if not strip[-1]:') | 205 yield w('if not strip[-1]:') |
192 w.shift() | 206 w.shift() |
193 for line in _generate([stream[0]]): | 207 for line in _generate([stream[0]], **kwargs): |
194 yield line | 208 yield line |
195 w.unshift() | 209 w.unshift() |
196 for line in _apply(rest, stream[1:-2]): | 210 for line in _apply(rest, stream[1:-2]): |
197 yield line | 211 yield line |
198 yield w('if not strip[-1]:') | 212 yield w('if not strip[-1]:') |
199 w.shift() | 213 w.shift() |
200 for line in _generate([stream[-1]]): | 214 for line in _generate([stream[-1]], **kwargs): |
201 yield line | 215 yield line |
202 w.unshift() | 216 w.unshift() |
203 yield w('strip.pop(-1)') | 217 yield w('strip.pop(-1)') |
204 | 218 |
205 elif isinstance(d, WithDirective): | 219 elif isinstance(d, WithDirective): |
212 for line in _apply(rest, stream): | 226 for line in _apply(rest, stream): |
213 yield line | 227 yield line |
214 yield w('pop()') | 228 yield w('pop()') |
215 | 229 |
216 elif isinstance(d, ContentDirective): | 230 elif isinstance(d, ContentDirective): |
217 for line in _generate([stream[0]]): | 231 for line in _generate([stream[0]], **kwargs): |
218 yield line | 232 yield line |
219 yield w('for v in e[%d].evaluate(ctxt): yield v', index['E'][d.expr]) | 233 yield w('for v in e[%d].evaluate(ctxt): yield v', index['E'][d.expr]) |
220 for line in _generate([stream[-1]]): | 234 for line in _generate([stream[-1]], **kwargs): |
221 yield line | 235 yield line |
222 | 236 |
223 elif isinstance(d, ReplaceDirective): | 237 elif isinstance(d, ReplaceDirective): |
224 yield w('for v in e[%d].evaluate(ctxt): yield v', index['E'][d.expr]) | 238 yield w('for v in e[%d].evaluate(ctxt): yield v', index['E'][d.expr]) |
225 | 239 |
240 elif isinstance(d, AttrsDirective): | |
241 for line in _apply(rest, stream, attrs_expr=d.expr): | |
242 yield line | |
243 | |
226 else: | 244 else: |
227 raise NotImplementedError, '%r directive not supported' % d.tagname | 245 raise NotImplementedError, '%r directive not supported' % d.tagname |
228 | 246 |
229 yield w() | 247 yield w() |
230 | 248 |
231 # Generate code for the given template stream | 249 # Generate code for the given template stream |
232 def _generate(stream): | 250 def _generate(stream, attrs_expr=None): |
233 for kind, data, pos in stream: | 251 for kind, data, pos in stream: |
234 | 252 |
235 if kind is EXPR: | 253 if kind is EXPR: |
236 yield w('for evt in _expand(e[%d].evaluate(ctxt), (f, %d, %d)): yield evt', | 254 yield w('for evt in _expand(e[%d].evaluate(ctxt), (f, %d, %d)): yield evt', |
237 index['E'][data], *pos[1:]) | 255 index['E'][data], *pos[1:]) |
261 yield w('(q[%d], [v for v in %s if v is not None]),' % ( | 279 yield w('(q[%d], [v for v in %s if v is not None]),' % ( |
262 index['Q'][name], ' + '.join(values) | 280 index['Q'][name], ' + '.join(values) |
263 )) | 281 )) |
264 w.unshift() | 282 w.unshift() |
265 yield w(']) if av]') | 283 yield w(']) if av]') |
266 yield w('yield START, (q[%d], a[%d] | at), (f, %d, %d)', qn, at, | 284 yield w('yield START, (q[%d], a[%d] | at%s), (f, %d, %d)', qn, at, |
285 attrs_expr and ' | _expand_attrs(e[%d].evaluate(ctxt))' % index['E'][attrs_expr] or '', | |
267 *pos[1:]) | 286 *pos[1:]) |
268 else: | 287 else: |
269 yield w('yield START, (q[%d], a[%d]), (f, %d, %d)', qn, at, *pos[1:]) | 288 yield w('yield START, (q[%d], a[%d]%s), (f, %d, %d)', qn, at, |
289 attrs_expr and ' | _expand_attrs(e[%d].evaluate(ctxt))' % index['E'][attrs_expr] or '', | |
290 *pos[1:]) | |
270 | 291 |
271 elif kind is END: | 292 elif kind is END: |
272 yield w('yield END, q[%d], (f, %d, %d)', index['Q'][data], *pos[1:]) | 293 yield w('yield END, q[%d], (f, %d, %d)', index['Q'][data], *pos[1:]) |
273 | 294 |
274 elif kind is SUB: | 295 elif kind is SUB: |
337 ${sayhi()} | 358 ${sayhi()} |
338 <ul py:if="items"> | 359 <ul py:if="items"> |
339 <li py:for="idx, item in enumerate(items)" | 360 <li py:for="idx, item in enumerate(items)" |
340 class="${idx % 2 and 'odd' or 'even'}" | 361 class="${idx % 2 and 'odd' or 'even'}" |
341 py:with="num=item + 1"> | 362 py:with="num=item + 1"> |
342 <span py:replace="num">NUM</span> | 363 <span py:if="num % 2" py:replace="num">NUM</span> |
343 </li> | 364 </li> |
344 </ul> | 365 </ul> |
345 </body> | 366 </body> |
346 </html>""" | 367 </html>""" |
347 | 368 |