--- /dev/null
+{% macro input_field(name, value='', type='text') -%}
+ <input type="{{ type }}" value="{{ value|e }}" name="{{ name }}">
+{%- endmacro %}
+
+{% macro textarea(name, value='', rows=10, cols=40) -%}
+ <textarea name="{{ name }}" rows="{{ rows }}" cols="{{ cols }}">{{
+ value|e }}</textarea>
+{%- endmacro %}
+
+{% macro form(action='', method='post') -%}
+ <form action="{{ action|e }}" method="{{ method }}">{{ caller() }}</form>
+{%- endmacro %}
--- /dev/null
+{% extends "layout.html" %}
+{% from "helpers.html" import input_field, textarea, form %}
+{% block page_title %}Index Page{% endblock %}
+{% block body %}
+ {%- for article in articles %}
+ <div class="article">
+ <h2><a href="{{ article.href|e }}">{{ article.title|e }}</a></h2>
+ <p class="meta">written by <a href="{{ article.user.href|e
+ }}">{{ article.user.username|e }}</a> on {{ article.pub_date|dateformat }}</p>
+ <div class="text">{{ article.body }}</div>
+ </div>
+ {%- endfor %}
+ {%- call form() %}
+ <dl>
+ <dt>Name</dt>
+ <dd>{{ input_field('name') }}</dd>
+ <dt>E-Mail</dt>
+ <dd>{{ input_field('email') }}</dd>
+ <dt>URL</dt>
+ <dd>{{ input_field('url') }}</dd>
+ <dt>Comment</dd>
+ <dd>{{ textarea('comment') }}</dd>
+ </dl>
+ {{ input_field(type='submit', value='Submit') }}
+ {%- endcall %}
+{% endblock %}
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>{% block page_title %}{% endblock %} | RealWorld Benchmark</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head>
+<body>
+ <div class="contents">
+ <div class="header">
+ <h1>RealWorld Benchmark</h1>
+ <blockquote><p>
+ A less stupid benchmark for Mako and Jinja2 to get an impression how
+ code changes affect runtime performance.
+ </p></blockquote>
+ </div>
+ <ul class="navigation">
+ {%- for href, caption in page_navigation %}
+ <li><a href="{{ href|e }}">{{ caption }}</a></li>
+ {%- endfor %}
+ </ul>
+ <div class="body">
+ {% block body %}{% endblock %}
+ </div>
+ <div class="footer">
+ © Copyright 2008 by I don't know who.
+ </div>
+ </div>
+</body>
+</html>
--- /dev/null
+<%def name="input_field(name='', value='', type='text')">
+ <input type="${type}" value="${value|h}" name="${name}">
+</%def>
+
+<%def name="textarea(name, value='', rows=10, cols=40)">
+ <textarea name="${name}" rows="${rows}" cols="${cols}">${value|h}</textarea>
+</%def>
+
+<%def name="form(action='', method='post')">
+ <form action="${action|h}" method="${method}">${caller.body()}</form>
+</%def>
--- /dev/null
+<%!
+ from rwbench import dateformat
+%>
+<%inherit file="layout.html" />
+<%namespace file="helpers.html" import="input_field, textarea, form" />
+<%def name="page_title()">Index Page</%def>
+% for article in articles:
+<div class="article">
+ <h2><a href="${article.href|h}">${article.title|h}</a></h2>
+ <p class="meta">written by <a href="${article.user.href|h
+ }">${article.user.username|h}</a> on ${dateformat(article.pub_date)}</p>
+ <div class="text">${article.body}</div>
+</div>
+% endfor
+<%call expr="form()">
+ <dl>
+ <dt>Name</dt>
+ <dd>${input_field('name')}</dd>
+ <dt>E-Mail</dt>
+ <dd>${input_field('email')}</dd>
+ <dt>URL</dt>
+ <dd>${input_field('url')}</dd>
+ <dt>Comment</dd>
+ <dd>${textarea('comment')}</dd>
+ </dl>
+ ${input_field(type='submit', value='Submit')}
+</%call>
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>${self.page_title()} | RealWorld Benchmark</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head>
+<body>
+ <div class="contents">
+ <div class="header">
+ <h1>RealWorld Benchmark</h1>
+ <blockquote><p>
+ A less stupid benchmark for Mako and Jinja2 to get an impression how
+ code changes affect runtime performance.
+ </p></blockquote>
+ </div>
+ <ul class="navigation">
+ % for href, caption in page_navigation:
+ <li><a href="${href|h}">${caption}</a></li>
+ % endfor
+ </ul>
+ <div class="body">
+ ${self.body()}
+ </div>
+ <div class="footer">
+ © Copyright 2008 by I don't know who.
+ </div>
+ </div>
+</body>
+</html>
+<%def name="page_title()"></%def>
--- /dev/null
+# -*- coding: utf-8 -*-
+"""
+ RealWorldish Benchmark
+ ~~~~~~~~~~~~~~~~~~~~~~
+
+ A more real-world benchmark of Jinja2.
+
+ :copyright: Copyright 2008 by Armin Ronacher.
+ :license: BSD.
+"""
+import sys
+from os.path import join, dirname, abspath
+from random import choice, randrange
+from datetime import datetime
+from timeit import Timer
+from jinja2 import Environment, FileSystemLoader
+from jinja2.utils import generate_lorem_ipsum
+from mako.lookup import TemplateLookup
+
+
+ROOT = abspath(dirname(__file__))
+
+
+def dateformat(x):
+ return x.strftime('%Y-%m-%d')
+
+
+jinja_env = Environment(loader=FileSystemLoader(join(ROOT, 'jinja')))
+jinja_env.filters['dateformat'] = dateformat
+
+mako_lookup = TemplateLookup(directories=[join(ROOT, 'mako')])
+
+
+class Article(object):
+
+ def __init__(self, id):
+ self.id = id
+ self.href = '/article/%d' % self.id
+ self.title = generate_lorem_ipsum(1, False, 5, 10)
+ self.user = choice(users)
+ self.body = generate_lorem_ipsum()
+ self.pub_date = datetime.utcfromtimestamp(randrange(1000000000,
+ 2000000000))
+
+
+class User(object):
+
+ def __init__(self, username):
+ self.href = '/user/%s' % username
+ self.username = username
+
+
+users = map(User, [u'John Doe', u'Jane Doe', u'Peter Somewhat'])
+articles = map(Article, range(20))
+navigation = [
+ ('index', 'Index'),
+ ('about', 'About'),
+ ('foo?bar=1', 'Foo with Bar'),
+ ('foo?bar=2&s=x', 'Foo with X')
+]
+
+context = dict(users=users, articles=articles, page_navigation=navigation)
+
+
+jinja_template = jinja_env.get_template('index.html')
+mako_template = mako_lookup.get_template('index.html')
+
+
+def test_jinja():
+ jinja_template.render(context)
+
+def test_mako():
+ mako_template.render_unicode(**context)
+
+
+if __name__ == '__main__':
+ sys.stdout.write('Realworldish Benchmark:\n')
+ for test in 'jinja', 'mako':
+ t = Timer(setup='from __main__ import test_%s as bench' % test,
+ stmt='bench()')
+ sys.stdout.write(' >> %-20s<running>' % test)
+ sys.stdout.flush()
+ sys.stdout.write('\r %-20s%.4f seconds\n' % (test, t.timeit(number=50) / 50))
if isinstance(node.arg, nodes.Const) and \
isinstance(node.arg.value, basestring) and \
((isinstance(node.node, nodes.Name) and
+ # this code ignores parameter declared names as the may only
+ # occour at the very beginning of a scope and we pull the
+ # attributes afterwards.
node.node.name not in (self.identifiers.declared_locally)) or
node.node in self.identifiers.static_subscribes):
if node in self.identifiers.static_subscribes:
self.identifiers.static_subscribes[node] = 1
def visit_Macro(self, node):
- self.generic_visit(node)
self.identifiers.declared_locally.add(node.name)
def visit_Import(self, node):
self.writeline('import %s as %s' % (imp, alias))
# add the load name
- self.writeline('name = %r' % self.filename)
+ self.writeline('name = %r' % self.name)
# generate the root render function.
self.writeline('def root(context, environment=environment):', extra=1)
self.writeline('if l_%s is missing:' % alias)
self.indent()
self.writeline('l_%s = environment.undefined(%r %% '
- 'included_template.name, '
+ 'included_template.__name__, '
'name=%r)' %
(alias, 'the template %r does not export '
'the requested name ' + repr(name), name))
if self.__name__ is None:
name = 'memory:%x' % id(self)
else:
- name = repr(self.name)
+ name = repr(self.__name__)
return '<%s %s>' % (self.__class__.__name__, name)
'markup_join', 'unicode_join']
-def markup_join(*args):
+def markup_join(seq):
"""Concatenation that escapes if necessary and converts to unicode."""
buf = []
- iterator = imap(soft_unicode, args)
+ iterator = imap(soft_unicode, seq)
for arg in iterator:
buf.append(arg)
if hasattr(arg, '__html__'):
return concat(buf)
-def unicode_join(*args):
+def unicode_join(seq):
"""Simple args to unicode conversion and concatenation."""
- return concat(imap(unicode, args))
+ return concat(imap(unicode, seq))
class Context(object):