diff doc/loader.txt @ 902:09cc3627654c experimental-inline

Sync `experimental/inline` branch with [source:trunk@1126].
author cmlenz
date Fri, 23 Apr 2010 21:08:26 +0000
parents
children
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/doc/loader.txt
@@ -0,0 +1,255 @@
+.. -*- mode: rst; encoding: utf-8 -*-
+
+=================
+Loading Templates
+=================
+
+Genshi comes with a simple but flexible implementation of a template loader in
+the ``genshi.template.loader`` module. The loader provides caching of
+templates so they do not need to be reparsed when used, support for multiple
+template directories that together form a virtual search path, as well as
+support for different template loading strategies.
+
+.. contents:: Contents
+   :depth: 3
+.. sectnum::
+
+
+-----
+Usage
+-----
+
+The basic usage pattern is simple: instantiate one ``TemplateLoader`` object
+and keep it around, then ask it to load a template whenever you need to load
+one:
+
+.. code-block:: python
+
+  from genshi.template import TemplateLoader
+  
+  loader = TemplateLoader(['/path/to/dir1', '/path/to/dir2'],
+                          auto_reload=True)
+  tmpl = loader.load('test.html')
+
+When you try to load a template that can't be found, you get a
+``TemplateNotFound`` error.
+
+The default template class used by the loader is ``MarkupTemplate``, but that
+can be overridden both with a different default (as a keyword argument to the
+``TemplateLoader`` constructor), as well as on invocation of the ``load()``
+method:
+
+.. code-block:: python
+
+  from genshi.template.text import NewTextTemplate
+  
+  tmpl = loader.load('mail.txt', cls=NewTextTemplate)
+
+
+-------
+Caching
+-------
+
+The ``TemplateLoader`` class provides a simple in-memory cache for parsed
+template objects. This improves performance, because templates do not need to
+be reparsed every time they are rendered.
+
+The size of this cache can be adjusted using the `max_cache_size` option on
+the ``TemplateLoader`` constructor. The value of that option determines the
+maximum number of template objects kept in the cache. When this limit is
+reached, any templates that haven't been used in a while get purged.
+Technically, this is a least-recently-used (LRU) cache, the default limit is
+set to 25 templates.
+
+Automatic Reloading
+===================
+
+Once a template has been cached, it will normally not get reparsed until it
+has been purged from the cache. This means that any changes to the template
+file are not taken into consideration as long as it is still found in the
+cache. As this is inconvenient in development scenarios, the ``auto_reload``
+option allows for automatic cache invalidation based on whether the template
+source has changed.
+
+.. code-block:: python
+
+  from genshi.template import TemplateLoader
+  
+  loader = TemplateLoader('templates', auto_reload=True, max_cache_size=100)
+
+In production environments, automatic reloading should be disabled, as it does
+affect performance negatively.
+
+Callback Interface
+==================
+
+Sometimes you need to make sure that templates get properly configured after
+they have been loaded, but you only want to do that when the template is
+actually loaded and parsed, not when it is returned from the cache.
+
+For such cases, the ``TemplateLoader`` provides a way to specify a callback
+function that gets invoked whenever a template is loaded. You can specify that
+callback by passing it into the loader constructor via the ``callback``
+keyword argument, or later by setting the attribute of the same name. The
+callback function should expect a single argument, the template object.
+
+For example, to properly inject the `translation filter`_ into any loaded
+template, you'd use code similar to this:
+
+.. code-block:: python
+
+  from genshi.filters import Translator
+  from genshi.template import TemplateLoader
+  
+  def template_loaded(template):
+      Translator(translations.ugettext).setup(template)
+  
+  loader = TemplateLoader('templates', callback=template_loaded)
+
+.. _`translation filter`: i18n.html
+
+--------------------
+Template Search Path
+--------------------
+
+The template loader can be configured with a list of multiple directories to
+search for templates. The loader maps these directories to a single logical
+directory for locating templates by file name.
+
+The order of the directories making up the search path is significant: the
+loader will first try to locate a requested template in the first directory on
+the path, then in the second, and so on. If there are two templates with the
+same file name in multiple directories on the search path, whatever file is
+found first gets used.
+
+Based on this design, an application could, for example, configure a search
+path consisting of a directory containing the default templates, as well as a
+directory where site-specific templates can be stored that will override the
+default templates.
+
+
+Load Functions
+==============
+
+Usually the search path consists of strings representing directory paths, but
+it may also contain “load functions”: functions that are basically invoked
+with the file name, and return the template content.
+
+Genshi comes with three builtin load functions:
+
+``directory(path)``
+-------------------
+
+The equivalent of just using a string containing the directory path: looks up
+the file name in a specific directory.
+
+.. code-block:: python
+
+  from genshi.template import TemplateLoader, loader
+  tl = TemplateLoader([loader.directory('/path/to/dir/')])
+
+That is the same as:
+
+.. code-block:: python
+
+  tl = TemplateLoader(['/path/to/dir/'])
+
+
+``package(name, path)``
+-----------------------
+
+Uses the ``pkg_resources`` API to locate files in Python package data (which
+may be inside a ZIP archive).
+
+.. code-block:: python
+
+  from genshi.template import TemplateLoader, loader
+  tl = TemplateLoader([loader.package('myapp', 'templates')])
+
+This will look for templates in the ``templates`` directory of the Python
+package ``myapp``.
+
+``prefixed(**delegates)``
+-------------------------
+
+Delegates load requests to different load functions based on the path prefix.
+
+.. code-block:: python
+
+  from genshi.template import TemplateLoader, loader
+  tl = TemplateLoader(loader.prefixed(
+    core = '/tmp/dir1',
+    plugin1 = loader.package('plugin1', 'templates'),
+    plugin2 = loader.package('plugin2', 'templates'),
+  ))
+  tmpl = tl.load('core/index.html')
+
+This example sets up a loader with three delegates, under the prefixes “core”,
+“plugin1”, and “plugin2”. When a template is requested, the ``prefixed`` load
+function looks for a delegate with a corresponding prefix, removes the prefix
+from the path and asks the delegate to load the template.
+
+In this case, assuming the directory ``/path/to/dir`` contains a file named
+``index.html``, that file will be used when we load ``core/index.html``. The
+other delegates are not checked as their prefix does not match.
+
+
+.. note:: These builtin load functions are available both as class methods
+          of the ``TemplateLoader`` class as well as on the module level
+
+
+Custom Load Functions
+---------------------
+
+You can easily use your own load function with the template loader, for
+example to load templates from a database. All that is needed is a callable
+object that accepts a ``filename`` (a string) and returns a tuple of the form
+``(filepath, filename, fileobj, uptodate_fun)``, where:
+
+``filepath``
+  is the absolute path to the template. This is primarily used for output in
+  tracebacks, and does not need to map to an actual path on the file system.
+``filename``
+  is the base name of the template file
+``fileobj``
+  is a readable file-like object that provides the content of the template
+``uptodate_fun``
+  is a function that the loader can invoke to check whether the cached version
+  of the template is still up-to-date, or ``None`` if the load function is not
+  able to provide such a check. If provided, the function should not expect
+  any parameters (so you'll definitely want to use a closure here), and should
+  return ``True`` if the template has not changed since it was last loaded.
+
+When the requested template can not be found, the function should raise an
+``IOError`` or ``TemplateNotFound`` exception.
+
+
+------------------
+Customized Loading
+------------------
+
+If you require a completely different implementation of template loading, you
+can extend or even replace the builtin ``TemplateLoader`` class.
+
+Protocol
+========
+
+The protocol between the template loader and the ``Template`` class is simple
+and only used for processing includes. The only required part of that protocol
+is that the object assigned to ``Template.loader`` implements a ``load``
+method compatible to that of the ``TemplateLoader`` class, at the minimum with
+the signature ``load(filename, relative_to=None, cls=None)``.
+
+In addition, templates currently check for the existence and value of a boolean
+``auto_reload`` property. If the property does not exist or evaluates to a
+non-truth value, inlining of included templates is disabled. Inlining is a
+small optimization that removes some overhead in the processing of includes.
+
+Subclassing ``TemplateLoader``
+==============================
+
+You can also adjust the behavior of the ``TemplateLoader`` class by subclassing
+it. You can of course override anything needed, but the class also provides the
+``_instantiate()`` hook, which is intended for use by subclasses to customize
+the creation of the template object from the file name and content. Please
+consult the code and the API documentation for more detail.
Copyright (C) 2012-2017 Edgewall Software