diff doc/templates.txt @ 820:1837f39efd6f experimental-inline

Sync (old) experimental inline branch with trunk@1027.
author cmlenz
date Wed, 11 Mar 2009 17:51:06 +0000
parents 0742f421caba
children 09cc3627654c
line wrap: on
line diff
--- a/doc/templates.txt
+++ b/doc/templates.txt
@@ -32,7 +32,9 @@
 used to generate any kind of HTML or XML output, as they provide many advantages
 over simple text-based templates (such as automatic escaping of strings).
 
-The following illustrates a very basic Genshi markup template::
+The following illustrates a very basic Genshi markup template:
+
+.. code-block:: genshi
 
   <?python
     title = "A Genshi Template"
@@ -60,7 +62,9 @@
 (c) usage of templates directives (``py:content`` and ``py:for``)
 (d) an inline Python expression (``${fruit}``).
 
-The template would generate output similar to this::
+The template would generate output similar to this:
+
+.. code-block:: genshi
 
   <html>
     <head>
@@ -79,7 +83,9 @@
 
 A *text template* is a simple plain text document that can also contain embedded
 Python code. Text templates can be used to generate simple *non-markup* text
-formats, such as the body of an plain text email. For example::
+formats, such as the body of an plain text email. For example:
+
+.. code-block:: genshitext
 
   Dear $name,
   
@@ -103,33 +109,44 @@
   be made available to the template as keyword arguments.
 * Serialize the resulting stream using its ``render()`` method.
 
-For example::
+For example:
+
+.. code-block:: pycon
 
   >>> from genshi.template import MarkupTemplate
   >>> tmpl = MarkupTemplate('<h1>Hello, $name!</h1>')
   >>> stream = tmpl.generate(name='world')
-  >>> print stream.render()
+  >>> print stream.render('xhtml')
   <h1>Hello, world!</h1>
 
-Using a text template is similar::
+.. note:: See the Serialization_ section of the `Markup Streams`_ page for
+          information on configuring template output options.
+
+Using a text template is similar:
+
+.. code-block:: pycon
 
   >>> from genshi.template import TextTemplate
   >>> tmpl = TextTemplate('Hello, $name!')
   >>> stream = tmpl.generate(name='world')
-  >>> print stream.render()
+  >>> print stream
   Hello, world!
 
-.. note:: See the Serialization_ section of the `Markup Streams`_ page for
-          information on configuring template output options.
+.. note:: If you want to use text templates, you should consider using the
+          ``NewTextTemplate`` class instead of simply ``TextTemplate``. See
+          the `Text Template Language`_ page.
 
 .. _serialization: streams.html#serialization
+.. _`Text Template Language`: text-templates.html
 .. _`Markup Streams`: streams.html
 
 Using a template loader provides the advantage that “compiled” templates are
 automatically cached, and only parsed again when the template file changes. In
 addition, it enables the use of a *template search path*, allowing template
 directories to be spread across different file-system locations. Using a
-template loader would generally look as follows::
+template loader would generally look as follows:
+
+.. code-block:: python
 
   from genshi.template import TemplateLoader
   loader = TemplateLoader([templates_dir1, templates_dir2])
@@ -158,7 +175,9 @@
 If the expression starts with a letter and contains only letters, digits, dots,
 and underscores, the curly braces may be omitted. In all other cases, the
 braces are required so that the template processor knows where the expression
-ends::
+ends:
+
+.. code-block:: pycon
 
   >>> from genshi.template import MarkupTemplate
   >>> tmpl = MarkupTemplate('<em>${items[0].capitalize()} item</em>')
@@ -168,7 +187,9 @@
 Expressions support the full power of Python. In addition, it is possible to
 access items in a dictionary using “dotted notation” (i.e. as if they were
 attributes), and vice-versa (i.e. access attributes as if they were items in a
-dictionary)::
+dictionary):
+
+.. code-block:: pycon
 
   >>> from genshi.template import MarkupTemplate
   >>> tmpl = MarkupTemplate('<em>${dict.foo}</em>')
