diff options
Diffstat (limited to 'doc/build/defs.rst')
-rw-r--r-- | doc/build/defs.rst | 622 |
1 files changed, 622 insertions, 0 deletions
diff --git a/doc/build/defs.rst b/doc/build/defs.rst new file mode 100644 index 0000000..314e9b9 --- /dev/null +++ b/doc/build/defs.rst @@ -0,0 +1,622 @@ +.. _defs_toplevel: + +=============== +Defs and Blocks +=============== + +``<%def>`` and ``<%block>`` are two tags that both demarcate any block of text +and/or code. They both exist within generated Python as a callable function, +i.e., a Python ``def``. They differ in their scope and calling semantics. +Whereas ``<%def>`` provides a construct that is very much like a named Python +``def``, the ``<%block>`` is more layout oriented. + +Using Defs +========== + +The ``<%def>`` tag requires a ``name`` attribute, where the ``name`` references +a Python function signature: + +.. sourcecode:: mako + + <%def name="hello()"> + hello world + </%def> + +To invoke the ``<%def>``, it is normally called as an expression: + +.. sourcecode:: mako + + the def: ${hello()} + +If the ``<%def>`` is not nested inside of another ``<%def>``, +it's 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 ``<%def>``\ s 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 defs 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> + + i'm 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 +``<%namespacename:defname>`` instead of the normal ``${}`` +syntax. This syntax, introduced in Mako 0.2.3, is functionally +equivalent to 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}"> + i'm the result + </%self:conditional> + +Produces: + +.. sourcecode:: html + + i'm 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>``. + +.. _blocks: + +Using Blocks +============ + +The ``<%block>`` tag introduces some new twists on the +``<%def>`` tag which make it more closely tailored towards layout. + +.. versionadded:: 0.4.1 + +An example of a block: + +.. sourcecode:: mako + + <html> + <body> + <%block> + this is a block. + </%block> + </body> + </html> + +In the above example, we define a simple block. The block renders its content in the place +that it's defined. Since the block is called for us, it doesn't need a name and the above +is referred to as an **anonymous block**. So the output of the above template will be: + +.. sourcecode:: html + + <html> + <body> + this is a block. + </body> + </html> + +So in fact the above block has absolutely no effect. Its usefulness comes when we start +using modifiers. Such as, we can apply a filter to our block: + +.. sourcecode:: mako + + <html> + <body> + <%block filter="h"> + <html>this is some escaped html.</html> + </%block> + </body> + </html> + +or perhaps a caching directive: + +.. sourcecode:: mako + + <html> + <body> + <%block cached="True" cache_timeout="60"> + This content will be cached for 60 seconds. + </%block> + </body> + </html> + +Blocks also work in iterations, conditionals, just like defs: + +.. sourcecode:: mako + + % if some_condition: + <%block>condition is met</%block> + % endif + +While the block renders at the point it is defined in the template, +the underlying function is present in the generated Python code only +once, so there's no issue with placing a block inside of a loop or +similar. Anonymous blocks are defined as closures in the local +rendering body, so have access to local variable scope: + +.. sourcecode:: mako + + % for i in range(1, 4): + <%block>i is ${i}</%block> + % endfor + +Using Named Blocks +------------------ + +Possibly the more important area where blocks are useful is when we +do actually give them names. Named blocks are tailored to behave +somewhat closely to Jinja2's block tag, in that they define an area +of a layout which can be overridden by an inheriting template. In +sharp contrast to the ``<%def>`` tag, the name given to a block is +global for the entire template regardless of how deeply it's nested: + +.. sourcecode:: mako + + <html> + <%block name="header"> + <head> + <title> + <%block name="title">Title</%block> + </title> + </head> + </%block> + <body> + ${next.body()} + </body> + </html> + +The above example has two named blocks "``header``" and "``title``", both of which can be referred to +by an inheriting template. A detailed walkthrough of this usage can be found at :ref:`inheritance_toplevel`. + +Note above that named blocks don't have any argument declaration the way defs do. They still implement themselves +as Python functions, however, so they can be invoked additional times beyond their initial definition: + +.. sourcecode:: mako + + <div name="page"> + <%block name="pagecontrol"> + <a href="">previous page</a> | + <a href="">next page</a> + </%block> + + <table> + ## some content + </table> + + ${pagecontrol()} + </div> + +The content referenced by ``pagecontrol`` above will be rendered both above and below the ``<table>`` tags. + +To keep things sane, named blocks have restrictions that defs do not: + +* The ``<%block>`` declaration cannot have any argument signature. +* The name of a ``<%block>`` can only be defined once in a template -- an error is raised if two blocks of the same + name occur anywhere in a single template, regardless of nesting. A similar error is raised if a top level def + shares the same name as that of a block. +* A named ``<%block>`` cannot be defined within a ``<%def>``, or inside the body of a "call", i.e. + ``<%call>`` or ``<%namespacename:defname>`` tag. Anonymous blocks can, however. + +Using Page Arguments in Named Blocks +------------------------------------ + +A named block is very much like a top level def. It has a similar +restriction to these types of defs in that arguments passed to the +template via the ``<%page>`` tag aren't automatically available. +Using arguments with the ``<%page>`` tag is described in the section +:ref:`namespaces_body`, and refers to scenarios such as when the +``body()`` method of a template is called from an inherited template passing +arguments, or the template is invoked from an ``<%include>`` tag +with arguments. To allow a named block to share the same arguments +passed to the page, the ``args`` attribute can be used: + +.. sourcecode:: mako + + <%page args="post"/> + + <a name="${post.title}" /> + + <span class="post_prose"> + <%block name="post_prose" args="post"> + ${post.content} + </%block> + </span> + +Where above, if the template is called via a directive like +``<%include file="post.mako" args="post=post" />``, the ``post`` +variable is available both in the main body as well as the +``post_prose`` block. + +Similarly, the ``**pageargs`` variable is present, in named blocks only, +for those arguments not explicit in the ``<%page>`` tag: + +.. sourcecode:: mako + + <%block name="post_prose"> + ${pageargs['post'].content} + </%block> + +The ``args`` attribute is only allowed with named blocks. With +anonymous blocks, the Python function is always rendered in the same +scope as the call itself, so anything available directly outside the +anonymous block is available inside as well. |