degal/html.py
author Tero Marttila <terom@fixme.fi>
Fri, 05 Jun 2009 17:25:58 +0300
changeset 53 14d73f544764
parent 52 3071d0709c4a
child 61 fad360dd01da
permissions -rw-r--r--
expressive HTML-rendering module with doctests
52
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     1
"""
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     2
    Generating HTML tags
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     3
"""
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     4
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     5
from cgi import escape
53
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
     6
import itertools as _itertools
52
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
     7
53
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
     8
class IRenderable (object) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
     9
    """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    10
        Something that's renderable as the contents of a HTML tag
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    11
    """
52
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
    12
53
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    13
    def render_raw_lines (self, indent=u'\t') :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    14
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    15
            Render the indented lines for tag and contents, without newlines
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    16
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    17
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    18
        abstract
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    19
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    20
class Tag (IRenderable) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    21
    """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    22
        A HTML tag, with attributes and contents, which can a mixture of data and other renderables(tags).
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    23
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    24
        Provides various kinds of rendering output
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    25
    """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    26
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    27
    @staticmethod
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    28
    def process_contents (contents) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    29
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    30
            Postprocess contents iterable to return new list.
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    31
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    32
            Items that are None will be omitted from the return value.
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    33
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    34
            >>> Tag.process_contents([])
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    35
            []
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    36
            >>> Tag.process_contents([None])
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    37
            []
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    38
            >>> Tag.process_contents([u'foo'])
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    39
            [u'foo']
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    40
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    41
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    42
        return [c for c in contents if c is not None]
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    43
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    44
    @staticmethod
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    45
    def process_attrs (attrs) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    46
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    47
            Postprocess attributes.
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    48
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    49
            Key-value pairs where the value is None will be ommitted, and any trailing underscores in the key omitted.
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    50
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    51
            TODO: only remove one underscore
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    52
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    53
            >>> Tag.process_attrs(dict())
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    54
            {}
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    55
            >>> Tag.process_attrs(dict(foo='bar'))
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    56
            {'foo': 'bar'}
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    57
            >>> Tag.process_attrs(dict(class_='bar', frob=None))
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    58
            {'class': 'bar'}
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    59
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    60
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    61
        return dict((k.rstrip('_'), v) for k, v in attrs.iteritems() if v is not None)
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    62
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    63
    def __init__ (self, name, *contents, **attrs) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    64
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    65
            Construct tag with given name/attributes or contents.
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    66
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    67
            The filtering rules desribed in process_contents/process_attrs apply.
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    68
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    69
            >>> Tag('foo')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    70
            Tag('foo')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    71
            >>> Tag('foo', 'quux')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    72
            Tag('foo', 'quux')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    73
            >>> Tag('foo', 'quux', bar=5)
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    74
            Tag('foo', 'quux', bar=5)
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    75
            >>> Tag('foo', class_='ten')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    76
            Tag('foo', class='ten')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    77
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    78
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    79
        self.name = name
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    80
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    81
        # store filtered/processed versions
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    82
        self.contents = self.process_contents(contents)
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    83
        self.attrs = self.process_attrs(attrs)
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    84
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    85
    def __call__ (self, *contents, **attrs) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    86
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    87
            Return a new Tag with this tag's attributes and contents, as well as the given attributes/contents.
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    88
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    89
            The filtering rules desribed in process_contents/process_attrs apply.
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    90
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    91
            >>> Tag('foo')('bar')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    92
            Tag('foo', 'bar')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    93
            >>> Tag('a', href='index.html')("Home")
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    94
            Tag('a', 'Home', href='index.html')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    95
            >>> Tag('bar', None)(5, foo=None, class_='bar')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    96
            Tag('bar', 5, class='bar')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    97
            >>> Tag('a')('b')('c')(asdf=5)
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    98
            Tag('a', 'b', 'c', asdf=5)
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
    99
            >>> t1 = Tag('a'); t2 = t1('b'); t1
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   100
            Tag('a')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   101
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   102
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   103
        # merge attrs/contents
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   104
        # XXX: new_attrs is not an iterator...
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   105
        new_attrs = dict(_itertools.chain(self.attrs.iteritems(), attrs.iteritems()))
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   106
        new_contents = _itertools.chain(self.contents, contents)
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   107
        
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   108
        # build new tag
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   109
        return Tag(self.name, *new_contents, **new_attrs)
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   110
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   111
    @staticmethod
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   112
    def format_attr (name, value) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   113
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   114
            Format a single HTML tag attribute
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   115
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   116
            >>> Tag.format_attr('name', 'value')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   117
            u'name="value"'
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   118
            >>> Tag.format_attr('this', '<a"b>')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   119
            u'this="&lt;a&quot;b&gt;"'
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   120
            >>> Tag.format_attr('xx', 1337)
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   121
            u'xx="1337"'
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   122
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   123
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   124
        return u'%s="%s"' % (name, escape(unicode(value), True))
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   125
 
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   126
    def render_attrs (self) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   127
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   128
            Return the HTML attributes string
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   129
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   130
            >>> Tag('x', foo=5, bar='<').render_attrs()
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   131
            u'foo="5" bar="&lt;"'
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   132
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   133
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   134
        return " ".join(self.format_attr(n, v) for n, v in self.attrs.iteritems())
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   135
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   136
    def render_contents (self, **render_opts) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   137
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   138
            Render the contents of the tag as a series of indented lines, with given render_lines options for subtags
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   139
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   140
            >>> list(Tag('x', 5).render_contents())
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   141
            [u'5']
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   142
            >>> list(Tag('x', 'line1', 'line2').render_contents())
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   143
            [u'line1', u'line2']
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   144
            >>> list(Tag('x', 'a', Tag('b', 'bb'), 'c').render_contents())
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   145
            [u'a', u'<b>', u'\\tbb', u'</b>', u'c']
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   146
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   147
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   148
        for content in self.contents :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   149
            if isinstance(content, IRenderable) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   150
                # sub-tags
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   151
                for line in content.render_raw_lines(**render_opts) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   152
                    yield line
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   153
            
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   154
            else :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   155
                # escape raw values
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   156
                yield escape(unicode(content))
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   157
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   158
    def render_raw_lines (self, indent=u'\t') :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   159
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   160
            Render the tag and indented content
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   161
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   162
            >>> list(Tag('xx', 'yy', zz='foo').render_raw_lines(indent=' '))
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   163
            [u'<xx zz="foo">', u' yy', u'</xx>']
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   164
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   165
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   166
        # render attr string, including preceding space
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   167
        attrs_stuff = (" " + self.render_attrs()) if self.attrs else ""
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   168
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   169
        if self.contents :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   170
            # tag with content
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   171
            yield u"<%s%s>" % (self.name, attrs_stuff)
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   172
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   173
            for line in self.render_contents(indent=indent) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   174
                yield indent + line
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   175
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   176
            yield u"</%s>" % (self.name, )
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   177
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   178
        else :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   179
            # singleton tag
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   180
            yield u"<%s%s />" % (self.name, attrs_stuff)
