diff --git a/lib/mako/codegen.py b/lib/mako/codegen.py index 5151feb5f90eef885c59885c63d53583b56790a9..1619426c1feabd38e28a062432d2b4a1fffeb5bd 100644 --- a/lib/mako/codegen.py +++ b/lib/mako/codegen.py @@ -178,7 +178,7 @@ class _GenerateRenderMethod(object): self.write_source_comment(node) self.printer.writeline("def make_namespace():") export = [] - identifiers = self.identifiers #.branch(node) + identifiers = self.identifiers.branch(node) class NSComponentVisitor(object): def visitComponentTag(s, node): self.write_inline_component(node, identifiers) @@ -198,7 +198,28 @@ class _GenerateRenderMethod(object): def visitComponentTag(self, node): pass def visitCallTag(self, node): - pass + self.write_source_comment(node) + self.printer.writeline("def ccall():") + export = ['body'] + identifiers = self.identifiers.branch(node) + self.write_variable_declares(identifiers) + class ComponentVisitor(object): + def visitComponentTag(s, node): + export.append(node.name) + vis = ComponentVisitor() + for n in node.nodes: + n.accept_visitor(vis) + self.printer.writeline("def body():") + for n in node.nodes: + n.accept_visitor(self) + self.printer.writeline("return ''") + self.printer.writeline(None) + self.printer.writeline("context.push(**{%s})" % (','.join(["%s:%s" % (repr(x), x) for x in export]))) + self.printer.writeline("context.write(unicode(%s))" % node.attributes['expr']) + self.printer.writeline("context.pop()") + self.printer.writeline(None) + self.printer.writeline("ccall()") + def visitInheritTag(self, node): pass @@ -272,3 +293,12 @@ class _Identifiers(object): pass def visitNamespaceTag(self, node): self.check_declared(node) + if node is self.node: + for n in node.nodes: + n.accept_visitor(self) + + def visitCallTag(self, node): + self.check_declared(node) + if node is self.node: + for n in node.nodes: + n.accept_visitor(self) \ No newline at end of file diff --git a/lib/mako/parsetree.py b/lib/mako/parsetree.py index 849b6e9c038774a7b1aa0b1e2ebe624da2df7559..9c42625de5a786731adf5f445d367cf72dca2e05 100644 --- a/lib/mako/parsetree.py +++ b/lib/mako/parsetree.py @@ -186,8 +186,8 @@ class Tag(Node): for x in re.split(r'(\${.+?})', self.attributes[key]): m = re.match(r'^\${(.+?)}$', x) if m: - code = ast.PythonCode(m.group(1), self.lineno, self.pos) - undeclared_identifiers = undeclared_identifiers.union(code.undeclared_identifiers) + #code = ast.PythonCode(m.group(1), self.lineno, self.pos) + #undeclared_identifiers = undeclared_identifiers.union(code.undeclared_identifiers) expr.append(m.group(1)) else: expr.append(repr(x)) @@ -237,6 +237,11 @@ class CallTag(Tag): __keyword__ = 'call' def __init__(self, keyword, attributes, **kwargs): super(CallTag, self).__init__(keyword, attributes, (), ('expr',), ('expr',), **kwargs) + self.code = ast.PythonCode(attributes['expr'], self.lineno, self.pos) + def declared_identifiers(self): + return self.code.declared_identifiers + def undeclared_identifiers(self): + return self.code.undeclared_identifiers class InheritTag(Tag): __keyword__ = 'inherit' diff --git a/lib/mako/runtime.py b/lib/mako/runtime.py index 4f2347c343a63fb51db259ce96d1c5c9f591ba48..3409ff748a5205dabca08d76412cb3fb140d7bdf 100644 --- a/lib/mako/runtime.py +++ b/lib/mako/runtime.py @@ -6,22 +6,28 @@ class Context(object): def __init__(self, template, buffer, **data): # TODO: not sure if Context should need template + buffer etc. self.buffer = buffer - self.data = data + self.stack = [data] # the Template instance currently rendering with this context. self.with_template = template def __getitem__(self, key): - return self.data[key] + return self.stack[-1][key] def get(self, key, default=None): - return self.data.get(key, default) + return self.stack[-1].get(key, default) def write(self, string): self.buffer.write(string) def update(self, **args): """produce a copy of this Context, updating the argument dictionary with the given keyword arguments.""" - x = self.data.copy() + x = self.stack[-1].copy() x.update(args) c = Context(self.with_template, self.buffer, **x) return c + def push(self, **args): + x = self.stack[-1].copy() + x.update(args) + self.stack.append(args) + def pop(self): + self.stack.pop() class Namespace(object): """provides access to collections of rendering methods, which can be local, from other templates, or from imported modules""" diff --git a/test/template.py b/test/component.py similarity index 92% rename from test/template.py rename to test/component.py index 8dd2f3e4420203b7848a758e9e574b16093499f9..39d51cc613576a3c4f127e2e275068a3aa15540b 100644 --- a/test/template.py +++ b/test/component.py @@ -36,6 +36,25 @@ class ComponentTest(unittest.TestCase): #print template.code assert template.render(variable='hi', a=5, b=6).strip() == """hello mycomp hi, 5, 6""" + def test_outer_scope(self): + t = Template(""" + + <%component name="a"> + a: x is ${x} + </%component> + + <%component name="b"> + <% + x = 10 + %> + b. x is ${x}. ${a()} + </%component> + + ${b()} +""") + #print t.code + print t.render(x=5) + def test_inter_component(self): """test components calling each other""" template = Template(""" @@ -292,26 +311,30 @@ class NestedComponentTest(unittest.TestCase): result = re.sub(r'[\s\n]+', ' ', result).strip() print result assert result == "heres y: 5 now heres y 7 a, heres y: 7 a, now heres y: 10 a, heres b: b, heres y: 10 b, heres c: this is c b, heres y again: 19 heres y again: 7" - -class NamespaceTest(unittest.TestCase): - def test_inline(self): - template = """ - <%namespace name="x"> - <%component name="a"> - this is x a - </%component> - <%component name="b"> - this is x b, and heres ${x.a()} + + def test_outer_scope(self): + t = Template(""" + + <%component name="a"> + a: x is ${x} + </%component> + + <%component name="b"> + <%component name="c"> + <% + x = 10 + %> + c. x is ${x}. ${a()} </%component> - </%namespace> - - ${x.a()} - - ${x.b()} -""" - t = Template(template) + + b. ${c()} + </%component> + + ${b()} +""") print t.code - print t.render() + print t.render(x=5) + class ExceptionTest(unittest.TestCase): def test_raise(self):