@@ -182,31 +203,90 @@
 See `Error Handling`_ below for details on how such errors are handled.
 
 
+Escaping
+========
+
+If you need to include a literal dollar sign in the output where Genshi would
+normally detect an expression, you can simply add another dollar sign:
+
+.. code-block:: pycon
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<em>$foo</em>') # Wanted "$foo" as literal output
+  >>> print tmpl.generate()
+  Traceback (most recent call last):
+    ...
+  UndefinedError: "foo" not defined
+  >>> tmpl = MarkupTemplate('<em>$$foo</em>')
+  >>> print tmpl.generate()
+  <em>$foo</em>
+
+But note that this is not necessary if the characters following the dollar sign
+do not qualify as an expression. For example, the following needs no escaping:
+
+.. code-block:: pycon
+
+  >>> tmpl = MarkupTemplate('<script>$(function() {})</script>')
+  >>> print tmpl.generate()
+  <script>$(function() {})</script>
+
+On the other hand, Genshi will always replace two dollar signs in text with a
+single dollar sign, so you'll need to use three dollar signs to get two in the
+output:
+
+.. code-block:: pycon
+
+  >>> tmpl = MarkupTemplate('<script>$$$("div")</script>')
+  >>> print tmpl.generate()
+  <script>$$("div")</script>
+
+
 .. _`code blocks`:
 
 Code Blocks
 ===========
 
-XML templates also support full Python code blocks using the ``<?python ?>``
-processing instruction::
+Templates also support full Python code blocks, using the ``<?python ?>``
+processing instruction in XML templates:
+
+.. code-block:: genshi
 
   <div>
     <?python
         from genshi.builder import tag
         def greeting(name):
