diff options
Diffstat (limited to 'doc/build/namespaces.rst')
-rw-r--r-- | doc/build/namespaces.rst | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/doc/build/namespaces.rst b/doc/build/namespaces.rst new file mode 100644 index 0000000..afd323d --- /dev/null +++ b/doc/build/namespaces.rst @@ -0,0 +1,475 @@ +.. _namespaces_toplevel: + +========== +Namespaces +========== + +Namespaces are used to organize groups of defs into +categories, and also to "import" defs from other files. + +If the file ``components.html`` defines these two defs: + +.. sourcecode:: mako + + ## components.html + <%def name="comp1()"> + this is comp1 + </%def> + + <%def name="comp2(x)"> + this is comp2, x is ${x} + </%def> + +you can make another file, for example ``index.html``, that +pulls those two defs into a namespace called ``comp``: + +.. sourcecode:: mako + + ## index.html + <%namespace name="comp" file="components.html"/> + + Here's comp1: ${comp.comp1()} + Here's comp2: ${comp.comp2(x=5)} + +The ``comp`` variable above is an instance of +:class:`.Namespace`, a **proxy object** which delivers +method calls to the underlying template callable using the +current context. + +``<%namespace>`` also provides an ``import`` attribute which can +be used to pull the names into the local namespace, removing the +need to call it via the "``.``" operator. When ``import`` is used, the +``name`` attribute is optional. + +.. sourcecode:: mako + + <%namespace file="components.html" import="comp1, comp2"/> + + Heres comp1: ${comp1()} + Heres comp2: ${comp2(x=5)} + +``import`` also supports the "``*``" operator: + +.. sourcecode:: mako + + <%namespace file="components.html" import="*"/> + + Heres comp1: ${comp1()} + Heres comp2: ${comp2(x=5)} + +The names imported by the ``import`` attribute take precedence +over any names that exist within the current context. + +.. note:: In current versions of Mako, usage of ``import='*'`` is + known to decrease performance of the template. This will be + fixed in a future release. + +The ``file`` argument allows expressions -- if looking for +context variables, the ``context`` must be named explicitly: + +.. sourcecode:: mako + + <%namespace name="dyn" file="${context['namespace_name']}"/> + +Ways to Call Namespaces +======================= + +There are essentially four ways to call a function from a +namespace. + +The "expression" format, as described previously. Namespaces are +just Python objects with functions on them, and can be used in +expressions like any other function: + +.. sourcecode:: mako + + ${mynamespace.somefunction('some arg1', 'some arg2', arg3='some arg3', arg4='some arg4')} + +Synonymous with the "expression" format is the "custom tag" +format, when a "closed" tag is used. This format, introduced in +Mako 0.2.3, allows the usage of a "custom" Mako tag, with the +function arguments passed in using named attributes: + +.. sourcecode:: mako + + <%mynamespace:somefunction arg1="some arg1" arg2="some arg2" arg3="some arg3" arg4="some arg4"/> + +When using tags, the values of the arguments are taken as +literal strings by default. To embed Python expressions as +arguments, use the embedded expression format: + +.. sourcecode:: mako + + <%mynamespace:somefunction arg1="${someobject.format()}" arg2="${somedef(5, 12)}"/> + +The "custom tag" format is intended mainly for namespace +functions which recognize body content, which in Mako is known +as a "def with embedded content": + +.. sourcecode:: mako + + <%mynamespace:somefunction arg1="some argument" args="x, y"> + Some record: ${x}, ${y} + </%mynamespace:somefunction> + +The "classic" way to call defs with embedded content is the ``<%call>`` tag: + +.. sourcecode:: mako + + <%call expr="mynamespace.somefunction(arg1='some argument')" args="x, y"> + Some record: ${x}, ${y} + </%call> + +For information on how to construct defs that embed content from +the caller, see :ref:`defs_with_content`. + +.. _namespaces_python_modules: + +Namespaces from Regular Python Modules +====================================== + +Namespaces can also import regular Python functions from +modules. These callables need to take at least one argument, +``context``, an instance of :class:`.Context`. A module file +``some/module.py`` might contain the callable: + +.. sourcecode:: python + + def my_tag(context): + context.write("hello world") + return '' + +A template can use this module via: + +.. sourcecode:: mako + + <%namespace name="hw" module="some.module"/> + + ${hw.my_tag()} + +Note that the ``context`` argument is not needed in the call; +the :class:`.Namespace` tag creates a locally-scoped callable which +takes care of it. The ``return ''`` is so that the def does not +dump a ``None`` into the output stream -- the return value of any +def is rendered after the def completes, in addition to whatever +was passed to :meth:`.Context.write` within its body. + +If your def is to be called in an "embedded content" context, +that is as described in :ref:`defs_with_content`, you should use +the :func:`.supports_caller` decorator, which will ensure that Mako +will ensure the correct "caller" variable is available when your +def is called, supporting embedded content: + +.. sourcecode:: python + + from mako.runtime import supports_caller + + @supports_caller + def my_tag(context): + context.write("<div>") + context['caller'].body() + context.write("</div>") + return '' + +Capturing of output is available as well, using the +outside-of-templates version of the :func:`.capture` function, +which accepts the "context" as its first argument: + +.. sourcecode:: python + + from mako.runtime import supports_caller, capture + + @supports_caller + def my_tag(context): + return "<div>%s</div>" % \ + capture(context, context['caller'].body, x="foo", y="bar") + +Declaring Defs in Namespaces +============================ + +The ``<%namespace>`` tag supports the definition of ``<%def>``\ s +directly inside the tag. These defs become part of the namespace +like any other function, and will override the definitions +pulled in from a remote template or module: + +.. sourcecode:: mako + + ## define a namespace + <%namespace name="stuff"> + <%def name="comp1()"> + comp1 + </%def> + </%namespace> + + ## then call it + ${stuff.comp1()} + +.. _namespaces_body: + +The ``body()`` Method +===================== + +Every namespace that is generated from a template contains a +method called ``body()``. This method corresponds to the main +body of the template, and plays its most important roles when +using inheritance relationships as well as +def-calls-with-content. + +Since the ``body()`` method is available from a namespace just +like all the other defs defined in a template, what happens if +you send arguments to it? By default, the ``body()`` method +accepts no positional arguments, and for usefulness in +inheritance scenarios will by default dump all keyword arguments +into a dictionary called ``pageargs``. But if you actually want +to get at the keyword arguments, Mako recommends you define your +own argument signature explicitly. You do this via using the +``<%page>`` tag: + +.. sourcecode:: mako + + <%page args="x, y, someval=8, scope='foo', **kwargs"/> + +A template which defines the above signature requires that the +variables ``x`` and ``y`` are defined, defines default values +for ``someval`` and ``scope``, and sets up ``**kwargs`` to +receive all other keyword arguments. If ``**kwargs`` or similar +is not present, the argument ``**pageargs`` gets tacked on by +Mako. When the template is called as a top-level template (i.e. +via :meth:`~.Template.render`) or via the ``<%include>`` tag, the +values for these arguments will be pulled from the ``Context``. +In all other cases, i.e. via calling the ``body()`` method, the +arguments are taken as ordinary arguments from the method call. +So above, the body might be called as: + +.. sourcecode:: mako + + ${self.body(5, y=10, someval=15, delta=7)} + +The :class:`.Context` object also supplies a :attr:`~.Context.kwargs` +accessor, for cases when you'd like to pass along the top level context +arguments to a ``body()`` callable: + +.. sourcecode:: mako + + ${next.body(**context.kwargs)} + +The usefulness of calls like the above become more apparent when +one works with inheriting templates. For more information on +this, as well as the meanings of the names ``self`` and +``next``, see :ref:`inheritance_toplevel`. + +.. _namespaces_builtin: + +Built-in Namespaces +=================== + +The namespace is so great that Mako gives your template one (or +two) for free. The names of these namespaces are ``local`` and +``self``. Other built-in namespaces include ``parent`` and +``next``, which are optional and are described in +:ref:`inheritance_toplevel`. + +.. _namespace_local: + +``local`` +--------- + +The ``local`` namespace is basically the namespace for the +currently executing template. This means that all of the top +level defs defined in your template, as well as your template's +``body()`` function, are also available off of the ``local`` +namespace. + +The ``local`` namespace is also where properties like ``uri``, +``filename``, and ``module`` and the ``get_namespace`` method +can be particularly useful. + +.. _namespace_self: + +``self`` +-------- + +The ``self`` namespace, in the case of a template that does not +use inheritance, is synonymous with ``local``. If inheritance is +used, then ``self`` references the topmost template in the +inheritance chain, where it is most useful for providing the +ultimate form of various "method" calls which may have been +overridden at various points in an inheritance chain. See +:ref:`inheritance_toplevel`. + +Inheritable Namespaces +====================== + +The ``<%namespace>`` tag includes an optional attribute +``inheritable="True"``, which will cause the namespace to be +attached to the ``self`` namespace. Since ``self`` is globally +available throughout an inheritance chain (described in the next +section), all the templates in an inheritance chain can get at +the namespace imported in a super-template via ``self``. + +.. sourcecode:: mako + + ## base.html + <%namespace name="foo" file="foo.html" inheritable="True"/> + + ${next.body()} + + ## somefile.html + <%inherit file="base.html"/> + + ${self.foo.bar()} + +This allows a super-template to load a whole bunch of namespaces +that its inheriting templates can get to, without them having to +explicitly load those namespaces themselves. + +The ``import="*"`` part of the ``<%namespace>`` tag doesn't yet +interact with the ``inheritable`` flag, so currently you have to +use the explicit namespace name off of ``self``, followed by the +desired function name. But more on this in a future release. + +Namespace API Usage Example - Static Dependencies +================================================== + +The ``<%namespace>`` tag at runtime produces an instance of +:class:`.Namespace`. Programmatic access of :class:`.Namespace` can be used +to build various kinds of scaffolding in templates and between templates. + +A common request is the ability for a particular template to declare +"static includes" - meaning, the usage of a particular set of defs requires +that certain Javascript/CSS files are present. Using :class:`.Namespace` as the +object that holds together the various templates present, we can build a variety +of such schemes. In particular, the :class:`.Context` has a ``namespaces`` +attribute, which is a dictionary of all :class:`.Namespace` objects declared. +Iterating the values of this dictionary will provide a :class:`.Namespace` +object for each time the ``<%namespace>`` tag was used, anywhere within the +inheritance chain. + + +.. _namespace_attr_for_includes: + +Version One - Use :attr:`.Namespace.attr` +----------------------------------------- + +The :attr:`.Namespace.attr` attribute allows us to locate any variables declared +in the ``<%! %>`` of a template. + +.. sourcecode:: mako + + ## base.mako + ## base-most template, renders layout etc. + <html> + <head> + ## traverse through all namespaces present, + ## look for an attribute named 'includes' + % for ns in context.namespaces.values(): + % for incl in getattr(ns.attr, 'includes', []): + ${incl} + % endfor + % endfor + </head> + <body> + ${next.body()} + </body + </html> + + ## library.mako + ## library functions. + <%! + includes = [ + '<link rel="stylesheet" type="text/css" href="mystyle.css"/>', + '<script type="text/javascript" src="functions.js"></script>' + ] + %> + + <%def name="mytag()"> + <form> + ${caller.body()} + </form> + </%def> + + ## index.mako + ## calling template. + <%inherit file="base.mako"/> + <%namespace name="foo" file="library.mako"/> + + <%foo:mytag> + a form + </%foo:mytag> + + +Above, the file ``library.mako`` declares an attribute ``includes`` inside its global ``<%! %>`` section. +``index.mako`` includes this template using the ``<%namespace>`` tag. The base template ``base.mako``, which is the inherited parent of ``index.mako`` and is responsible for layout, then locates this attribute and iterates through its contents to produce the includes that are specific to ``library.mako``. + +Version Two - Use a specific named def +----------------------------------------- + +In this version, we put the includes into a ``<%def>`` that +follows a naming convention. + +.. sourcecode:: mako + + ## base.mako + ## base-most template, renders layout etc. + <html> + <head> + ## traverse through all namespaces present, + ## look for a %def named 'includes' + % for ns in context.namespaces.values(): + % if hasattr(ns, 'includes'): + ${ns.includes()} + % endif + % endfor + </head> + <body> + ${next.body()} + </body + </html> + + ## library.mako + ## library functions. + + <%def name="includes()"> + <link rel="stylesheet" type="text/css" href="mystyle.css"/> + <script type="text/javascript" src="functions.js"></script> + </%def> + + <%def name="mytag()"> + <form> + ${caller.body()} + </form> + </%def> + + + ## index.mako + ## calling template. + <%inherit file="base.mako"/> + <%namespace name="foo" file="library.mako"/> + + <%foo:mytag> + a form + </%foo:mytag> + +In this version, ``library.mako`` declares a ``<%def>`` named ``includes``. The example works +identically to the previous one, except that ``base.mako`` looks for defs named ``include`` +on each namespace it examines. + +API Reference +============= + +.. autoclass:: mako.runtime.Namespace + :show-inheritance: + :members: + +.. autoclass:: mako.runtime.TemplateNamespace + :show-inheritance: + :members: + +.. autoclass:: mako.runtime.ModuleNamespace + :show-inheritance: + :members: + +.. autofunction:: mako.runtime.supports_caller + +.. autofunction:: mako.runtime.capture + |