[Twisted-web] Macros in Nevow

Donovan Preston dp at ulaluma.com
Wed Sep 8 22:29:19 MDT 2004

Implementing compile-time macros has always been on my list of things 
to do in Nevow, but so far I haven't needed it so I haven't bothered 
trying to do it. Now that nevow is getting more finished and there are 
fewer pressing issues for me to work on, I thought I'd give it a shot. 
It turned out to be pretty easy:

 >>> from nevow import flat, tags
 >>> flat.precompile(tags.html[ tags.div(macro=lambda c: 
c.tag.children*5)[ "Child " ]])
['<html>Child Child Child Child Child </html>']

I'm not yet sure exactly how macro directives would be handled -- I 
think there would have to be an explicit type check against the type of 
toBeRenderedBy, followed by a ctx.locate(IMacroFactory).macro(name). 
This is different than how the render and data directives are simply 
adapters registered against the directive type, but I think it is ok.

Another thing to consider would be parameterized macros similar to the 
parameterized renderers and data directives we can use now. However 
since the macro executes immediately the parameters could probably be 
passed directly to the macro method:

<html><div nevow:macro="foo bar,baz" /></html>

def macro_foo(self, ctx, bar, baz):
	return bar, baz

(Which would result in:


Comments, suggestions, heckles?


Index: nevow/flat/flatstan.py
--- nevow/flat/flatstan.py      (revision 587)
+++ nevow/flat/flatstan.py      (working copy)
@@ -40,10 +40,17 @@

      if visible and context.isAttrib:
          raise RuntimeError, "Tried to render tag '%s' in an tag 
attribute context." % (original.tagName)
+    if context.precompile and original.macro:
+        toBeRenderedBy = original.macro
+        original.macro = Unset
+        newContext = context.with(original)
+        yield serialize(toBeRenderedBy(newContext), newContext)
+        return
      ## TODO: Do we really need to bypass precompiling for *all* 
      ## Perhaps just render?
-    if context.precompile and (original._specials or 
+    if context.precompile and ([x for x in original._specials.values() 
if x is not None and x is not Unset] or original.slotData):
          ## The tags inside this one get a "fresh" parent chain, because
          ## when the context yielded here is serialized, the parent
          ## chain gets reconnected to the actual parents at that
Index: nevow/stan.py
--- nevow/stan.py       (revision 582)
+++ nevow/stan.py       (working copy)
@@ -77,7 +77,7 @@
      which make representing trees of XML natural using pure python
      syntax. See the docstrings for these methods for more details.
-    specials = ['data', 'render', 'remember', 'pattern', 'key']
+    specials = ['data', 'render', 'remember', 'pattern', 'key', 

      slotData = None
      def __init__(self, tag, attributes=None, children=None, 
@@ -108,9 +108,9 @@
          table(width="100%", height="50%", border="1")

          Attributes may be 'invisible' tag instances (so that
-        a(href=invisible(data="foo", render=myhrefrenderer) works),
+        a(href=invisible(data="foo", render=myhrefrenderer)) works),
          strings, functions, or any other object which has a registered
-        ISerializable adapter.
+        flattener.

          A few magic attributes have values other than these, as they
          are not serialized for output but rather have special purposes
@@ -151,7 +151,7 @@
          """Add children to this tag. Multiple children may be added by
          passing a tuple or a list. Children may be other tag instances,
          strings, functions, or any other object which has a registered
-        ISerializable adapter.
+        flattener.

          This is implemented using __getitem__ because it then allows
          the natural syntax:

More information about the Twisted-web mailing list