![](https://secure.gravatar.com/avatar/9e03aaf8edbe4b2c0d25e30ab9a69ffb.jpg?s=120&d=mm&r=g)
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: <html>barbaz</html>) Comments, suggestions, heckles? dp 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* specials? ## Perhaps just render? - if context.precompile and (original._specials or original.slotData): + 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', 'macro'] slotData = None def __init__(self, tag, attributes=None, children=None, specials=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:
participants (1)
-
Donovan Preston