Mercurial > genshi > mirror
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: |