diff options
Diffstat (limited to 'doc/build/inheritance.rst')
| -rw-r--r-- | doc/build/inheritance.rst | 283 |
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. |
