jason kirtland avatar jason kirtland committed 9cd7f9c

Expand documentation of Generator. Incomplete.

Comments (0)

Files changed (3)

docs/source/templating/jinja2.rst

 Jinja2 Templates
 ================
 
+.. _markupsettings:
+
+Markup Settings
+---------------
+
+Placeholder... this should be in its own file and shared with a reworked
+Genshi guide.
+
+auto_name
+
+auto_value
+
+auto_domid
+
+auto_for
+
+auto_tabindex
+
+auto_filter
+
+
 Markup Generator Usage
-------------------------------
+----------------------
 
-Printing an input tag::
+The markup generator makes it easy to generate HTML and XML markup
+tags, and when combined with Flatland elements make it easy to create
+HTML forms that capture and redisplay input, and communicate
+validation errors to users right at the fields that generated them.
 
-   >>> import flatland
+.. doctest:: generatorintro
+
+   >>> from flatland import String
    >>> from flatland.out.markup import Generator
+
+.. doctest:: generatorintro
+
    >>> gen = Generator()
-   >>> el = flatland.String('foo', name='thinger')
+   >>> el = String('foo', name='thinger')
    >>> print gen.input(el)
    <input name="thinger" value="foo" />
-   
-It's quite simple to output any tag you need with flatland::
 
-    >>> from flatland.out.markup import Generator
+It's quite simple to output any tag you need with flatland.
+
+.. doctest:: generatorintro
+
+   >>> print gen.tag('a', href="/", contents="Home")
+   <a href="/">Home</a>
+
+Flatland markup generators can be used anywhere you'd use a Unicode
+string, and are completely at home in template languages such as
+Jinja2 and Mako.
+
+.. doctest:: generatorintro
+
     >>> from jinja2 import Template
     >>> template = Template('''\
-    ... Hi I'm a generator, see my tag: {{ gen.tag('a', href='#') }}
+    ... {{ gen.input(el) }}
     ... ''')
-    >>> gen = Generator()
-    >>> print template.render(gen=gen)
-    Hi I'm a generator, see my tag: <a href="#" />
+    >>> el = String(name='username')
+    >>> print template.render(gen=gen, el=el)
+    <input name="username" value="" />
 
-There's also no requirement that these tags exist in any current standard::
+And some time-saving generation features are available.
 
-    >>> from flatland.out.markup import Generator
-    >>> gen = Generator()
+.. doctest:: generatorintro
+
+    >>> template = Template('''\
+    ... {{ gen.set(auto_domid=True, auto_for=True) -}}
+    ... {{ gen.label(el) }}
+    ... {{ gen.input(el) }}
+    ... ''')
+    >>> el = String(name='username')
+    >>> gen = Generator(markup='html')
+    >>> print template.render(gen=gen, el=el)
+    <label for="f_username"></label>
+    <input name="username" value="" id="f_username">
+
+
+There's also no requirement that these tags exist in any current standard:
+
+.. doctest:: generatorintro
+
     >>> print gen.tag('wookie', contents="wookies are not really real")
     <wookie>wookies are not really real</wookie>
 
-    
+
+Generator
+---------
+
+Placeholder.
+
+.. currentmodule:: flatland.out.markup
+
+
+.. autoclass:: Generator
+   :members:
+
+
+.. autoclass:: Tag
+   :members:
+
+
 In Progress
 -----------
 

flatland/out/generic.py

 class Context(object):
     """A stacked key/value mapping."""
 
+    # These methods are public but undocumented.  For friendly, user-facing
+    # versions, see the Generator subclass.
+
     def __init__(self):
         self._frames = [dict(_default_context)]
 

flatland/out/markup.py

 from flatland.out.util import parse_trool
 
 
-_default_options = {u'ordered_attributes': True}
+_default_settings = {u'ordered_attributes': True}
 _static_attribute_order = [u'type', u'name', u'value']
 
 
 class Generator(Context):
+    """General XML/HTML tag generator"""
 
-    def __init__(self, markup='xhtml', **options):
+    def __init__(self, markup='xhtml', **settings):
+        """Create a generator.
+
+        Accepts any :ref:`markupsettings`, as well as the following:
+
+        :param markup: tag output style: 'xml', 'xhtml' or 'html'
+
+        :param ordered_attributes: if True (default), output markup attributes
+          in a predictable order.  Useful for tests and generally a little
+          more pleasant to read.
+
+        """
         Context.__init__(self)
         if markup == 'html':
             self.xml = False
         else:
             raise TypeError("Unknown markup type %r" % markup)
         self._tags = defaultdict(list)
-        self._frames[-1].update(_default_options)
+        self._frames[-1].update(_default_settings)
         self.push()
-        self.update(options)
+        self.update(settings)
 
     def begin(self, **settings):
+        """Begin a new :ref:`markupsettings` context.
+
+        Puts \*\*settings into effect until a matching :meth:`end` is called.
+        Each setting specified will mask the current value, reverting when
+        :meth:`end` is called.
+
+        """
         self.push(**settings)
         return self['markup_wrapper'](u'')
 
     def end(self):
+        """End a :ref:`markupsettings` context.
+
+        Restores the settings that were in effect before :meth:`begin`.
+
+        """
         if len(self._frames) == 2:
             raise RuntimeError("end() without matching begin()")
         self.pop()
         return self['markup_wrapper'](u'')
 
     def set(self, **settings):