-            return tag.b('Hello, %s!' % name') ?>
+            return tag.b('Hello, %s!' % name) ?>
     ${greeting('world')}
   </div>
 
-This will produce the following output::
+This will produce the following output:
+
+.. code-block:: xml
 
   <div>
     <b>Hello, world!</b>
   </div>
 
+In text templates (although only those using the new syntax introduced in
+Genshi 0.5), code blocks use the special ``{% python %}`` directive:
+
+.. code-block:: genshitext
+
+  {% python
+      from genshi.builder import tag
+      def greeting(name):
+          return 'Hello, %s!' % name
+  %}
+  ${greeting('world')}
+
+This will produce the following output::
+
+  Hello, world!
+
+
 Code blocks can import modules, define classes and functions, and basically do
 anything you can do in normal Python code. What code blocks can *not* do is to
-produce content that is included directly in the generated page.
+produce content that is emitted directly tp the generated output.
 
 .. note:: Using the ``print`` statement will print to the standard output
           stream, just as it does for other Python code in your application.
@@ -220,7 +300,13 @@
 design. If you're using many code blocks, that may be a sign that you should
 move such code into separate Python modules.
 
-.. note:: Code blocks are not currently supported in text templates.
+If you'd rather not allow the use of Python code blocks in templates, you can
+simply set the ``allow_exec`` parameter (available on the ``Template`` and the
+``TemplateLoader`` initializers) to ``False``. In that case Genshi will raise
+a syntax error when a ``<?python ?>`` processing instruction is encountered.
+But please note that disallowing code blocks in templates does not turn Genshi
+into a sandboxable template engine; there are sufficient ways to do harm even
+using plain expressions.
 
 
 .. _`error handling`:
@@ -228,62 +314,85 @@
 Error Handling
 ==============
 
-By default, Genshi allows you to access variables that are not defined, without
-raising a ``NameError`` exception as regular Python code would::
+By default, Genshi raises an ``UndefinedError`` if a template expression
+attempts to access a variable that is not defined:
+
+.. code-block:: pycon
 
   >>> from genshi.template import MarkupTemplate
   >>> tmpl = MarkupTemplate('<p>${doh}</p>')
+  >>> tmpl.generate().render('xhtml')
+  Traceback (most recent call last):
+    ...
+  UndefinedError: "doh" not defined
+
+You can change this behavior by setting the variable lookup mode to "lenient".
+In that case, accessing undefined variables returns an `Undefined` object,
+meaning that the expression does not fail immediately. See below for details.
+
+If you need to check whether a variable exists in the template context, use the
+defined_ or the value_of_ function described below. To check for existence of
+attributes on an object, or keys in a dictionary, use the ``hasattr()``,
+``getattr()`` or ``get()`` functions, or the ``in`` operator, just as you would
+in regular Python code:
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<p>${defined("doh")}</p>')
+  >>> print tmpl.generate().render('xhtml')
+  <p>False</p>
+
+.. note:: Lenient error handling was the default in Genshi prior to version 0.5.
+          Strict mode was introduced in version 0.4, and became the default in
+          0.5. The reason for this change was that the lenient error handling
+          was masking actual errors in templates, thereby also making it harder
+          to debug some problems.
+
+
+.. _`lenient`:
+
+Lenient Mode
+------------
+
+If you instruct Genshi to use the lenient variable lookup mode, it allows you
+to access variables that are not defined, without raising an ``UndefinedError``.
+
+This mode can be chosen by passing the ``lookup='lenient'`` keyword argument to
+the template initializer, or by passing the ``variable_lookup='lenient'``
+keyword argument to the ``TemplateLoader`` initializer:
+
+.. code-block:: pycon
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<p>${doh}</p>', lookup='lenient')
   >>> print tmpl.generate().render('xhtml')
   <p></p>
 
 You *will* however get an exception if you try to call an undefined variable, or
-do anything else with it, such as accessing its attributes::
+do anything else with it, such as accessing its attributes:
+
+.. code-block:: pycon
 
   >>> from genshi.template import MarkupTemplate
-  >>> tmpl = MarkupTemplate('<p>${doh.oops}</p>')
+  >>> tmpl = MarkupTemplate('<p>${doh.oops}</p>', lookup='lenient')
   >>> print tmpl.generate().render('xhtml')
   Traceback (most recent call last):
     ...
   UndefinedError: "doh" not defined
 
 If you need to know whether a variable is defined, you can check its type
-against the ``Undefined`` class, for example in a conditional directive::
+against the ``Undefined`` class, for example in a conditional directive:
+
+.. code-block:: pycon
 
   >>> from genshi.template import MarkupTemplate
-  >>> tmpl = MarkupTemplate('<p>${type(doh) is not Undefined}</p>')
+  >>> tmpl = MarkupTemplate('<p>${type(doh) is not Undefined}</p>',
+  ...                       lookup='lenient')
   >>> print tmpl.generate().render('xhtml')
   <p>False</p>
 
 Alternatively, the built-in functions defined_ or value_of_ can be used in this
 case.
 
-Strict Mode
------------
-
-In addition to the default "lenient" error handling, Genshi lets you use a less
-forgiving mode if you prefer errors blowing up loudly instead of being ignored
-silently.
-
-This mode can be chosen by passing the ``lookup='strict'`` keyword argument to
-the template initializer, or by passing the ``variable_lookup='strict'`` keyword
-argument to the ``TemplateLoader`` initializer::
-
-  >>> from genshi.template import MarkupTemplate
-  >>> tmpl = MarkupTemplate('<p>${doh}</p>', lookup='strict')
-  >>> print tmpl.generate().render('xhtml')
-  Traceback (most recent call last):
-    ...
-  UndefinedError: "doh" not defined
-
-When using strict mode, any reference to an undefined variable, as well as
-trying to access an non-existing item or attribute of an object, will cause an
-``UndefinedError`` to be raised immediately.
-
-.. note:: While this mode is currently not the default, it may be promoted to
-          the default in future versions of Genshi. In general, the default
-          lenient error handling mode can be considered dangerous as it silently
-          ignores typos.
-
 Custom Modes
 ------------
 
Copyright (C) 2012-2017 Edgewall Software