Templating

This narrative covers various aspects of Twiddler behavior that help with using multiple Twiddlers to render a complete piece of output. This commonly occurs when rendering pages using a common site look and feel.

Clone Method

When you call the replace or repeat methods on a Twiddler, it
alters the object on which you call the method. This is often
undesirable. For example, when rendering a template in a web
application, you don't want to modify the template itself!

For this reason, each twiddler has a clone method. This method
creates a full and independent copy of the object it's called on.

For example, we can clone this Twiddler:

>>> from twiddler import Twiddler
>>> t1 = Twiddler('''<html>
...   <body>
...   <div id="content">This is our page content!</div>
...   </body>
... </html>''')
>>> t2 = t1.clone()

Now we can modify the clone:

>>> t2['content'].replace('A Rendered Page')
>>> print t2.render()
<html>
  <body>
  <div id="content">A Rendered Page</div>
  </body>
</html>

The original remains pristine:

>>> print t1.render()
<html>
  <body>
  <div id="content">This is our page content!</div>
  </body>
</html>

Of course, if we now modify t1, it has no effect on t2:

>>> t1['content'].replace('We changed the template!')
>>> print t1.render()
<html>
  <body>
  <div id="content">We changed the template!</div>
  </body>
</html>
>>> print t2.render()
<html>
  <body>
  <div id="content">A Rendered Page</div>
  </body>
</html>

Be careful you don't confuse the clone method of a Twiddler with
the clone method of a Twiddler element. It's the clone method of
the Twiddler we are talking about here, the clone method of
Twiddler elements is used in generating recursive output and is
described in repeat.txt.

Combining Templates with Pages

You may be wondering why the execute method exists. To explain
this, we will expand on the templating example from readme.txt.

Here's our site template, this time with a code block:

>>> from twiddler.input.default import DefaultWithCodeBlock
>>> site_template = Twiddler('''<html>
... <!--twiddler
... def template_manipulation(t,title):
...   t['title'].replace(title)
... -->
...   <body>
...   <h1 id="title">The Site Header</h1>
...   <div id="content">Content goes here</div>
...   </body>
... </html>''',input=DefaultWithCodeBlock)

Now we want a template to display page objects. This template
should use the site template above, but we want to have as little
code as possible outside these two templates. The problem is that
this means we need to do the cloning of the site template in the
code block of our page template. We also need to render the code
block in the site template, but we already know that only the
first code block in a Twiddler will get rendered. The solution is
to clone the site template and then call its execute method with
the right parameters, all inside the code block of the page
template: 

>>> page_template = Twiddler("""<html>
... <!--twiddler
... def render_page(t,template,page):
...   st = template.clone()
...   st.execute(page['title'])
...   st['content'].replace(t['content'])
...   st['author'].replace(page['author'])
...   st['body'].replace(page['body'])
...   # This next step is how we indicate that we want the cloned
...   # and manipulated site template to be what is rendered by
...   # the render method:
...   return st
... -->
...   <body>
...   <div id="content">
...    <div id="author">Mr Smithers</div>
...    <div id="body">
...    This is the page body!
...    </div>
...   </div>
...   </body>
... </html>""",input=DefaultWithCodeBlock)

Finally, this is how we render the page template so that it has
access to both the page data and the site template:

>>> page = {
...     'title':'The Test Page',
...     'author':'Monty Burns',
...     'body':'\nTesting bodies are fine bodies.\n',
... }
>>> print page_template.render(site_template,page)
<html>
  <body>
  <h1 id="title">The Test Page</h1>
  <div id="content">
   <div id="author">Monty Burns</div>
   <div id="body">
Testing bodies are fine bodies.
</div>
  </div>
  </body>
</html>
changed November 13, 2007