staching

Compact implementation of Mustache logic-less templating. Fork of Stache.


License
MIT
Install
pip install staching==0.0.1

Documentation

staching

Compact implementation of the Mustache logic-less templating language. This is a fork of the Stache project. See: https://github.com/hyperturtle/Stache https://pypi.python.org/pypi/Stache/0.0.9

The biggest changes are:

  • The render_js functionality has been removed making stache an even lighter weight implementation of Mustache

  • Formatting line feeds after Mustache section tags were not being stripped properly staching now distinguishes between block and inline section tags and formats appropriately

  • staching.py is a single file so can be easily embedded in another project without it being an external dependency

  • staching.py can be run from the command line to render a template with json data

  • Convenience functions

Implements everything from Mustache.5 except for lambdas in one small python file.

Plus five new things:

  • Implied closing tags {{/}}
  • Self referencer {{.}},
  • Existence check {{?exists}}{{/exists}}
  • Data pusher {{< blah}}{{/blah}}
  • Default {{:default}}

Quick Start

import staching

# setup the data dictionary

with open(pathtotemplatefile, "r") as fp:
    content = staching.render(fp.read(), data)

Compiles all the templates and returns a template object.

stacher = Stache()
# setup data dict
stacher.add_template('template_name', templatefile.read())
content = stacher.render_template('template_name', data)

Overview

Fast lightweight implementation. It consists of two main methods, _tokenize, and _parse, both python generators. _tokenize creates tokens and _parse consumes and renders them.

Existing Stuff

{{tag}}

Renders the value of tag, html escaped, within the current scope

{{{unescape}}} & {{&unescape}}

Don't html escape the value

{{#section}}{{/section}}

Section blocks. Renders the enclosed block if

  • section is true
  • section exists

If section exists and is a(n):

  • Array: It renders the enclosed block for each element in the array, placing the current element in scope
  • Dict: It renders the enclosed block once and places the Dict as the current scope

{{^invert}}{{/invert}}

Renders the enclosed block if invert is an empty string, empty array, false, or doesn't exist. The opposite the the section block.

{{! comments - ignore me }}

Ignores the text within the tag

{{>partial}}

Looks up the partial template and renders it with the current context

New Stuff

{{/}} Implied closing tag

Whenever you use {{/}} it implies the closing of the nearest block.

{{#open}}stuff goes here{{/}}

Is the same as:

{{#open}}stuff goes here{{/open}}

{{.}} Self Referencer

This renders the current "scope". This is useful if you want to iterate over an array and wrap them.

{{#array}}<li>{{.}}</li>\n{{/array}}

with array = [1,2,3,'yay'] will produce:

<li>1</li>
<li>2</li>
<li>3</li>
<li>yay</li>

Existence Check {{?exists}}{{/}}

Forces a check of the tag name, rather than imply that it is a section block. This is useful for check if an array has members rather than iterate over the members

{{?array}}
stuff\n
{{/}}

with {array: [1, 2, 3, 4]} results in:

stuff

as opposed to

{{#array}}
stuff\n
{{/}}

which would render

stuff
stuff
stuff
stuff

{{:default}}stuff{{/}}

This is equivalent to {{default}}{{^default}}stuff{{/}}

It renders the enclosed section if default doesn't exist, empty or false

{{<thing}} Pusher {{/thing}}

It renders the inner block and adds it to the global scope.

{{<thing}}
It takes this. You can put anything in here.
{{tags}}, {{#blocks}}{{/blocks}}, etc.
{{/thing}}

and it populates the global scope with a key of thing. Watch out, it can override existing vars. A convention such as

{{<namespace.thing}}{{/namespace.thing}}

or similiar will help with collisions. This is helpful if you want to use stache templates for masterpages/inheritance. Lets say you have these templates:

master =

<div id="header">
{{header}}
</div>

<div id="footer">
{{footer}}
</div>

page =

{{<header}}
{{name}}
{{/header}}

{{<footer}}
footer
{{/footer}}

{{>master}}

Rendering the page template with {'name': 'Stachio'} will produce

<div id="header">
Stachio
</div>

<div id="footer">
footer
</div>

You can also apply the inverted block or default block to supply default blocks

master =

<div id="header">
{{header}}
{{^header}}Default Header{{/header}}
</div>

<div id="footer">
{{:footer}}Default Footer{{/footer}}
</div>

Rendering {{<footer}}Custom Footer{{/footer}}{{>master}} with {} will produce

<div id="header">
Default Header
</div>

<div id="footer">
Custom Footer
</div>

Install

pip install staching

Test

You can run python test.py or if you have nosetests:

cd staching
nosetests

Benchmark

python test.py

Usage:

>>> from staching import Stache
>>> Stache().render("Hello {{who}}!", dict(who="World"))
Hello World

or

>>> import staching
>>> Stache.render("Hello {{world}}!", dict(world="Stache!"))
Hello Stache!

To populate partials:

>>> from staching import Stache
>>> stachio = Stache()
>>> stachio.add_template('main', 'a = {{a}};')
>>> stachio.add_template('main1', 'b = [ {{#b}}{{.}} {{/b}}];')
>>> stachio.add_template('main2', 'stachio')
>>> stachio.add_template('woah', '{{>main}} {{>main1}} {{>main2}}')
>>> stachio.render_template('woah',dict(a=1, b=[1,2,3,4,5]))
a = 1; b = [ 1 2 3 4 5 ] stachio

If you want to put in dynamic file loading of partials you can override Stache().templates with a dict() like object and override the __get__ and load the template in __get__ if it doesn't exist. Once you load up the template, you'll need to call self.add_template(template_name, template) to tokenize the template.

I don't think this is ideal though... Ideas for populating partials are welcome.

Efficient use with async wsgi:

For wsgi apps that support async, you can yield parts of the rendered template as they render. render_iter and render_template_iter both produce iterators that are yield'ed as it is generated.

>>> for part in Stache.render_iter("Hello {{world}}!", dict(world="Stache!")):
>>>     yield part
Hello
Stache!

Timeline: