blob: ccdefa2ff313e6fb1d61c340075468bc3eb06878 [file] [log] [blame]
Armin Ronacher023b5e92008-05-08 11:03:10 +02001from jinja2 import nodes
2from jinja2.ext import Extension
3
4
Armin Ronacher762079c2008-05-08 23:57:56 +02005class FragmentCacheExtension(Extension):
6 # a set of names that trigger the extension.
Armin Ronacher023b5e92008-05-08 11:03:10 +02007 tags = set(['cache'])
8
9 def __init__(self, environment):
Armin Ronacher762079c2008-05-08 23:57:56 +020010 super(FragmentCacheExtension, self).__init__(environment)
Armin Ronacher023b5e92008-05-08 11:03:10 +020011
Armin Ronacher762079c2008-05-08 23:57:56 +020012 # add the defaults to the environment
13 environment.extend(
14 fragment_cache_prefix='',
15 fragment_cache=None
16 )
Armin Ronacher023b5e92008-05-08 11:03:10 +020017
18 def parse(self, parser):
19 # the first token is the token that started the tag. In our case
20 # we only listen to ``'cache'`` so this will be a name token with
21 # `cache` as value. We get the line number so that we can give
22 # that line number to the nodes we create by hand.
jenisysfa3a3022015-05-09 18:57:52 +020023 lineno = next(parser.stream).lineno
Armin Ronacher023b5e92008-05-08 11:03:10 +020024
25 # now we parse a single expression that is used as cache key.
26 args = [parser.parse_expression()]
27
Armin Ronacher762079c2008-05-08 23:57:56 +020028 # if there is a comma, the user provided a timeout. If not use
29 # None as second parameter.
Armin Ronacherfdf95302008-05-11 22:20:51 +020030 if parser.stream.skip_if('comma'):
Armin Ronacher023b5e92008-05-08 11:03:10 +020031 args.append(parser.parse_expression())
Armin Ronacher023b5e92008-05-08 11:03:10 +020032 else:
33 args.append(nodes.Const(None))
34
35 # now we parse the body of the cache block up to `endcache` and
36 # drop the needle (which would always be `endcache` in that case)
37 body = parser.parse_statements(['name:endcache'], drop_needle=True)
38
39 # now return a `CallBlock` node that calls our _cache_support
40 # helper method on this extension.
Armin Ronacher27069d72008-05-11 19:48:12 +020041 return nodes.CallBlock(self.call_method('_cache_support', args),
42 [], [], body).set_lineno(lineno)
Armin Ronacher023b5e92008-05-08 11:03:10 +020043
44 def _cache_support(self, name, timeout, caller):
45 """Helper callback."""
Armin Ronacher762079c2008-05-08 23:57:56 +020046 key = self.environment.fragment_cache_prefix + name
Armin Ronacher023b5e92008-05-08 11:03:10 +020047
Armin Ronacher762079c2008-05-08 23:57:56 +020048 # try to load the block from the cache
Armin Ronacher023b5e92008-05-08 11:03:10 +020049 # if there is no fragment in the cache, render it and store
50 # it in the cache.
Armin Ronacher762079c2008-05-08 23:57:56 +020051 rv = self.environment.fragment_cache.get(key)
Armin Ronacher7850dc52009-02-08 11:11:57 +010052 if rv is not None:
Armin Ronacher762079c2008-05-08 23:57:56 +020053 return rv
Armin Ronacherd89f0f32009-02-04 18:57:27 +010054 rv = caller()
55 self.environment.fragment_cache.add(key, rv, timeout)
Armin Ronacher023b5e92008-05-08 11:03:10 +020056 return rv