52
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   181
    
53
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   182
    def render_lines (self, indent=u'\t', newline=u'\n') :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   183
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   184
            Render full output lines with given newlines
52
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   185
53
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   186
            >>> list(Tag('xx', 'yy').render_lines())
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   187
            [u'<xx>\\n', u'\\tyy\\n', u'</xx>\\n']
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   188
        """
52
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   189
53
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   190
        for line in self.render_raw_lines(indent) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   191
            yield line + newline
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   192
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   193
    def render_unicode (self, **render_opts) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   194
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   195
            Render full tag as a single unicode string
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   196
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   197
            >>> Tag('xx', 'yy').render_unicode()
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   198
            u'<xx>\\n\\tyy\\n</xx>\\n'
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   199
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   200
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   201
        return "".join(self.render_lines(**render_opts))
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   202
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   203
    def render_str (self, charset='ascii', **render_opts) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   204
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   205
            Render full tag as an encoded string
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   206
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   207
            >>> Tag('xx', 'yy').render_str()
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   208
            '<xx>\\n\\tyy\\n</xx>\\n'
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   209
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   210
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   211
        return self.render_unicode(**render_opts).encode(charset)
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   212
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   213
    def render_out (self, stream, charset, **render_opts) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   214
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   215
            Render output into the given stream, encoding using the given charset
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   216
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   217
            >>> from StringIO import StringIO; buf = StringIO(); Tag('xx', 'yy').render_out(buf, 'ascii'); buf.getvalue()
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   218
            '<xx>\\n\\tyy\\n</xx>\\n'
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   219
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   220
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   221
        for line in self.render_lines(**render_opts) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   222
            stream.write(line.encode(charset))
52
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   223
    
53
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   224
    # default output
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   225
    __str__ = render_str
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   226
    __unicode__ = render_unicode
52
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   227
53
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   228
    # default .render method
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   229
    render = render_unicode
52
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   230
53
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   231
    def __repr__ (self) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   232
        return 'Tag(%s)' % ', '.join(
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   233
            [
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   234
                repr(self.name)
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   235
            ] + [
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   236
                repr(c) for c in self.contents
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   237
            ] + [
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   238
                '%s=%r' % (name, value) for name, value in self.attrs.iteritems()
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   239
            ]
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   240
        )
52
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   241
53
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   242
class Text (IRenderable) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   243
    """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   244
        Raw HTML text
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   245
    """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   246
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   247
    def __init__ (self, line) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   248
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   249
            Initialize to render as the given lines
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   250
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   251
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   252
        self.lines = [line]
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   253
    
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   254
    def render_raw_lines (self, indent=u'\t') :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   255
        return self.lines
52
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   256
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   257
class TagFactory (object) :
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   258
    """
53
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   259
        Build Tags with names give as attribute names
52
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   260
    """
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   261
53
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   262
    def __getattr__ (self, name) :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   263
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   264
            Get a Tag object with the given name, but no contents
52
3071d0709c4a start writing some kind of nested-HTML-tag-generators magic to use instead of templates :)
Tero Marttila <terom@fixme.fi>
parents:
diff changeset
   265
53
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   266
            >>> TagFactory().a(href='bar')('quux')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   267
            Tag('a', 'quux', href='bar')
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   268
        """
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   269
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   270
        return Tag(name)
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   271
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   272
# pretty names
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   273
tag = Tag
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   274
tags = TagFactory()
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   275
raw = Text
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   276
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   277
# testing
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   278
if __name__ == '__main__' :
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   279
    import doctest
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   280
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   281
    doctest.testmod()
14d73f544764 expressive HTML-rendering module with doctests
Tero Marttila <terom@fixme.fi>
parents: 52
diff changeset
   282