+        """Change the :ref:`markupsettings` in effect.
+
+        Change the \*\*settings in the current scope.  Changes remain in
+        effect until another :meth:`set` or a :meth:`end` ends the current
+        scope.
+
+        """
+
         for key, value in settings.items():
             if key not in self:
                 raise TypeError(
 
     @property
     def form(self):
+        """Generate a <form/> tag.
+
+        :param bind: optional, a flatland element.
+        :param \*\*attributes: any desired xml/html attributes.
+        :returns: a printable :class:`Tag`
+
+        If provided with a bind, form tags can generate the *name* attribute.
+
+        """
         return self._tag(u'form', False, True)
 
     @property
     def input(self):
+        """Generate an <input/> tag.
+
+        :param bind: optional, a flatland element.
+        :param \*\*attributes: any desired xml/html attributes.
+        :returns: a printable :class:`Tag`
+
+        If provided with a bind, input tags can generate the *name*, *value*
+        and *id* attributes.  Input tags support *tabindex* attributes.
+
+        """
         return self._tag(u'input', True)
 
     @property
     def textarea(self):
+        """Generate a <textarea/> tag.
+
+        :param bind: optional, a flatland element.
+        :param \*\*attributes: any desired xml/html attributes.
+        :returns: a printable :class:`Tag`
+
+        If provided with a bind, textarea tags can generate the *name* and
+        *id* attributes.  If the bind has a value, it will be used as the tag
+        body.  Textarea tags support *tabindex* attributes.  To provide an
+        alternate tag body, either supply *contents* or use the
+        :meth:`~Tag.open` and :meth:`~Tag.close` method of the returned tag.
+
+        """
         return self._tag(u'textarea', False, True)
 
     @property
     def button(self):
+        """Generate a <button/> tag.
+
+        :param bind: optional, a flatland element.
+        :param \*\*attributes: any desired xml/html attributes.
+        :returns: a printable :class:`Tag`
+
+        If provided with a bind, button tags can generate the *name*, *value*,
+        and *id* attributes.  Button tags support *tabindex* attributes.
+
+        """
         return self._tag(u'button')
 
     @property
     def select(self):
+        """Generate a <select/> tag.
+
+        :param bind: optional, a flatland element.
+        :param \*\*attributes: any desired xml/html attributes.
+        :returns: a printable :class:`Tag`
+
+        If provided with a bind, select tags can generate the *name* and *id*
+        attributes.  Select tags support *tabindex* attributes.
+
+        """
         return self._tag(u'select', False, True)
 
     @property
     def option(self):
+        """Generate a <option/> tag.
+
+        :param bind: optional, a flatland element.
+        :param \*\*attributes: any desired xml/html attributes.
+        :returns: a printable :class:`Tag`
+
+        If provided with a bind, option tags can generate the *value*
+        attribute.  To provide tag body, either supply *contents* or use the
+        :meth:`~Tag.open` and :meth:`~Tag.close` method of the returned tag::
+
+           print generator.option.open(style='bold')
+           print '<strong>contents</strong>'
+           print generator.option.close()
+
+        """
         return self._tag(u'option', False, True)
 
     @property
     def label(self):
+        """Generate a <label/> tag.
+
+        :param bind: optional, a flatland element.
+        :param \*\*attributes: any desired xml/html attributes.
+        :returns: a printable :class:`Tag`
+
+        If provided with a bind, label tags can generate the *for* attribute
+        and fill in the tag body with the element's
+        :attr:`~flatland.Element.label`, if present.
+
+        """
         return self._tag(u'label')
 
-    def tag(self, tagname, bind=None, **kw):
+    def tag(self, tagname, bind=None, **attributes):
+        """Generate any tag.
+
+        :param tagname: the name of the tag.
+        :param bind: optional, a flatland element.
+        :param \*\*attributes: any desired xml/html attributes.
+        :returns: a printable :class:`Tag`
+
+        The attribute rules appropriate for *tagname* will be applied.  For
+        example, ``tag('input')`` is equivalent to ``input()``.
+
+        """
         if isinstance(tagname, str):  # pragma: nocover
             tagname = unicode(tagname)
         tagname = tagname.lower()
-        if bind is None and not kw:
+        if bind is None and not attributes:
             return self._tag(tagname)
         else:
-            return self._tag(tagname)(bind, **kw)
+            return self._tag(tagname)(bind, **attributes)
 
     def _tag(self, tagname, empty_in_html=False, always_paired=False):
         if self._tags[tagname]:
 
 
 class Tag(object):
+    """A printable markup tag.
+
+    Tags are generated by :class:`Generator` and are usually called
+    immediately, returning a fully formed markup string::
+
+      print generator.textarea(contents="hello!")
+
+    For more fine-tuned control over your markup, you may instead choose to
+    use the :meth:`open` and :meth:`close` methods of the tag::
+
+      print generator.textarea.open()
+      print "hello!"
+      print generator.textarea.close()
+
+    """
+
     __slots__ = ('tagname', 'contents', '_context',
                  '_html_dangle', '_always_paired')
 
         self.contents = None
 
     def open(self, bind=None, **attributes):
+        """Return the opening half of the tag, e.g. <p>.
+
+        :param bind: optional, a flatland element.
+        :param \*\*attributes: any desired tag attributes.
+
+        """
         if self not in self._context._tags[self.tagname]:
             self._context._tags[self.tagname].append(self)
         return self._markup(self._open(bind, attributes) + u'>')
 
     def close(self):
+        """Return the closing half of the tag, e.g. </p>."""
         try:
             self._context._tags[self.tagname].remove(self)
         except ValueError:
         return self._context['markup_wrapper'](string)
 
     def __call__(self, bind=None, **attributes):
+        """Return a complete, closed markup string."""
         header = self._open(bind, attributes)
         contents = self.contents
         if not contents:
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.