[Zope-dev] Patch to provide "local" and "set" tags in DTML

Phillip J. Eby pje@telecommunity.com
Sun, 07 Nov 1999 21:32:24 -0500


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'),



  _____
   _/__)
___/