updated macro stuff
--HG--
branch : trunk
diff --git a/jinja2/compiler.py b/jinja2/compiler.py
index 5c64699..bdf195f 100644
--- a/jinja2/compiler.py
+++ b/jinja2/compiler.py
@@ -381,7 +381,7 @@
for arg in node.defaults:
self.visit(arg)
self.write(', ')
- self.write('), %r)' % accesses_arguments)
+ self.write('), %r, make_undefined)' % accesses_arguments)
def visit_ExprStmt(self, node, frame):
self.newline(node)
@@ -447,6 +447,8 @@
self.visit(node.target, assignment_frame)
self.write(' = ')
self.visit(node.node, frame)
+
+ # make sure toplevel assignments are added to the context.
if frame.toplevel:
for name in assignment_frame.assigned_names:
self.writeline('context[%r] = l_%s' % (name, name))
diff --git a/jinja2/runtime.py b/jinja2/runtime.py
index 7af5c4a..c1c34e1 100644
--- a/jinja2/runtime.py
+++ b/jinja2/runtime.py
@@ -14,7 +14,7 @@
defaultdict = None
-__all__ = ['extends', 'subscribe', 'TemplateContext']
+__all__ = ['extends', 'subscribe', 'TemplateContext', 'Macro']
def extends(template, namespace):
@@ -33,44 +33,79 @@
class TemplateContext(dict):
+ """
+ Holds the variables of the local template or of the global one. It's
+ not save to use this class outside of the compiled code. For example
+ update and other methods will not work as they seem (they don't update
+ the exported variables for example).
+ """
def __init__(self, globals, undefined_factory, filename):
- dict.__init__(self)
- self.globals = globals
+ dict.__init__(self, globals)
+ self.exported = set()
self.undefined_factory = undefined_factory
self.filename = filename
self.filters = {}
self.tests = {}
+ def __setitem__(self, key, value):
+ """If we set items to the dict we track the variables set so
+ that includes can access the exported variables."""
+ dict.__setitem__(self, key, value)
+ self.exported.add(key)
+
+ def __delitem__(self, key):
+ """On delete we no longer export it."""
+ dict.__delitem__(self, key)
+ self.exported.dicard(key)
+
+ def get_exported(self):
+ """Get a dict of all exported variables."""
+ return dict((k, self[k]) for k in self.exported)
+
# if there is a default dict, dict has a __missing__ method we can use.
if defaultdict is None:
def __getitem__(self, name):
if name in self:
return self[name]
- elif name in self.globals:
- return self.globals[name]
return self.undefined_factory(name)
else:
def __missing__(self, key):
- try:
- return self.globals[key]
- except:
- return self.undefined_factory(key)
+ return self.undefined_factory(key)
class Macro(object):
+ """
+ Wraps a macor
+ """
- def __init__(self, func, name, arguments, defaults, catch_all):
+ def __init__(self, func, name, arguments, defaults, catch_all, \
+ undefined_factory):
self.func = func
self.name = name
self.arguments = arguments
self.defaults = defaults
self.catch_all = catch_all
+ self.undefined_factory = undefined_factory
def __call__(self, *args, **kwargs):
- if len(args) > len(self.arguments):
+ arg_count = len(self.arguments)
+ if len(args) > arg_count:
raise TypeError('macro %r takes not more than %d argument(s).' %
(self.name, len(self.arguments)))
arguments = {}
- # XXX: assemble arguments
- return u''.join(self.func(*args, **kwargs))
+ for idx, name in enumerate(self.arguments):
+ try:
+ value = args[idx]
+ except IndexError:
+ try:
+ value = kwargs.pop(name)
+ except KeyError:
+ try:
+ value = self.defaults[idx - arg_count]
+ except IndexError:
+ value = self.undefined_factory(name)
+ arguments['l_' + name] = arg
+ if self.catch_all:
+ arguments['l_arguments'] = kwargs
+ return u''.join(self.func(**arguments))