summaryrefslogtreecommitdiff
path: root/doc/build/defs.rst
diff options
context:
space:
mode:
Diffstat (limited to 'doc/build/defs.rst')
-rw-r--r--doc/build/defs.rst435
1 files changed, 435 insertions, 0 deletions
diff --git a/doc/build/defs.rst b/doc/build/defs.rst
index 8b13789..1e3abb6 100644
--- a/doc/build/defs.rst
+++ b/doc/build/defs.rst
@@ -1 +1,436 @@
+.. _defs_toplevel:
+
+====
+Defs
+====
+
+``<%def>`` is the single tag used to demarcate any block of text
+and/or code. It exists within generated Python as a callable
+function:
+
+.. sourcecode:: mako
+
+ <%def name="hello()">
+ hello world
+ </%def>
+
+They are normally called as expressions:
+
+.. sourcecode:: mako
+
+ the def: ${hello()}
+
+If the ``<%def>`` is not nested inside of another ``<%def>``,
+its known as a **top level def** and can be accessed anywhere in
+the template, including above where it was defined.
+
+All defs, top level or not, have access to the current
+contextual namespace in exactly the same way their containing
+template does. Suppose the template below is executed with the
+variables ``username`` and ``accountdata`` inside the context:
+
+.. sourcecode:: mako
+
+ Hello there ${username}, how are ya. Lets see what your account says:
+
+ ${account()}
+
+ <%def name="account()">
+ Account for ${username}:<br/>
+
+ % for row in accountdata:
+ Value: ${row}<br/>
+ % endfor
+ </%def>
+
+The ``username`` and ``accountdata`` variables are present
+within the main template body as well as the body of the
+``account()`` def.
+
+Since defs are just Python functions, you can define and pass
+arguments to them as well:
+
+.. sourcecode:: mako
+
+ ${account(accountname='john')}
+
+ <%def name="account(accountname, type='regular')">
+ account name: ${accountname}, type ${type}
+ </%def>
+
+When you declare an argument signature for your def, they are
+required to follow normal Python conventions (i.e., all
+arguments are required except keyword arguments with a default
+value). This is in contrast to using context-level variables,
+which evaluate to ``UNDEFINED`` if you reference a name that
+does not exist.
+
+Calling defs from Other Files
+==============================
+
+Top level ``<%defs>`` are **exported** by your template's
+module, and can be called from the outside; including from other
+templates, as well as normal Python code. Calling a ``<%def>``
+from another template is something like using an ``<%include>``
+- except you are calling a specific function within the
+template, not the whole template.
+
+The remote ``<%def>`` call is also a little bit like calling
+functions from other modules in Python. There is an "import"
+step to pull the names from another template into your own
+template; then the function or functions are available.
+
+To import another template, use the ``<%namespace>`` tag:
+
+.. sourcecode:: mako
+
+ <%namespace name="mystuff" file="mystuff.html"/>
+
+The above tag adds a local variable "mystuff" to the current
+scope.
+
+Then, just call the defs off of ``mystuff``:
+
+.. sourcecode:: mako
+
+ ${mystuff.somedef(x=5,y=7)}
+
+The ``<%namespace>`` tag also supports some of the other
+semantics of Python's ``import`` statement, including pulling
+names into the local variable space, or using ``*`` to represent
+all names, using the ``import`` attribute:
+
+.. sourcecode:: mako
+
+ <%namespace file="mystuff.html" import="foo, bar"/>
+
+This is just a quick intro to the concept of a **namespace**,
+which is a central Mako concept that has its own chapter in
+these docs. For more detail and examples, see
+:ref:`namespaces_toplevel`.
+
+Calling defs programmatically
+==============================
+
+You can call def's programmatically from any :class:`.Template` object
+using the :meth:`~.Template.get_def()` method, which returns a :class:`.DefTemplate`
+object. This is a :class:`.Template` subclass which the parent
+:class:`.Template` creates, and is usable like any other template:
+
+.. sourcecode:: python
+
+ from mako.template import Template
+
+ template = Template("""
+ <%def name="hi(name)">
+ hi ${name}!
+ </%def>
+
+ <%def name="bye(name)">
+ bye ${name}!
+ </%def>
+ """)
+
+ print template.get_def("hi").render(name="ed")
+ print template.get_def("bye").render(name="ed")
+
+
+Defs within Defs
+================
+
+The def model follows regular Python rules for closures.
+Declaring ``<%def>`` inside another ``<%def>`` declares it
+within the parent's **enclosing scope**:
+
+.. sourcecode:: mako
+
+ <%def name="mydef()">
+ <%def name="subdef()">
+ a sub def
+ </%def>
+
+ im the def, and the subcomponent is ${subdef()}
+ </%def>
+
+Just like Python, names that exist outside the inner ``<%def>``
+exist inside it as well:
+
+.. sourcecode:: mako
+
+ <%
+ x = 12
+ %>
+ <%def name="outer()">
+ <%
+ y = 15
+ %>
+ <%def name="inner()">
+ inner, x is ${x}, y is ${y}
+ </%def>
+
+ outer, x is ${x}, y is ${y}
+ </%def>
+
+Assigning to a name inside of a def declares that name as local
+to the scope of that def (again, like Python itself). This means
+the following code will raise an error:
+
+.. sourcecode:: mako
+
+ <%
+ x = 10
+ %>
+ <%def name="somedef()">
+ ## error !
+ somedef, x is ${x}
+ <%
+ x = 27
+ %>
+ </%def>
+
+...because the assignment to ``x`` declares x as local to the
+scope of ``somedef``, rendering the "outer" version unreachable
+in the expression that tries to render it.
+
+.. _defs_with_content:
+
+Calling a def with embedded content and/or other defs
+=====================================================
+
+A flip-side to def within def is a def call with content. This
+is where you call a def, and at the same time declare a block of
+content (or multiple blocks) that can be used by the def being
+called. The main point of such a call is to create custom,
+nestable tags, just like any other template language's
+custom-tag creation system - where the external tag controls the
+execution of the nested tags and can communicate state to them.
+Only with Mako, you don't have to use any external Python
+modules, you can define arbitrarily nestable tags right in your
+templates.
+
+To achieve this, the target def is invoked using the form
+``<%namepacename:defname>`` instead of the normal ``${}``
+syntax. This syntax, introduced in Mako 0.2.3, is functionally
+equivalent another tag known as ``call``, which takes the form
+``<%call expr='namespacename.defname(args)'>``. While ``%call``
+is available in all versions of Mako, the newer style is
+probably more familiar looking. The ``namespace`` portion of the
+call is the name of the **namespace** in which the def is
+defined - in the most simple cases, this can be ``local`` or
+``self`` to reference the current template's namespace (the
+difference between ``local`` and ``self`` is one of inheritance
+- see :ref:`namespaces_builtin` for details).
+
+When the target def is invoked, a variable ``caller`` is placed
+in its context which contains another namespace containing the
+body and other defs defined by the caller. The body itself is
+referenced by the method ``body()``. Below, we build a ``%def``
+that operates upon ``caller.body()`` to invoke the body of the
+custom tag:
+
+.. sourcecode:: mako
+
+ <%def name="buildtable()">
+ <table>
+ <tr><td>
+ ${caller.body()}
+ </td></tr>
+ </table>
+ </%def>
+
+ <%self:buildtable>
+ I am the table body.
+ </%self:buildtable>
+
+This produces the output (whitespace formatted):
+
+.. sourcecode:: html
+
+ <table>
+ <tr><td>
+ I am the table body.
+ </td></tr>
+ </table>
+
+Using the older ``%call`` syntax looks like:
+
+.. sourcecode:: mako
+
+ <%def name="buildtable()">
+ <table>
+ <tr><td>
+ ${caller.body()}
+ </td></tr>
+ </table>
+ </%def>
+
+ <%call expr="buildtable()">
+ I am the table body.
+ </%call>
+
+The ``body()`` can be executed multiple times or not at all.
+This means you can use def-call-with-content to build iterators,
+conditionals, etc:
+
+.. sourcecode:: mako
+
+ <%def name="lister(count)">
+ % for x in range(count):
+ ${caller.body()}
+ % endfor
+ </%def>
+
+ <%self:lister count="${3}">
+ hi
+ </%self:lister>
+
+Produces:
+
+.. sourcecode:: html
+
+ hi
+ hi
+ hi
+
+Notice above we pass ``3`` as a Python expression, so that it
+remains as an integer.
+
+A custom "conditional" tag:
+
+.. sourcecode:: mako
+
+ <%def name="conditional(expression)">
+ % if expression:
+ ${caller.body()}
+ % endif
+ </%def>
+
+ <%self:conditional expression="${4==4}">
+ im the result
+ </%self:conditional>
+
+Produces:
+
+.. sourcecode:: html
+
+ im the result
+
+But that's not all. The ``body()`` function also can handle
+arguments, which will augment the local namespace of the body
+callable. The caller must define the arguments which it expects
+to receive from its target def using the ``args`` attribute,
+which is a comma-separated list of argument names. Below, our
+``<%def>`` calls the ``body()`` of its caller, passing in an
+element of data from its argument:
+
+.. sourcecode:: mako
+
+ <%def name="layoutdata(somedata)">
+ <table>
+ % for item in somedata:
+ <tr>
+ % for col in item:
+ <td>${caller.body(col=col)}</td>
+ % endfor
+ </tr>
+ % endfor
+ </table>
+ </%def>
+
+ <%self:layoutdata somedata="${[[1,2,3],[4,5,6],[7,8,9]]}" args="col">\
+ Body data: ${col}\
+ </%self:layoutdata>
+
+Produces:
+
+.. sourcecode:: html
+
+ <table>
+ <tr>
+ <td>Body data: 1</td>
+ <td>Body data: 2</td>
+ <td>Body data: 3</td>
+ </tr>
+ <tr>
+ <td>Body data: 4</td>
+ <td>Body data: 5</td>
+ <td>Body data: 6</td>
+ </tr>
+ <tr>
+ <td>Body data: 7</td>
+ <td>Body data: 8</td>
+ <td>Body data: 9</td>
+ </tr>
+ </table>
+
+You don't have to stick to calling just the ``body()`` function.
+The caller can define any number of callables, allowing the
+``<%call>`` tag to produce whole layouts:
+
+.. sourcecode:: mako
+
+ <%def name="layout()">
+ ## a layout def
+ <div class="mainlayout">
+ <div class="header">
+ ${caller.header()}
+ </div>
+ <div class="sidebar">
+ ${caller.sidebar()}
+ </div>
+ <div class="content">
+ ${caller.body()}
+ </div>
+ </div>
+ </%def>
+
+ ## calls the layout def
+ <%self:layout>
+ <%def name="header()">
+ I am the header
+ </%def>
+ <%def name="sidebar()">
+ <ul>
+ <li>sidebar 1</li>
+ <li>sidebar 2</li>
+ </ul>
+ </%def>
+
+ this is the body
+ </%self:layout>
+
+The above layout would produce:
+
+.. sourcecode:: html
+
+ <div class="mainlayout">
+ <div class="header">
+ I am the header
+ </div>
+
+ <div class="sidebar">
+ <ul>
+ <li>sidebar 1</li>
+ <li>sidebar 2</li>
+ </ul>
+ </div>
+
+ <div class="content">
+ this is the body
+ </div>
+ </div>
+
+The number of things you can do with ``<%call>`` and/or the
+``<%namespacename:defname>`` calling syntax is enormous. You can
+create form widget libraries, such as an enclosing ``<FORM>``
+tag and nested HTML input elements, or portable wrapping schemes
+using ``<div>`` or other elements. You can create tags that
+interpret rows of data, such as from a database, providing the
+individual columns of each row to a ``body()`` callable which
+lays out the row any way it wants. Basically anything you'd do
+with a "custom tag" or tag library in some other system, Mako
+provides via ``<%def>`` tags and plain Python callables which are
+invoked via ``<%namespacename:defname>`` or ``<%call>``.
+
+