-
Notifications
You must be signed in to change notification settings - Fork 0
Complex Template Inheritance
Cinje so far has avoided adding an over-abundance of magical inheritance, capture, placeholder, and other processes common to other engines. When your templates are Python standard functions, there's no need for magic as you can just pass template generators around and consume them as desired.
An example of a "complex template" might be component-based approach towards page generation. Because emitting HTML pages is the typical use for a template engine like this some standardized HTML templates are provided built-in under the cinje.std
namespace. To demonstrate use, we'll be dissecting the cinje.std.html:page
template.
To get started, let's define a basic HTML5 page template:
# encoding: cinje
: def page
<!DOCTYPE html>
<html>
<head>
</head>
<body>
: yield
</body>
</html>
: end
While this will suffice, clearly there are a few things missing. We'll expand this as we go, but to quickly illustrate how you would now use this "wrapping template" (note the presence of a bare : yield
statement) here is another template that makes use of the page template:
# encoding: cinje
: from cinje.std.html import page
: def my_page
: using page
<p>Hello.</p>
Running cinje.flatten(my_page())
would result in the following HTML:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>Hello.</p>
</body>
</html>
An HTML page generally contains references to external assets in the header, and usually JavaScript links are added to the bottom. Pages also have titles and other metadata (such as social sharing details), so our generic page wrapping template should support these. However, we're likely not going to cover every possible case, so we should provide some way to override the generation of these sections.
To accomplish this, let's define two new template functions to go with the page
one, that accept some arguments for the data they'll emit:
: def default_header title, metadata=[], styles=[]
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
: for name, value in metadata
<meta&{name=name, content=value}>
: end
<title>${title}</title>
: for href in styles
<link&{href=href, rel="stylesheet"}>
: end
: end
: def default_footer scripts=[]
: for href in scripts
<script&{src=href}></script>
: end
: end
As a note, defining default lists like that has consequences, but it's okay in this instance because we only ever read those values.
Let's re-define the page
wrapper template definition to allow passing values through.
: def page title, header=default_header, footer=default_footer, metadata=[], styles=[], scripts=[], **attributes
You can see that we're now passing in the placeholder templates, as well as lists of metadata, styles, scripts, and any other keyword argument the user of the template wishes. To update the page template to make use of this, change the <html>
declaration to:
<html&{lang=attributes.pop('lang', 'en')}>
Within the <head>
section, add:
: if header
: use header metadata=metadata, styles=styles
: end
Update the <body>
declaration thusly:
<body&{attributes, role='document'}>
Then to use the footer, add the following after the : yield
:
: if footer
: use footer scripts=scripts
: end
Now the keyword values will be applied as HTML attributes on the <body>
, excepting lang
which is applied to the <html>
tag, the default body role is "document", and if a header and footer are supplied (they are by default), then metadata, styles, and scripts will be generated as appropriate.
Now you can easily use the page template, and easily override the header or footer generation. Interestingly, you can : use
the default ones within your overridden ones if you only wish to add more data:
: from functools import partial
: from cinje.std.html import default_header, page
: def my_header title, metadata=[], styles=[]
# Added before...
: use default_header title, metadata, styles
# Added after...
: end
: my_page = partial(page, header=my_header)
First class functions for life.