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
Copyright (C) 2012-2017 Edgewall Software