comparison markup/template.py @ 65:5c024cf58ecb

Support the use of directives as elements to reduce the need for using `py:strip`.
author cmlenz
date Sun, 09 Jul 2006 15:23:26 +0000
parents 33c2702cf6da
children 822089ae65ce
comparison
equal deleted inserted replaced
64:c612c73ae4ec 65:5c024cf58ecb
29 * py:match directives use (basic) XPath expressions to match against input 29 * py:match directives use (basic) XPath expressions to match against input
30 nodes, making match templates more powerful while keeping the syntax simple 30 nodes, making match templates more powerful while keeping the syntax simple
31 31
32 Todo items: 32 Todo items:
33 * Improved error reporting 33 * Improved error reporting
34 * Support for using directives as elements and not just as attributes, reducing
35 the need for wrapper elements with py:strip=""
36 * Support for list comprehensions and generator expressions in expressions 34 * Support for list comprehensions and generator expressions in expressions
37 35
38 Random thoughts: 36 Random thoughts:
39 * Is there any need to support py:extends and/or py:layout? 37 * Is there any need to support py:extends and/or py:layout?
40 * Could we generate byte code from expressions? 38 * Could we generate byte code from expressions?
307 </p> 305 </p>
308 </div> 306 </div>
309 """ 307 """
310 __slots__ = ['name', 'args', 'defaults', 'stream', 'directives'] 308 __slots__ = ['name', 'args', 'defaults', 'stream', 'directives']
311 309
310 ATTRIBUTE = 'function'
311
312 def __init__(self, args): 312 def __init__(self, args):
313 Directive.__init__(self, None) 313 Directive.__init__(self, None)
314 ast = compiler.parse(args, 'eval').node 314 ast = compiler.parse(args, 'eval').node
315 self.args = [] 315 self.args = []
316 self.defaults = {} 316 self.defaults = {}
361 <li>1</li><li>2</li><li>3</li> 361 <li>1</li><li>2</li><li>3</li>
362 </ul> 362 </ul>
363 """ 363 """
364 __slots__ = ['targets'] 364 __slots__ = ['targets']
365 365
366 ATTRIBUTE = 'each'
367
366 def __init__(self, value): 368 def __init__(self, value):
367 targets, value = value.split(' in ', 1) 369 targets, value = value.split(' in ', 1)
368 self.targets = [str(name.strip()) for name in targets.split(',')] 370 self.targets = [str(name.strip()) for name in targets.split(',')]
369 Directive.__init__(self, value) 371 Directive.__init__(self, value)
370 372
401 <b>Hello</b> 403 <b>Hello</b>
402 </div> 404 </div>
403 """ 405 """
404 __slots__ = [] 406 __slots__ = []
405 407
408 ATTRIBUTE = 'test'
409
406 def __call__(self, stream, ctxt, directives): 410 def __call__(self, stream, ctxt, directives):
407 if self.expr.evaluate(ctxt): 411 if self.expr.evaluate(ctxt):
408 return self._apply_directives(stream, ctxt, directives) 412 return self._apply_directives(stream, ctxt, directives)
409 return [] 413 return []
410 414
424 Hello Dude 428 Hello Dude
425 </span> 429 </span>
426 </div> 430 </div>
427 """ 431 """
428 __slots__ = ['path', 'stream'] 432 __slots__ = ['path', 'stream']
433
434 ATTRIBUTE = 'path'
429 435
430 def __init__(self, value): 436 def __init__(self, value):
431 Directive.__init__(self, None) 437 Directive.__init__(self, None)
432 self.path = Path(value) 438 self.path = Path(value)
433 self.stream = [] 439 self.stream = []
563 `py:when` or `py:otherwise` block. Behavior is also undefined if a 569 `py:when` or `py:otherwise` block. Behavior is also undefined if a
564 `py:otherwise` occurs before `py:when` blocks. 570 `py:otherwise` occurs before `py:when` blocks.
565 """ 571 """
566 __slots__ = ['matched', 'value'] 572 __slots__ = ['matched', 'value']
567 573
574 ATTRIBUTE = 'test'
575
568 def __call__(self, stream, ctxt, directives): 576 def __call__(self, stream, ctxt, directives):
569 if self.expr: 577 if self.expr:
570 self.value = self.expr.evaluate(ctxt) 578 self.value = self.expr.evaluate(ctxt)
571 self.matched = False 579 self.matched = False
572 ctxt.push(_choose=self) 580 ctxt.push(_choose=self)
579 """Implementation of the `py:when` directive for nesting in a parent with 587 """Implementation of the `py:when` directive for nesting in a parent with
580 the `py:choose` directive. 588 the `py:choose` directive.
581 589
582 See the documentation of `py:choose` for usage. 590 See the documentation of `py:choose` for usage.
583 """ 591 """
592
593 ATTRIBUTE = 'test'
594
584 def __call__(self, stream, ctxt, directives): 595 def __call__(self, stream, ctxt, directives):
585 choose = ctxt['_choose'] 596 choose = ctxt['_choose']
586 if choose.matched: 597 if choose.matched:
587 return [] 598 return []
588 value = self.expr.evaluate(ctxt) 599 value = self.expr.evaluate(ctxt)
685 696
686 elif kind is Stream.START: 697 elif kind is Stream.START:
687 # Record any directive attributes in start tags 698 # Record any directive attributes in start tags
688 tag, attrib = data 699 tag, attrib = data
689 directives = [] 700 directives = []
701 strip = False
702
703 if tag in self.NAMESPACE:
704 cls = self._dir_by_name.get(tag.localname)
705 if cls is None:
706 raise BadDirectiveError(tag, pos[0], pos[1])
707 directives.append(cls(attrib.get(getattr(cls, 'ATTRIBUTE', None), '')))
708 strip = True
709
690 new_attrib = [] 710 new_attrib = []
691 for name, value in attrib: 711 for name, value in attrib:
692 if name in self.NAMESPACE: 712 if name in self.NAMESPACE:
693 cls = self._dir_by_name.get(name.localname) 713 cls = self._dir_by_name.get(name.localname)
694 if cls is None: 714 if cls is None:
695 raise BadDirectiveError(name, self.filename, pos[1]) 715 raise BadDirectiveError(name, pos[0], pos[1])
696 else: 716 directives.append(cls(value))
697 directives.append(cls(value))
698 else: 717 else:
699 value = list(self._interpolate(value, *pos)) 718 value = list(self._interpolate(value, *pos))
700 new_attrib.append((name, value)) 719 new_attrib.append((name, value))
720
701 if directives: 721 if directives:
702 directives.sort(lambda a, b: cmp(self._dir_order.index(a.__class__), 722 directives.sort(lambda a, b: cmp(self._dir_order.index(a.__class__),
703 self._dir_order.index(b.__class__))) 723 self._dir_order.index(b.__class__)))
704 dirmap[(depth, tag)] = (directives, len(stream)) 724 dirmap[(depth, tag)] = (directives, len(stream), strip)
705 725
706 stream.append((kind, (tag, Attributes(new_attrib)), pos)) 726 stream.append((kind, (tag, Attributes(new_attrib)), pos))
707 depth += 1 727 depth += 1
708 728
709 elif kind is Stream.END: 729 elif kind is Stream.END:
711 stream.append((kind, data, pos)) 731 stream.append((kind, data, pos))
712 732
713 # If there have have directive attributes with the corresponding 733 # If there have have directive attributes with the corresponding
714 # start tag, move the events inbetween into a "subprogram" 734 # start tag, move the events inbetween into a "subprogram"
715 if (depth, data) in dirmap: 735 if (depth, data) in dirmap:
716 directives, start_offset = dirmap.pop((depth, data)) 736 directives, start_offset, strip = dirmap.pop((depth, data))
717 substream = stream[start_offset:] 737 substream = stream[start_offset:]
738 if strip:
739 substream = substream[1:-1]
718 stream[start_offset:] = [(Template.SUB, 740 stream[start_offset:] = [(Template.SUB,
719 (directives, substream), pos)] 741 (directives, substream), pos)]
720 742
721 elif kind is Stream.TEXT: 743 elif kind is Stream.TEXT:
722 for kind, data, pos in self._interpolate(data, *pos): 744 for kind, data, pos in self._interpolate(data, *pos):
Copyright (C) 2012-2017 Edgewall Software