Patch to provide "local" and "set" tags in DTML
Below is a patch for the current version of DocumentTemplates which adds "local" and "set" tags to DTML. Both use syntax identical to that of the "let" tag, with two key differences. First, where "let" defines variables that remain constant within the block, the "local" tag defines local variables which may be changed within the block's scope by using the "set" tag. The second difference is that the "set" tag is an empty tag like "var", not a block tag. Thus, it can be used repetitively (e.g. within "in" loops) or to set different values of a variable on opposing conditions of an "if" tag. There are some limitations, for security reasons. Only variables named in a "local" block may be set by "set", and only those in the innermost such block. This helps to prevent an untrusted, called DTML method from polluting its parent's namespace (since its caller can wrap the call with a "local" block that defines no variables). Naturally, "set" cannot be used outside a "local" block, although this is a runtime error rather than a compile-time error. The code should be considered alpha quality - I have used it for a few things over the past few months, but it has not been put to anything heavy yet. It is available for use under the same terms as the rest of DT_Let, which is to say, under the ZPL. Enjoy. Index: DT_Let.py =================================================================== RCS file: /cvs-repository/Zope2/lib/python/DocumentTemplate/DT_Let.py,v retrieving revision 1.5 diff -r1.5 DT_Let.py 122c122,127 < tname, args, section = blocks[0] ---
if hasattr(self,'blockContinuations'): tname, args, section = (blocks[0]+(None,))[:3] self.section = section.blocks else: tname, args = self.name, blocks
124,125c129 < self.section = section.blocks < self.args = args = parse_let_params(args) ---
self.args = args = parse_let_params(args,tag=tname)
177a182,232
localdictname = '__$local.dict__'
class Local(Let):
name = 'local'
def render(self, md):
d={}; md._push(d);
try: d[localdictname]=d for name,expr in self.args: if type(expr) is type(''): d[name]=md[expr] else: d[name]=expr(md) return render_blocks(self.section, md)
finally: if d.has_key(localdictname): del d[localdictname] md._pop(1)
__call__ = render
class Set: name = 'set'
__init__ = Let.__init__.im_func
def render(self, md):
try: d = md[localdictname]
except KeyError: raise 'SetWithoutLocal',"'set' used outside of 'local' block"
for name,expr in self.args:
if not d.has_key(name): raise 'SetUndefined',"variable '%s' is not defined within
current 'local' block"
if type(expr) is type(''): d[name]=md[expr] else: d[name]=expr(md)
__call__ = render
Index: DT_String.py =================================================================== RCS file: /cvs-repository/Zope2/lib/python/DocumentTemplate/DT_String.py,v retrieving revision 1.31 diff -r1.31 DT_String.py 141a142,143
'local': ('local', 'DT_Let', 'Local'), 'set': ('set', 'DT_Let', 'Set'),
_____ _/__) ___/
participants (1)
-
Phillip J. Eby