#!/usr/bin/python """deelan's XHTML generator Deex is a little Python module that uses nested function lists to render sequences of XHTML tags. To use Deex you only need to import a couple of functions: "render" wich takes a tree of nested functions and render the corresponding XHTML markup and "curry", used to bind parameter values to functions. Visit http://www.deelan.com/dev/deex/ for the latest version and examples """ __version__ = "0.9" __author__ = "Andrea Peltrin (deelan AT interplanet DOT it)" __copyright__ = "Copyright 2003, Andrea Peltrin" __license__ = "GPL" # see full license statement below __history__ = """ 0.9 - 2003-12-27 - First public release. """ # Copyright (C) 2003 Andrea Peltrin # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # curry class from Python Cookbook, see: # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52549/ class curry: def __init__(self, fun, *args, **kwargs): self.fun = fun self.pending = args[:] self.kwargs = kwargs.copy() # let's trick Python and pretend object is a *function* object func_name = property(fget=lambda self: self.fun.func_name) def __call__(self, *args, **kwargs): if kwargs and self.kwargs: kw = self.kwargs.copy() kw.update(kwargs) else: kw = kwargs or self.kwargs return self.fun(*(self.pending + args), **kw) # @@ is this list complete? empty = dict.fromkeys('area base basefont br col frame hr img input isindex link meta param'.split()) # new-line after? newlined = dict.fromkeys('html head body link meta div ul ol li dl p hr h1 h2 h3 h4 h5 h6 table tr thead tbody tfoot'.split()) from cgi import escape def render(root): assert callable(root), 'Root element must be a callable' # list to accumulate partial strings s = [] def r_render(node): if node.__doc__: s.append('\n' % node.__doc__) #@@ or print doc as is? # forget everything after the underscore tag = node.func_name.split('_', 1)[0] s.append('<%s' % tag) children = node() start = 0 try: #check if object supports items() methods items = children[0].items() s.append(' ') # space up a bit (@@ there must be a better way!) s.append(' '.join(['%s="%s"' % (k, escape(str(v), True)) for k, v in items])) start = 1 # start offset for children list except AttributeError: pass s.append((tag in empty) and ' />' or '>') #if tag in newlined: # s.append('\n') # prettify for child in children[start:]: #print '*** got', child if callable(child): # function? r_render(child) elif isinstance(child, (list, tuple)): for c in child: r_render(c) # iterate over else: s.append(child) # close parent tag if tag not in empty: s.append('%s' % (tag, tag in newlined and '\n' or '')) # prettify return s # handy # start rendering from root node return ''.join(r_render(root)) # make a string if __name__=='__main__': print __doc__