Skip to content

Instantly share code, notes, and snippets.

@Xion
Created January 30, 2012 20:45
Show Gist options
  • Save Xion/1706583 to your computer and use it in GitHub Desktop.
Save Xion/1706583 to your computer and use it in GitHub Desktop.
from jinja2.ext import Extension
from jinja2.nodes import CallBlock, Output, MarkSafe
class CaptureExtension(Extension):
''' Generic capture extension, useful for providing
content that should go into specific places in HTML template,
such as the <head> tag for JavaScript includes.
Syntax for providing content for so-called 'dataset' (here it's "js"):
{% store 'foo' in 'js' %}
<script ... >
{% endstore %}
and for emitting it:
{% emit 'js' %}
Extension inspired heavily by http://stackoverflow.com/a/6090560/434799 ,
but improved and refined somewhat.
'''
tags = set(['store', 'emit'])
def __init__(self, environment):
super(CaptureExtension, self).__init__(environment)
environment.extend(captured = {})
def parse(self, parser):
''' Parsing function. Recognizes tags and produces
appropriate nodes.
'''
tag = parser.stream.next()
parse_method = getattr(self, '_parse_%s_tag' % tag.value)
return parse_method(parser, tag)
def _parse_store_tag(self, parser, tag):
''' Parses the {% store %} tag.
@return: A template node for the tag
'''
key = parser.parse_tuple(simplified = True, extra_end_rules = ['name:in'])
parser.stream.skip() # skipping 'in'
dataset = parser.parse_expression()
body = parser.parse_statements(['name:end' + tag.value], drop_needle = True)
node = CallBlock(self.call_method('_exec_store', [key, dataset]), [], [], body)
node.set_lineno(tag.lineno) # for debugging
return node
def _parse_emit_tag(self, parser, tag):
''' Parses the {% emit %} tag.
@return: A template node for the tag
'''
dataset = parser.parse_expression()
emit_call_node = self.call_method('_exec_emit', [dataset], lineno = tag.lineno)
nodes = [MarkSafe(emit_call_node)]
return Output(nodes)
def _exec_store(self, key, dataset, caller):
''' Executes the {% store %} command.
@return: Empty string (this tag does not produce output)
'''
dataset_content = self.environment.captured.setdefault(dataset, {})
if key not in dataset_content:
dataset_content[key] = caller()
return ""
def _exec_emit(self, dataset):
''' Executes the {% emit %} command.
@return: Content of specified dataset as string
'''
dataset_content = self.environment.captured.get(dataset, {})
output = "\n".join(dataset_content.itervalues())
return output
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment