aboutsummaryrefslogtreecommitdiffstats
path: root/doc/build/inheritance.rst
diff options
context:
space:
mode:
Diffstat (limited to 'doc/build/inheritance.rst')
-rw-r--r--doc/build/inheritance.rst283
1 files changed, 248 insertions, 35 deletions
diff --git a/doc/build/inheritance.rst b/doc/build/inheritance.rst
index e8fe2c2..60775fa 100644
--- a/doc/build/inheritance.rst
+++ b/doc/build/inheritance.rst
@@ -4,6 +4,12 @@
Inheritance
===========
+.. note:: Most of the inheritance examples here take advantage of a feature that's
+ new in Mako as of version 0.4.1 called the "block". This tag is very similar to
+ the "def" tag but is more streamlined for usage with inheritance. Note that
+ all of the examples here which use blocks can also use defs instead. Constrasting
+ usages will be illustrated.
+
Using template inheritance, two or more templates can organize
themselves into an **inheritance chain**, where content and
functions from all involved templates can be intermixed. The
@@ -14,7 +20,7 @@ to send the executional control to template ``B`` at runtime
the **inherited** template, then makes decisions as to what
resources from ``A`` shall be executed.
-In practice, it looks like this. Heres a hypothetical inheriting
+In practice, it looks like this. Here's a hypothetical inheriting
template, ``index.html``:
.. sourcecode:: mako
@@ -22,9 +28,9 @@ template, ``index.html``:
## index.html
<%inherit file="base.html"/>
- <%def name="header()">
+ <%block name="header">
this is some header content
- </%def>
+ </%block>
this is the body content.
@@ -36,42 +42,47 @@ And ``base.html``, the inherited template:
<html>
<body>
<div class="header">
- ${self.header()}
+ <%block name="header"/>
</div>
${self.body()}
<div class="footer">
- ${self.footer()}
+ <%block name="footer">
+ this is the footer
+ </%block>
</div>
</body>
</html>
- <%def name="footer()">
- this is the footer
- </%def>
-
Here is a breakdown of the execution:
* When ``index.html`` is rendered, control immediately passes to
``base.html``.
* ``base.html`` then renders the top part of an HTML document,
- then calls the method ``header()`` off of a built in namespace
+ then invokes the ``<%block name="header">`` block. It invokes the
+ underlying ``header()`` function off of a built in namespace
called ``self`` (this namespace was first introduced in the
- Namespaces chapter in
- :ref:`namespace_self`). Since
- ``index.html`` is the topmost template and also defines a def
- called ``header()``, its this ``header()`` def that gets
- executed.
+ Namespaces chapter in :ref:`namespace_self`). Since
+ ``index.html`` is the topmost template and also defines a block
+ called ``header``, its this ``header`` block that ultimately gets
+ executed - instead of the one that's present in ``base.html``.
* Control comes back to ``base.html``. Some more HTML is
rendered.
* ``base.html`` executes ``self.body()``. The ``body()``
function on all template-based namespaces refers to the main
body of the template, therefore the main body of
``index.html`` is rendered.
+* When ``<%block name="header">`` is encountered in ``index.html``
+ during the ``self.body()`` call, a conditional is checked - does the
+ current inherited template, i.e. ``base.html``, also define this block ? If yes,
+ the ``<%block>`` is **not** executed here - the inheritance
+ mechanism knows that the parent template is responsible for rendering
+ this block (and in fact it already has). In other words a block
+ only renders in its *basemost scope*.
* Control comes back to ``base.html``. More HTML is rendered,
- then the ``self.footer()`` expression is invoked.
-* The ``footer`` def is only defined in ``base.html``, so being
+ then the ``<%block name="footer">`` expression is invoked.
+* The ``footer`` block is only defined in ``base.html``, so being
the topmost definition of ``footer``, its the one that
executes. If ``index.html`` also specified ``footer``, then
its version would **override** that of the base.
@@ -104,6 +115,208 @@ seriously; while useful to setup some commonly recognized
semantics, a textual template is not very much like an
object-oriented class construct in practice).
+Nesting Blocks
+==============
+
+The named blocks defined in an inherited template can also be nested within
+other blocks. The name given to each block is globally accessible via any inheriting
+template. We can add a new block ``title`` to our ``header`` block:
+
+.. sourcecode:: mako
+
+ ## base.html
+ <html>
+ <body>
+ <div class="header">
+ <%block name="header">
+ <h2>
+ <%block name="title"/>
+ </h2>
+ </%block>
+ </div>
+
+ ${self.body()}
+
+ <div class="footer">
+ <%block name="footer">
+ this is the footer
+ </%block>
+ </div>
+ </body>
+ </html>
+
+The inheriting template can name either or both of ``header`` and ``title``, separately
+or nested themselves:
+
+.. sourcecode:: mako
+
+ ## index.html
+ <%inherit file="base.html"/>
+
+ <%block name="header">
+ this is some header content
+ ${parent.header()}
+ </%block>
+
+ <%block name="title">
+ this is the title
+ </%block>
+
+ this is the body content.
+
+Note when we overrode ``header``, we added an extra call ``${parent.header()}`` in order to invoke
+the parent's ``header`` block in addition to our own. That's described in more detail below,
+in :ref:`parent_namespace`.
+
+Rendering a named block multiple times
+======================================
+
+Recall from the section :ref:`blocks` that a named block is just like a ``<%def>``,
+with some different usage rules. We can call one of our named sections distinctly, for example
+a section that is used more than once, such as the title of a page:
+
+.. sourcecode:: mako
+
+ <html>
+ <head>
+ <title>${self.title()}</title>
+ </head>
+ <body>
+ <%block name="header">
+ <h2><%block name="title"/></h2>
+ </%block>
+ ${self.body()}
+ </body>
+ </html>
+
+Where above an inheriting template can define ``<%block name="title">`` just once, and it will be
+used in the base template both in the ``<title>`` section as well as the ``<h2>``.
+
+But what about defs ?
+=====================
+
+The previous example used the ``<%block>`` tag to produce areas of content
+to be overridden. Before Mako 0.4.1, there wasn't any such tag - instead
+there was only the ``<%def>`` tag. As it turns out, named blocks and defs are
+largely interchangeable. The def simply doesn't call itself automatically,
+and has more open-ended naming and scoping rules that are more flexible and similar
+to Python itself, but less suited towards layout. The first example from
+this chapter using defs would look like:
+
+.. sourcecode:: mako
+
+ ## index.html
+ <%inherit file="base.html"/>
+
+ <%def name="header()">
+ this is some header content
+ </%def>
+
+ this is the body content.
+
+And ``base.html``, the inherited template:
+
+.. sourcecode:: mako
+
+ ## base.html
+ <html>
+ <body>
+ <div class="header">
+ ${self.header()}
+ </div>
+
+ ${self.body()}
+
+ <div class="footer">
+ ${self.footer()}
+ </div>
+ </body>
+ </html>
+
+ <%def name="header()"/>
+ <%def name="footer()">
+ this is the footer
+ </%def>
+
+Above, we illustrate that defs differ from blocks in that their definition
+and invocation are defined in two separate places, instead of at once. You can *almost* do exactly what a
+block does if you put the two together:
+
+.. sourcecode:: mako
+
+ <div class="header">
+ <%def name="header()"></%def>${self.header()}
+ </div>
+
+The ``<%block>`` is obviously more streamlined than the ``<%def>`` for this kind
+of usage. In addition,
+the above "inline" approach with ``<%def>`` does not work with nesting:
+
+.. sourcecode:: mako
+
+ <head>
+ <%def name="header()">
+ <title>
+ ## this won't work !
+ <%def name="title()">default title</%def>${self.title()}
+ </title>
+ </%def>${self.header()}
+ </head>
+
+Where above, the ``title()`` def, because it's a def within a def, is not part of the
+template's exported namespace and will not be part of ``self``. If the inherited template
+did define its own ``title`` def at the top level, it would be called, but the "default title"
+above is not present at all on ``self`` no matter what. For this to work as expected
+you'd instead need to say:
+
+.. sourcecode:: mako
+
+ <head>
+ <%def name="header()">
+ <title>
+ ${self.title()}
+ </title>
+ </%def>${self.header()}
+
+ <%def name="title()"/>
+ </head>
+
+That is, ``title`` is defined outside of any other defs so that it is in the ``self`` namespace.
+It works, but the definition needs to be potentially far away from the point of render.
+
+A named block is always placed in the ``self`` namespace, regardless of nesting,
+so this restriction is lifted:
+
+.. sourcecode:: mako
+
+ ## base.html
+ <head>
+ <%block name="header">
+ <title>
+ <%block name="title"/>
+ </title>
+ </%block>
+ </head>
+
+The above template defines ``title`` inside of ``header``, and an inheriting template can define
+one or both in **any** configuration, nested inside each other or not, in order for them to be used:
+
+.. sourcecode:: mako
+
+ ## index.html
+ <%inherit file="base.html"/>
+ <%block name="title">
+ the title
+ </%block>
+ <%block name="header">
+ the header
+ </%block>
+
+So while the ``<%block>`` tag lifts the restriction of nested blocks not being available externally,
+in order to achieve this it *adds* the restriction that all block names in a single template need
+to be globally unique within the template, and additionally that a ``<%block>`` can't be defined
+inside of a ``<%def>``. It's a more restricted tag suited towards a more specific use case than ``<%def>``.
+
Using the "next" namespace to produce content wrapping
=======================================================
@@ -127,20 +340,19 @@ Lets change the line in ``base.html`` which calls upon
<html>
<body>
<div class="header">
- ${self.header()}
+ <%block name="header"/>
</div>
${next.body()}
<div class="footer">
- ${self.footer()}
+ <%block name="footer">
+ this is the footer
+ </%block>
</div>
</body>
</html>
- <%def name="footer()">
- this is the footer
- </%def>
Lets also add an intermediate template called ``layout.html``,
which inherits from ``base.html``:
@@ -150,17 +362,16 @@ which inherits from ``base.html``:
## layout.html
<%inherit file="base.html"/>
<ul>
- ${self.toolbar()}
+ <%block name="toolbar">
+ <li>selection 1</li>
+ <li>selection 2</li>
+ <li>selection 3</li>
+ </%block>
</ul>
<div class="mainlayout">
${next.body()}
</div>
- <%def name="toolbar()">
- <li>selection 1</li>
- <li>selection 2</li>
- <li>selection 3</li>
- </%def>
And finally change ``index.html`` to inherit from
``layout.html`` instead:
@@ -215,15 +426,17 @@ Without the ``next`` namespace, only the main body of
``index.html`` could be used; there would be no way to call
``layout.html``'s body content.
+.. _parent_namespace:
+
Using the "parent" namespace to augment defs
=============================================
Lets now look at the other inheritance-specific namespace, the
opposite of ``next`` called ``parent``. ``parent`` is the
namespace of the template **immediately preceding** the current
-template. What is most useful about this namespace is the
-methods within it which can be accessed within overridden
-versions of those methods. This is not as hard as it sounds and
+template. What's useful about this namespace is that
+defs or blocks can call upon their overridden versions.
+This is not as hard as it sounds and
is very much like using the ``super`` keyword in Python. Lets
modify ``index.html`` to augment the list of selections provided
by the ``toolbar`` function in ``layout.html``:
@@ -233,16 +446,16 @@ by the ``toolbar`` function in ``layout.html``:
## index.html
<%inherit file="layout.html"/>
- <%def name="header()">
+ <%block name="header">
this is some header content
- </%def>
+ </%block>
- <%def name="toolbar()">
+ <%block name="toolbar">
## call the parent's toolbar first
${parent.toolbar()}
<li>selection 4</li>
<li>selection 5</li>
- </%def>
+ </%block>
this is the body content.