Edgewall Software

Ticket #396: select_added_too_late.patch

File select_added_too_late.patch, 9.9 KB (added by Carsten Klein <carsten.klein@…>, 6 years ago)
  • genshi/template/inline.py

     
    7979    return '{%s}' % ', '.join(buf)
    8080
    8181
     82# represents basically a symbol table
     83class Context(object):
     84
     85    def __init__(self):
     86        self.qnames = []
     87        self.attributes = {}
     88        self.expressions = []
     89        self.macros = {}
     90        self.paths = []
     91        self.suites = []
     92        self.variables = {}
     93        self.last_event = None
     94
     95    def declare_attr(self, qname, value):
     96        pass
     97
     98    def declare_expression(self, expr):
     99        pass
     100
     101    def declare_macro(self, name, macro):
     102        pass
     103
     104    def declare_path(self, path):
     105        pass
     106
     107    def declare_qname(self, qname):
     108        pass
     109
     110    def declare_suite(self, suite):
     111        pass
     112
     113    def declare_variable(self, name, expr):
     114        pass
     115
     116
     117# Stream
     118class StreamProcessor(object):
     119
     120    def __init__(self):
     121        self.visitors = []
     122        self.visitors.append(EndEventVisitor())
     123        self.visitors.append(ExecEventVisitor())
     124        self.visitors.append(IncludeEventVisitor())
     125        self.visitors.append(StartEventVisitor())
     126        self.visitors.append(SubstreamEventVisitor())
     127
     128    def process(self, stream, context):
     129        for kind, data, pos in stream:
     130            context.last_event = (kind, data, pos)
     131            for visitor in visitors:
     132                if visitor.can_visit(kind):
     133                    visitor.visit(kind, data, pos, context)
     134                    break
     135
     136
     137# Stream Events
     138class StreamEventVisitor(object):
     139
     140    #@abstractmethod
     141    def can_visit(self, kind):
     142        pass
     143
     144    #@abstractmethod
     145    def visit(self, kind, data, pos, context):
     146        pass
     147
     148
     149class EndEventVisitor(StreamEventVisitor):
     150
     151    def can_visit(self, kind):
     152        return kind is END
     153
     154    def visit(self, kind, data, pos, context):
     155        pass
     156
     157
     158class ExecEventVisitor(StreamEventVisitor):
     159
     160    def can_visit(self, kind):
     161        return kind is EXEC
     162
     163    def visit(self, kind, data, pos, context):
     164        pass
     165
     166
     167class IncludeEventVisitor(StreamEventVisitor):
     168
     169    def can_visit(self, kind):
     170        return kind is INCLUDE
     171
     172    def visit(self, kind, data, pos, context):
     173        pass
     174
     175
     176class StartEventVisitor(StreamEventVisitor):
     177
     178    def can_visit(self, kind):
     179        return kind is START
     180
     181    def visit(self, kind, data, pos, context):
     182        pass
     183
     184
     185class SubstreamEventVisitor(StreamEventVisitor):
     186
     187    def __init__(self):
     188        self.visitors = []
     189        self.visitors.append(AttrsDirectiveVisitor())
     190        self.visitors.append(ChooseDirectiveVisitor())
     191        self.visitors.append(ContentDirectiveVisitor())
     192        self.visitors.append(DefDirectiveVisitor())
     193        self.visitors.append(ForDirectiveVisitor())
     194        self.visitors.append(IfDirectiveVisitor())
     195        self.visitors.append(MatchDirectiveVisitor())
     196        self.visitors.append(OtherwiseDirectiveVisitor())
     197        self.visitors.append(ReplaceDirectiveVisitor())
     198        self.visitors.append(StripDirectiveVisitor())
     199        self.visitors.append(WhenDirectiveVisitor())
     200        self.visitors.append(WithDirectiveVisitor())
     201
     202    def can_visit(self, kind):
     203        return kind is SUB
     204
     205    def visit(self, kind, data, pos, context):
     206        directives, substream = data
     207
     208        for directive in directives:
     209            for visitor in self.visitors:
     210                if visitor.can_visit(directive):
     211                    visitor.visit(directive, substream, context)
     212                    break
     213
     214        # recursively process the substreams
     215        processor = StreamProcessor()
     216        processor.process(substream, context)
     217
     218
     219# Directives
     220
     221class DirectiveVisitor(object):
     222
     223    #@abstractmethod
     224    def can_vist(self, directive):
     225        pass
     226
     227    #@abstractmethod
     228    def visit(self, directive, substream, context):
     229        pass
     230
     231
     232class AttrsDirectiveVisitor(DirectiveVisitor):
     233
     234    def can_visit(self, kind):
     235        return isinstance(directive, AttrsDirective)
     236
     237    def visit(self, directive, substream, context):
     238        pass
     239
     240
     241class ChooseDirectiveVisitor(DirectiveVisitor):
     242
     243    def can_visit(self, kind):
     244        return isinstance(directive, ChooseDirective)
     245
     246    def visit(self, directive, substream, context):
     247        pass
     248
     249
     250class ContentDirectiveVisitor(DirectiveVisitor):
     251
     252    def can_visit(self, kind):
     253        return isinstance(directive, ContentDirective)
     254
     255    def visit(self, directive, substream, context):
     256        pass
     257
     258
     259class DefDirectiveVisitor(DirectiveVisitor):
     260
     261    def can_visit(self, kind):
     262        return isinstance(directive, DefDirective)
     263
     264    def visit(self, directive, substream, context):
     265        pass
     266
     267
     268class ForDirectiveVisitor(DirectiveVisitor):
     269
     270    def can_visit(self, kind):
     271        return isinstance(directive, ForDirective)
     272
     273    def visit(self, directive, substream, context):
     274        pass
     275
     276
     277class IfDirectiveVisitor(DirectiveVisitor):
     278
     279    def can_visit(self, kind):
     280        return isinstance(directive, IfDirective)
     281
     282    def visit(self, directive, substream, context):
     283
     284        if directive.expr:
     285            context.declare_expression( directive.expr )
     286
     287
     288class MatchDirectiveVisitor(DirectiveVisitor):
     289
     290    def can_visit(self, kind):
     291        return isinstance(directive, MatchDirective)
     292
     293    def visit(self, directive, substream, context):
     294
     295        if directive.path:
     296            context.declare_path( directive.path )
     297
     298
     299class OtherwiseDirectiveVisitor(DirectiveVisitor):
     300
     301    def can_visit(self, kind):
     302        return isinstance(directive, OtherwiseDirective)
     303
     304    def visit(self, directive, substream, context):
     305        pass
     306
     307
     308class ReplaceDirectiveVisitor(DirectiveVisitor):
     309
     310    def can_visit(self, kind):
     311        return isinstance(directive, ReplaceDirective)
     312
     313    def visit(self, directive, substream, context):
     314        pass
     315
     316
     317class StripDirectiveVisitor(DirectiveVisitor):
     318
     319    def can_visit(self, kind):
     320        return isinstance(directive, StripDirective)
     321
     322    def visit(self, directive, substream, context):
     323        # FIXME problem here, strip strips the current element when true,
     324        # which is already accomplished by this,
     325        # however, if strip resolves to false, then the original element
     326        # in the stream must be preserved, which is currently not supported
     327        # by this, unless context would provide something like last_event
     328        pass
     329
     330
     331class WhenDirectiveVisitor(DirectiveVisitor):
     332
     333    def can_visit(self, kind):
     334        return isinstance(directive, WhenDirective)
     335
     336    def visit(self, directive, substream, context):
     337
     338        if directive.expr:
     339            context.declare_expr(directive.expr)
     340        else:
     341            raise Error()
     342
     343
     344class WithDirectiveVisitor(DirectiveVisitor):
     345
     346    def can_visit(self, kind):
     347        return isinstance(directive, WithDirective)
     348
     349    def visit(self, directive, substream, context):
     350
     351        if directive.vars:
     352            for var in directive.vars:
     353                context.declare_variable(var)
     354
     355
    82356def inline(template):
    83357    w = CodeWriter()
    84358
     
    118392                directives, substream = data
    119393                for directive in directives:
    120394
     395                    # IfDirective, WhenDirective, OtherwiseDirective, ChooseDirective
    121396                    if directive.expr:
    122397                        yield 'E', directive.expr, directive.expr
    123398
     399                    # WithDirective
    124400                    elif hasattr(directive, 'vars'):
    125401                        for _, expr in directive.vars:
    126402                            yield 'E', expr, expr
    127403
     404                    # MatchDirective
    128405                    elif hasattr(directive, 'path') and directive.path:
    129406                        yield 'P', directive.path, directive.path
    130407
     
    274551    for line in _generate(template.stream):
    275552        yield line
    276553
     554    # THINK must also remove macro functions at end of compiled template?
     555    # declared macros are generally visible on a global scope, therefore
     556    # they should be kept in context
     557    #if defs:
     558    #    yield w()
     559    #    yield w('pop()')
     560    #    yield w()
    277561
    278562if __name__ == '__main__':
    279563    import timeit
     
    297581        <span py:replace="item + 1">NUM</span>
    298582      </li>
    299583    </ul>
     584    <div id="foo">foo</div>
     585    <div id="bar">bar</div>
    300586 </body>
    301587</html>"""
    302588
  • genshi/template/markup.py

     
    343343                        del match_templates[idx]
    344344                        idx -= 1
    345345
     346                    # Make the select() function available in the body of the
     347                    # match template
     348                    selected = [False]
     349                    def select(path):
     350                        selected[0] = True
     351                        return content.select(path, namespaces, ctxt)
     352                    vars = dict(select=select)
     353
    346354                    # Let the remaining match templates know about the event so
    347355                    # they get a chance to update their internal state
    348356                    for test in [mt[0] for mt in match_templates[idx + 1:]]:
     
    362370                        content = list(content)
    363371                    content = Stream(content)
    364372
    365                     # Make the select() function available in the body of the
    366                     # match template
    367                     selected = [False]
    368                     def select(path):
    369                         selected[0] = True
    370                         return content.select(path, namespaces, ctxt)
    371                     vars = dict(select=select)
    372 
    373373                    # Recursively process the output
    374374                    template = _apply_directives(template, directives, ctxt,
    375375                                                 vars)