comparison genshi/template/core.py @ 362:fe40d34fb71d trunk

Follow-up to [431]: directives are no longer instantiated directly at parse time, but instead by the `attach()` method of the directive class (which replaces the `prepare()` method).
author cmlenz
date Wed, 22 Nov 2006 10:37:24 +0000
parents 860bec4af34c
children 37e4b4bb0b53
comparison
equal deleted inserted replaced
361:860bec4af34c 362:fe40d34fb71d
134 def push(self, data): 134 def push(self, data):
135 """Push a new scope on the stack.""" 135 """Push a new scope on the stack."""
136 136
137 def pop(self): 137 def pop(self):
138 """Pop the top-most scope from the stack.""" 138 """Pop the top-most scope from the stack."""
139
140
141 class DirectiveMeta(type):
142 """Meta class for template directives."""
143
144 def __new__(cls, name, bases, d):
145 d['tagname'] = name.lower().replace('directive', '')
146 return type.__new__(cls, name, bases, d)
147
148
149
150 class Directive(object):
151 """Abstract base class for template directives.
152
153 A directive is basically a callable that takes three positional arguments:
154 `ctxt` is the template data context, `stream` is an iterable over the
155 events that the directive applies to, and `directives` is is a list of
156 other directives on the same stream that need to be applied.
157
158 Directives can be "anonymous" or "registered". Registered directives can be
159 applied by the template author using an XML attribute with the
160 corresponding name in the template. Such directives should be subclasses of
161 this base class that can be instantiated with the value of the directive
162 attribute as parameter.
163
164 Anonymous directives are simply functions conforming to the protocol
165 described above, and can only be applied programmatically (for example by
166 template filters).
167 """
168 __metaclass__ = DirectiveMeta
169 __slots__ = ['expr']
170
171 def __init__(self, value, namespaces=None, filename=None, lineno=-1,
172 offset=-1):
173 try:
174 self.expr = value and Expression(value, filename, lineno) or None
175 except SyntaxError, err:
176 err.msg += ' in expression "%s" of "%s" directive' % (value,
177 self.tagname)
178 raise TemplateSyntaxError(err, filename, lineno,
179 offset + (err.offset or 0))
180
181 def __call__(self, stream, ctxt, directives):
182 """Apply the directive to the given stream.
183
184 @param stream: the event stream
185 @param ctxt: the context data
186 @param directives: a list of the remaining directives that should
187 process the stream
188 """
189 raise NotImplementedError
190
191 def __repr__(self):
192 expr = ''
193 if self.expr is not None:
194 expr = ' "%s"' % self.expr.source
195 return '<%s%s>' % (self.__class__.__name__, expr)
196
197 def prepare(self, directives, stream):
198 """Called after the template stream has been completely parsed.
199
200 The part of the template stream associated with the directive will be
201 replaced by what this function returns. This allows the directive to
202 optimize the template or validate the way the directive is used.
203 """
204 return stream
205 139
206 140
207 def _apply_directives(stream, ctxt, directives): 141 def _apply_directives(stream, ctxt, directives):
208 """Apply the given directives to the stream.""" 142 """Apply the given directives to the stream."""
209 if directives: 143 if directives:
305 offset += len(grp) 239 offset += len(grp)
306 return _interpolate(text, [cls._FULL_EXPR_RE, cls._SHORT_EXPR_RE]) 240 return _interpolate(text, [cls._FULL_EXPR_RE, cls._SHORT_EXPR_RE])
307 _interpolate = classmethod(_interpolate) 241 _interpolate = classmethod(_interpolate)
308 242
309 def _prepare(self, stream): 243 def _prepare(self, stream):
310 """Call the `prepare` method of every directive instance in the 244 """Call the `attach` method of every directive found in the template."""
311 template so that various optimization and validation tasks can be
312 performed.
313 """
314 for kind, data, pos in stream: 245 for kind, data, pos in stream:
315 if kind is SUB: 246 if kind is SUB:
316 directives, substream = data 247 directives = []
317 for directive in directives[:]: 248 substream = data[1]
318 substream = directive.prepare(directives, substream) 249 for cls, value, namespaces, pos in data[0]:
250 directive, substream = cls.attach(self, substream, value,
251 namespaces, pos)
252 if directive:
253 directives.append(directive)
319 substream = self._prepare(substream) 254 substream = self._prepare(substream)
320 if directives: 255 if directives:
321 yield kind, (directives, list(substream)), pos 256 yield kind, (directives, list(substream)), pos
322 else: 257 else:
323 for event in substream: 258 for event in substream:
Copyright (C) 2012-2017 Edgewall Software