[ZPT] Zope 2 should use Zope 3's ZPT?

Chris Withers chris at simplistix.co.uk
Tue Nov 23 05:06:22 EST 2004


Yet another good reason why Zope 2 should use Zope 3's ZPT.

I remember someone talking about this. Can they remember who they are?
And if so, how's it going?

cheers,

Chris

Shane Hathaway wrote:

> Log message for revision 28489:
>   Templates now allow metal:define-macro and metal:use-macro in the same tag.
>   
>   This allows a macro to extend another macro, which is particularly 
>   useful for writing a skin that customizes another skin.
>   
> 
> Changed:
>   U   Zope3/trunk/doc/CHANGES.txt
>   U   Zope3/trunk/src/zope/tal/taldefs.py
>   U   Zope3/trunk/src/zope/tal/talgenerator.py
>   U   Zope3/trunk/src/zope/tal/talinterpreter.py
>   A   Zope3/trunk/src/zope/tal/tests/input/acme_template.pt
>   A   Zope3/trunk/src/zope/tal/tests/input/document_list.pt
>   A   Zope3/trunk/src/zope/tal/tests/input/pnome_template.pt
>   U   Zope3/trunk/src/zope/tal/tests/input/test_metal7.html
>   A   Zope3/trunk/src/zope/tal/tests/output/acme_template.html
>   A   Zope3/trunk/src/zope/tal/tests/output/acme_template_source.html
>   A   Zope3/trunk/src/zope/tal/tests/output/document_list.html
>   A   Zope3/trunk/src/zope/tal/tests/output/document_list_source.html
>   U   Zope3/trunk/src/zope/tal/tests/output/test_metal1.html
>   U   Zope3/trunk/src/zope/tal/tests/test_talinterpreter.py
> 
> -=-
> Modified: Zope3/trunk/doc/CHANGES.txt
> ===================================================================
> --- Zope3/trunk/doc/CHANGES.txt	2004-11-22 10:15:51 UTC (rev 28488)
> +++ Zope3/trunk/doc/CHANGES.txt	2004-11-22 16:38:56 UTC (rev 28489)
> @@ -10,15 +10,20 @@
>  
>      New features
>  
> +      - Page templates now allow metal:define-macro and
> +        metal:use-macro in the same tag.  This allows a macro to
> +        extend another macro, which is particularly useful for writing
> +        a skin that customizes another skin.
> +
>        - Added pagelet concept. Pagelets are responsible for a piece 
>          of content in a view. They can be used to render additionaly 
>          provided information into a pagetemplate.
>  
> -        + Added tal expression 'pagelet'
> +        + Added tales expression 'pagelet'
>  
> -        + Added tal expression 'pagelets'
> +        + Added tales expression 'pagelets'
>  
> -        + Added tal expression 'pagedata'
> +        + Added tales expression 'pagedata'
>          
>        - Added pagelet chooser for store pagelet name in the annotation
>          of a object.
> 
> Modified: Zope3/trunk/src/zope/tal/taldefs.py
> ===================================================================
> --- Zope3/trunk/src/zope/tal/taldefs.py	2004-11-22 10:15:51 UTC (rev 28488)
> +++ Zope3/trunk/src/zope/tal/taldefs.py	2004-11-22 16:38:56 UTC (rev 28489)
> @@ -19,7 +19,7 @@
>  from zope.tal.interfaces import ITALExpressionErrorInfo
>  from zope.interface import implements
>  
> -TAL_VERSION = "1.5"
> +TAL_VERSION = "1.5.1"
>  
>  XML_NS = "http://www.w3.org/XML/1998/namespace" # URI for XML namespace
>  XMLNS_NS = "http://www.w3.org/2000/xmlns/" # URI for XML NS declarations
> 
> Modified: Zope3/trunk/src/zope/tal/talgenerator.py
> ===================================================================
> --- Zope3/trunk/src/zope/tal/talgenerator.py	2004-11-22 10:15:51 UTC (rev 28488)
> +++ Zope3/trunk/src/zope/tal/talgenerator.py	2004-11-22 16:38:56 UTC (rev 28489)
> @@ -387,6 +387,14 @@
>          self.inMacroUse = 0
>          self.emit("useMacro", expr, cexpr, self.popSlots(), program)
>  
> +    def emitExtendMacro(self, defineName, useExpr):
> +        cexpr = self.compileExpression(useExpr)
> +        program = self.popProgram()
> +        self.inMacroUse = 0
> +        self.emit("extendMacro", useExpr, cexpr, self.popSlots(), program,
> +                  defineName)
> +        self.emitDefineMacro(defineName)
> +
>      def emitDefineSlot(self, slotName):
>          program = self.popProgram()
>          slotName = slotName.strip()
> @@ -538,10 +546,12 @@
>              raise I18NError("i18n:data must be accompanied by i18n:translate",
>                              position)
>  
> -        if len(metaldict) > 1 and (defineMacro or useMacro):
> -            raise METALError("define-macro and use-macro cannot be used "
> -                             "together or with define-slot or fill-slot",
> -                             position)
> +        if defineMacro or useMacro:
> +            if fillSlot or defineSlot:
> +                raise METALError(
> +                    "define-slot and fill-slot cannot be used with "
> +                    "define-macro or use-macro", position)
> +
>          if replace:
>              if content:
>                  raise TALError(
> @@ -827,10 +837,13 @@
>              self.emitDefineSlot(defineSlot)
>          if fillSlot:
>              self.emitFillSlot(fillSlot)
> -        if useMacro:
> -            self.emitUseMacro(useMacro)
> -        if defineMacro:
> -            self.emitDefineMacro(defineMacro)
> +        if useMacro or defineMacro:
> +            if useMacro and defineMacro:
> +                self.emitExtendMacro(defineMacro, useMacro)
> +            elif useMacro:
> +                self.emitUseMacro(useMacro)
> +            elif defineMacro:
> +                self.emitDefineMacro(defineMacro)
>          if useMacro or defineSlot:
>              # generate a source annotation after define-slot or use-macro
>              # because the source file might have changed
> 
> Modified: Zope3/trunk/src/zope/tal/talinterpreter.py
> ===================================================================
> --- Zope3/trunk/src/zope/tal/talinterpreter.py	2004-11-22 10:15:51 UTC (rev 28488)
> +++ Zope3/trunk/src/zope/tal/talinterpreter.py	2004-11-22 16:38:56 UTC (rev 28489)
> @@ -181,7 +181,10 @@
>          self.html = 0
>          self.endsep = "/>"
>          self.endlen = len(self.endsep)
> +        # macroStack contains:
> +        # [(macroName, slots, definingName, extending, entering, i18ncontext)]
>          self.macroStack = []
> +        self.inUseDirective = False
>          self.position = None, None  # (lineno, offset)
>          self.col = 0
>          self.level = 0
> @@ -220,11 +223,12 @@
>          assert self.level == level
>          assert self.scopeLevel == scopeLevel
>  
> -    def pushMacro(self, macroName, slots, entering=1):
> +    def pushMacro(self, macroName, slots, definingName, extending, entering=1):
>          if len(self.macroStack) >= self.stackLimit:
>              raise METALError("macro nesting limit (%d) exceeded "
>                               "by %s" % (self.stackLimit, `macroName`))
> -        self.macroStack.append([macroName, slots, entering, self.i18nContext])
> +        self.macroStack.append([macroName, slots, definingName, extending,
> +                                entering, self.i18nContext])
>  
>      def popMacro(self):
>          return self.macroStack.pop()
> @@ -361,28 +365,29 @@
>          try:
>              for item in attrList:
>                  if _len(item) == 2:
> -                    name, s = item
> +                    rendered = item[1:]
>                  else:
>                      # item[2] is the 'action' field:
>                      if item[2] in ('metal', 'tal', 'xmlns', 'i18n'):
>                          if not self.showtal:
>                              continue
> -                        ok, name, s = self.attrAction(item)
> +                        rendered = self.attrAction(item)
>                      else:
> -                        ok, name, s = attrAction(self, item)
> -                    if not ok:
> +                        rendered = attrAction(self, item)
> +                    if not rendered:
>                          continue
> -                slen = _len(s)
> -                if (wrap and
> -                    col >= align and
> -                    col + 1 + slen > wrap):
> -                    append("\n")
> -                    append(" "*align)
> -                    col = align + slen
> -                else:
> -                    append(" ")
> -                    col = col + 1 + slen
> -                append(s)
> +                for s in rendered:
> +                    slen = _len(s)
> +                    if (wrap and
> +                        col >= align and
> +                        col + 1 + slen > wrap):
> +                        append("\n")
> +                        append(" "*align)
> +                        col = align + slen
> +                    else:
> +                        append(" ")
> +                        col = col + 1 + slen
> +                    append(s)
>              append(end)
>              col = col + endlen
>          finally:
> @@ -393,33 +398,47 @@
>      def attrAction(self, item):
>          name, value, action = item[:3]
>          if action == 'insert':
> -            return 0, name, value
> +            return ()
>          macs = self.macroStack
>          if action == 'metal' and self.metal and macs:
> -            if len(macs) > 1 or not macs[-1][2]:
> -                # Drop all METAL attributes at a use-depth above one.
> -                return 0, name, value
> +            # Drop all METAL attributes at a use-depth beyond the first
> +            # use-macro and its extensions
> +            if len(macs) > 1:
> +                for macro in macs[1:]:
> +                    if macro is None:
> +                        return ()
> +                    extending = macro[3]
> +                    if not extending:
> +                        return ()
> +            if not macs[-1][4]:
> +                return ()
>              # Clear 'entering' flag
> -            macs[-1][2] = 0
> +            macs[-1][4] = 0
>              # Convert or drop depth-one METAL attributes.
>              i = name.rfind(":") + 1
>              prefix, suffix = name[:i], name[i:]
>              if suffix == "define-macro":
>                  # Convert define-macro as we enter depth one.
> -                name = prefix + "use-macro"
> -                value = macs[-1][0] # Macro name
> +                useName = macs[0][0]
> +                defName = macs[0][2]
> +                res = []
> +                if defName:
> +                    res.append('%sdefine-macro=%s' % (prefix, quote(defName)))
> +                if useName:
> +                    res.append('%suse-macro=%s' % (prefix, quote(useName)))
> +                return res
>              elif suffix == "define-slot":
>                  name = prefix + "fill-slot"
>              elif suffix == "fill-slot":
>                  pass
>              else:
> -                return 0, name, value
> +                return ()
>  
>          if value is None:
>              value = name
>          else:
>              value = "%s=%s" % (name, quote(value))
> -        return 1, name, value
> +        return [value]
>  
>      def attrAction_tal(self, item):
>          name, value, action = item[:3]
> @@ -451,8 +470,9 @@
>                      value = translated
>              if value is None:
>                  value = name
> -            value = "%s=%s" % (name, quote(value))
> -        return ok, name, value
> +            return ["%s=%s" % (name, quote(value))]
> +        else:
> +            return ()
>      bytecode_handlers["<attrAction>"] = attrAction
>  
>      def no_tag(self, start, program):
> @@ -751,8 +771,10 @@
>  
>      def do_defineMacro(self, (macroName, macro)):
>          macs = self.macroStack
> +        wasInUse = self.inUseDirective
> +        self.inUseDirective = False
>          if len(macs) == 1:
> -            entering = macs[-1][2]
> +            entering = macs[-1][4]
>              if not entering:
>                  macs.append(None)
>                  self.interpret(macro)
> @@ -760,9 +782,11 @@
>                  macs.pop()
>                  return
>          self.interpret(macro)
> +        self.inUseDirective = wasInUse
>      bytecode_handlers["defineMacro"] = do_defineMacro
>  
> -    def do_useMacro(self, (macroName, macroExpr, compiledSlots, block)):
> +    def do_useMacro(self, (macroName, macroExpr, compiledSlots, block),
> +                    definingName=None, extending=False):
>          if not self.metal:
>              self.interpret(block)
>              return
> @@ -778,14 +802,18 @@
>              if mode != (self.html and "html" or "xml"):
>                  raise METALError("macro %s has incompatible mode %s" %
>                                   (`macroName`, `mode`), self.position)
> -        self.pushMacro(macroName, compiledSlots)
> +        self.pushMacro(macroName, compiledSlots, definingName, extending)
>  
>          # We want 'macroname' name to be always available as a variable
>          outer = self.engine.getValue('macroname')
>          self.engine.setLocal('macroname', macroName.split('/')[-1])
>  
>          prev_source = self.sourceFile
> +        wasInUse = self.inUseDirective
> +        self.inUseDirective = True
>          self.interpret(macro)
> +        self.inUseDirective = wasInUse
> +
>          if self.sourceFile != prev_source:
>              self.engine.setSourceFile(prev_source)
>              self.sourceFile = prev_source
> @@ -794,6 +822,19 @@
>          self.engine.setLocal('macroname', outer)
>      bytecode_handlers["useMacro"] = do_useMacro
>  
> +    def do_extendMacro(self, (macroName, macroExpr, compiledSlots, block,
> +                              definingName)):
> +        # extendMacro results from a combination of define-macro and
> +        # use-macro.  definingName has the value of the
> +        # metal:define-macro attribute.
> +        extending = False
> +        if self.metal and self.inUseDirective:
> +            # extend the calling directive.
> +            extending = True
> +        self.do_useMacro((macroName, macroExpr, compiledSlots, block),
> +                         definingName, extending)
> +    bytecode_handlers["extendMacro"] = do_extendMacro
> +
>      def do_fillSlot(self, (slotName, block)):
>          # This is only executed if the enclosing 'use-macro' evaluates
>          # to 'default'.
> @@ -806,17 +847,41 @@
>              return
>          macs = self.macroStack
>          if macs and macs[-1] is not None:
> -            macroName, slots = self.popMacro()[:2]
> -            slot = slots.get(slotName)
> +            len_macs = len(macs)
> +            # Measure the extension depth of this use-macro
> +            depth = 1
> +            while depth < len_macs:
> +                if macs[-depth][3]:
> +                    depth += 1
> +                else:
> +                    break
> +            # Search for a slot filler from the most specific to the
> +            # most general macro.  The most general is at the top of
> +            # the stack.
> +            slot = None
> +            i = len_macs - depth
> +            while i < len_macs:
> +                slots = macs[i][1]
> +                slot = slots.get(slotName)
> +                if slot is not None:
> +                    break
> +                i += 1
>              if slot is not None:
> +                # Found a slot filler.  Temporarily chop the macro
> +                # stack starting at the macro that filled the slot and
> +                # render the slot filler.
> +                chopped = macs[i:]
> +                del macs[i:]
>                  prev_source = self.sourceFile
>                  self.interpret(slot)
>                  if self.sourceFile != prev_source:
>                      self.engine.setSourceFile(prev_source)
>                      self.sourceFile = prev_source
> -                self.pushMacro(macroName, slots, entering=0)
> +                # Restore the stack entries.
> +                for mac in chopped:
> +                    mac[4] = 0  # Not entering
> +                macs.extend(chopped)
>                  return
> -            self.pushMacro(macroName, slots)
>              # Falling out of the 'if' allows the macro to be interpreted.
>          self.interpret(block)
>      bytecode_handlers["defineSlot"] = do_defineSlot
> 
> Added: Zope3/trunk/src/zope/tal/tests/input/acme_template.pt
> ===================================================================
> --- Zope3/trunk/src/zope/tal/tests/input/acme_template.pt	2004-11-22 10:15:51 UTC (rev 28488)
> +++ Zope3/trunk/src/zope/tal/tests/input/acme_template.pt	2004-11-22 16:38:56 UTC (rev 28489)
> @@ -0,0 +1,15 @@
> +<!-- This is ACME's generic look and feel, which is based on
> +PNOME's look and feel. -->
> +<html metal:use-macro="pnome_macros_page" metal:define-macro="page">
> +<head>
> +<title metal:fill-slot="title">ACME Look and Feel</title>
> +</head>
> +<body>
> +<div metal:fill-slot="page-footer">
> +Copyright 2004 Acme Inc.
> +<div metal:define-slot="disclaimer">
> +Standard disclaimers apply.
> +</div>
> +</div>
> +</body>
> +</html>
> 
> Added: Zope3/trunk/src/zope/tal/tests/input/document_list.pt
> ===================================================================
> --- Zope3/trunk/src/zope/tal/tests/input/document_list.pt	2004-11-22 10:15:51 UTC (rev 28488)
> +++ Zope3/trunk/src/zope/tal/tests/input/document_list.pt	2004-11-22 16:38:56 UTC (rev 28489)
> @@ -0,0 +1,21 @@
> +<!-- ACME's document_list uses the ACME look and feel -->
> +<html metal:use-macro="acme_macros_page">
> +<head>
> +<title metal:fill-slot="title">Acme Document List</title>
> +<style metal:fill-slot="local-styles" type="text/css">
> +  body { background-color: white; }
> +</style>
> +</head>
> +<body>
> +<div metal:fill-slot="content">
> +<h1>Documents</h1>
> +<ul>
> +<li>Rocket Science for Dummies</li>
> +<li>Birds for the Gourmet Chef</li>
> +</ul>
> +</div>
> +<div metal:fill-slot="disclaimer">
> +This document list is classified.
> +</div>
> +</body>
> +</html>
> 
> Added: Zope3/trunk/src/zope/tal/tests/input/pnome_template.pt
> ===================================================================
> --- Zope3/trunk/src/zope/tal/tests/input/pnome_template.pt	2004-11-22 10:15:51 UTC (rev 28488)
> +++ Zope3/trunk/src/zope/tal/tests/input/pnome_template.pt	2004-11-22 16:38:56 UTC (rev 28489)
> @@ -0,0 +1,23 @@
> +<!-- fakeplone is a fictional user interface created by a large,
> +well-focused team of graphics designers -->
> +<html metal:define-macro="page">
> +<head>
> +<title metal:define-slot="title">Title here</title>
> +<metal:block define-slot="local-styles">
> +</metal:block>
> +</head>
> +<body>
> +<div>
> +  <div metal:define-slot="annoying-quote">
> +  "The early bird gets the worm, but the second mouse gets the cheese."
> +  </div>
> +  <a href="#">Preferences...</a>
> +</div>
> +<div metal:define-slot="content">
> +  Content here
> +</div>
> +<div metal:define-slot="page-footer">
> +  page footer
> +</div>
> +</body>
> +</html>
> 
> Modified: Zope3/trunk/src/zope/tal/tests/input/test_metal7.html
> ===================================================================
> --- Zope3/trunk/src/zope/tal/tests/input/test_metal7.html	2004-11-22 10:15:51 UTC (rev 28488)
> +++ Zope3/trunk/src/zope/tal/tests/input/test_metal7.html	2004-11-22 16:38:56 UTC (rev 28489)
> @@ -1,4 +1,6 @@
>  <html metal:define-macro="page" i18n:domain="zope">
>      <x metal:define-slot="title" />
>  </html>
> -<html metal:use-macro="page" />
> \ No newline at end of file
> +<html metal:use-macro="page">
> +    <x metal:fill-slot="title" />
> +</html>
> 
> Added: Zope3/trunk/src/zope/tal/tests/output/acme_template.html
> ===================================================================
> --- Zope3/trunk/src/zope/tal/tests/output/acme_template.html	2004-11-22 10:15:51 UTC (rev 28488)
> +++ Zope3/trunk/src/zope/tal/tests/output/acme_template.html	2004-11-22 16:38:56 UTC (rev 28489)
> @@ -0,0 +1,26 @@
> +<!-- This is ACME's generic look and feel, which is based on
> +PNOME's look and feel. -->
> +<html>
> +<head>
> +<title>ACME Look and Feel</title>
> +
> +
> +</head>
> +<body>
> +<div>
> +  <div>
> +  "The early bird gets the worm, but the second mouse gets the cheese."
> +  </div>
> +  <a href="#">Preferences...</a>
> +</div>
> +<div>
> +  Content here
> +</div>
> +<div>
> +Copyright 2004 Acme Inc.
> +<div>
> +Standard disclaimers apply.
> +</div>
> +</div>
> +</body>
> +</html>
> 
> Added: Zope3/trunk/src/zope/tal/tests/output/acme_template_source.html
> ===================================================================
> --- Zope3/trunk/src/zope/tal/tests/output/acme_template_source.html	2004-11-22 10:15:51 UTC (rev 28488)
> +++ Zope3/trunk/src/zope/tal/tests/output/acme_template_source.html	2004-11-22 16:38:56 UTC (rev 28489)
> @@ -0,0 +1,27 @@
> +<!-- This is ACME's generic look and feel, which is based on
> +PNOME's look and feel. -->
> +<html metal:define-macro="page"
> +      metal:use-macro="pnome_macros_page">
> +<head>
> +<title metal:fill-slot="title">ACME Look and Feel</title>
> +<metal:block>
> +</metal:block>
> +</head>
> +<body>
> +<div>
> +  <div>
> +  "The early bird gets the worm, but the second mouse gets the cheese."
> +  </div>
> +  <a href="#">Preferences...</a>
> +</div>
> +<div>
> +  Content here
> +</div>
> +<div metal:fill-slot="page-footer">
> +Copyright 2004 Acme Inc.
> +<div metal:define-slot="disclaimer">
> +Standard disclaimers apply.
> +</div>
> +</div>
> +</body>
> +</html>
> 
> Added: Zope3/trunk/src/zope/tal/tests/output/document_list.html
> ===================================================================
> --- Zope3/trunk/src/zope/tal/tests/output/document_list.html	2004-11-22 10:15:51 UTC (rev 28488)
> +++ Zope3/trunk/src/zope/tal/tests/output/document_list.html	2004-11-22 16:38:56 UTC (rev 28489)
> @@ -0,0 +1,30 @@
> +<!-- ACME's document_list uses the ACME look and feel -->
> +<html>
> +<head>
> +<title>Acme Document List</title>
> +<style type="text/css">
> +  body { background-color: white; }
> +</style>
> +</head>
> +<body>
> +<div>
> +  <div>
> +  "The early bird gets the worm, but the second mouse gets the cheese."
> +  </div>
> +  <a href="#">Preferences...</a>
> +</div>
> +<div>
> +<h1>Documents</h1>
> +<ul>
> +<li>Rocket Science for Dummies</li>
> +<li>Birds for the Gourmet Chef</li>
> +</ul>
> +</div>
> +<div>
> +Copyright 2004 Acme Inc.
> +<div>
> +This document list is classified.
> +</div>
> +</div>
> +</body>
> +</html>
> 
> Added: Zope3/trunk/src/zope/tal/tests/output/document_list_source.html
> ===================================================================
> --- Zope3/trunk/src/zope/tal/tests/output/document_list_source.html	2004-11-22 10:15:51 UTC (rev 28488)
> +++ Zope3/trunk/src/zope/tal/tests/output/document_list_source.html	2004-11-22 16:38:56 UTC (rev 28489)
> @@ -0,0 +1,30 @@
> +<!-- ACME's document_list uses the ACME look and feel -->
> +<html metal:use-macro="acme_macros_page">
> +<head>
> +<title metal:fill-slot="title">Acme Document List</title>
> +<style metal:fill-slot="local-styles" type="text/css">
> +  body { background-color: white; }
> +</style>
> +</head>
> +<body>
> +<div>
> +  <div>
> +  "The early bird gets the worm, but the second mouse gets the cheese."
> +  </div>
> +  <a href="#">Preferences...</a>
> +</div>
> +<div metal:fill-slot="content">
> +<h1>Documents</h1>
> +<ul>
> +<li>Rocket Science for Dummies</li>
> +<li>Birds for the Gourmet Chef</li>
> +</ul>
> +</div>
> +<div>
> +Copyright 2004 Acme Inc.
> +<div metal:fill-slot="disclaimer">
> +This document list is classified.
> +</div>
> +</div>
> +</body>
> +</html>
> 
> Modified: Zope3/trunk/src/zope/tal/tests/output/test_metal1.html
> ===================================================================
> --- Zope3/trunk/src/zope/tal/tests/output/test_metal1.html	2004-11-22 10:15:51 UTC (rev 28488)
> +++ Zope3/trunk/src/zope/tal/tests/output/test_metal1.html	2004-11-22 16:38:56 UTC (rev 28489)
> @@ -22,7 +22,7 @@
>  
>  <span metal:use-macro="OUTER2">
>    AAA
> -  <xxx metal:fill-slot="OUTERSLOT">
> +  <xxx>
>    <span>INNER</span>
>    </xxx>
>    BBB
> @@ -48,7 +48,7 @@
>  
>  <span metal:use-macro="OUTER3">
>    AAA
> -  <xxx metal:fill-slot="OUTERSLOT">
> +  <xxx>
>    <span>INNER
>      <xxx>INNERSLOT</xxx>
>    </span>
> @@ -63,7 +63,7 @@
>  </span>
>  
>  <span metal:use-macro="INNER3">INNER
> -    <xxx metal:fill-slot="INNERSLOT">INNERSLOT</xxx>
> +    <xxx>INNERSLOT</xxx>
>    </span>
>  
>  <span metal:use-macro="INNER3">INNER
> 
> Modified: Zope3/trunk/src/zope/tal/tests/test_talinterpreter.py
> ===================================================================
> --- Zope3/trunk/src/zope/tal/tests/test_talinterpreter.py	2004-11-22 10:15:51 UTC (rev 28488)
> +++ Zope3/trunk/src/zope/tal/tests/test_talinterpreter.py	2004-11-22 16:38:56 UTC (rev 28489)
> @@ -16,12 +16,13 @@
>  
>  $Id$
>  """
> +import os
>  import sys
>  import unittest
>  
>  from StringIO import StringIO
>  
> -from zope.tal.taldefs import METALError, I18NError
> +from zope.tal.taldefs import METALError, I18NError, TAL_VERSION
>  from zope.tal.htmltalparser import HTMLTALParser
>  from zope.tal.talinterpreter import TALInterpreter
>  from zope.tal.dummyengine import DummyEngine, DummyTranslationDomain
> @@ -74,6 +75,76 @@
>          self.assertEqual(output, '<p><div>foo</div></p>')
>  
>  
> +class MacroExtendTestCase(TestCaseBase):
> +
> +    def setUp(self):
> +        s = self._read(('input', 'pnome_template.pt'))
> +        self.pnome_program, pnome_macros = self._compile(s)
> +        s = self._read(('input', 'acme_template.pt'))
> +        self.acme_program, acme_macros = self._compile(s)
> +        s = self._read(('input', 'document_list.pt'))
> +        self.doclist_program, doclist_macros = self._compile(s)
> +        macros = {
> +            'pnome_macros_page': pnome_macros['page'],
> +            'acme_macros_page': acme_macros['page'],
> +            }
> +        self.engine = DummyEngine(macros)
> +
> +    def _read(self, path):
> +        dir = os.path.dirname(__file__)
> +        fn = os.path.join(dir, *path)
> +        f = open(fn)
> +        data = f.read()
> +        f.close()
> +        return data
> +
> +    def test_acme_extends_pnome(self):
> +        # ACME inc. has a document_list template that uses ACME's
> +        # common look and feel.  ACME's look and feel is based on the
> +        # work of PNOME, Inc., a company that creates Pretty Nice
> +        # Object Management Environments for Zope.  This test verifies
> +        # that document_list works as expected.
> +        result = StringIO()
> +        interpreter = TALInterpreter(
> +            self.doclist_program, {}, self.engine, stream=result)
> +        interpreter()
> +        actual = result.getvalue().strip()
> +        expected = self._read(('output', 'document_list.html')).strip()
> +        self.assertEqual(actual, expected)
> +
> +    def test_acme_extends_pnome_source(self):
> +        # Render METAL attributes in document_list
> +        result = StringIO()
> +        interpreter = TALInterpreter(
> +            self.doclist_program, {}, self.engine, stream=result, tal=False)
> +        interpreter()
> +        actual = result.getvalue().strip()
> +        expected = self._read(('output', 'document_list_source.html')).strip()
> +        self.assertEqual(actual, expected)
> +
> +    def test_preview_acme_template(self):
> +        # An ACME designer is previewing the ACME design.  For the
> +        # purposes of this use case, extending a macro should act the
> +        # same as using a macro.
> +        result = StringIO()
> +        interpreter = TALInterpreter(
> +            self.acme_program, {}, self.engine, stream=result)
> +        interpreter()
> +        actual = result.getvalue().strip()
> +        expected = self._read(('output', 'acme_template.html')).strip()
> +        self.assertEqual(actual, expected)
> +
> +    def test_preview_acme_template_source(self):
> +        # Render METAL attributes in acme_template
> +        result = StringIO()
> +        interpreter = TALInterpreter(
> +            self.acme_program, {}, self.engine, stream=result, tal=False)
> +        interpreter()
> +        actual = result.getvalue().strip()
> +        expected = self._read(('output', 'acme_template_source.html')).strip()
> +        self.assertEqual(actual, expected)
> +        
> +
>  class I18NCornerTestCase(TestCaseBase):
>  
>      def setUp(self):
> @@ -155,7 +226,7 @@
>                      '<div>THIS IS TEXT FOR <span>BARVALUE</span>.</div>\n')
>  
>      def test_translate_static_text_as_dynamic_from_bytecode(self):
> -        program =  [('version', '1.5'),
> +        program =  [('version', TAL_VERSION),
>   ('mode', 'html'),
>  ('setPosition', (1, 0)),
>  ('beginScope', {'i18n:translate': ''}),
> @@ -441,6 +512,7 @@
>  def test_suite():
>      suite = unittest.makeSuite(I18NErrorsTestCase)
>      suite.addTest(unittest.makeSuite(MacroErrorsTestCase))
> +    suite.addTest(unittest.makeSuite(MacroExtendTestCase))
>      suite.addTest(unittest.makeSuite(OutputPresentationTestCase))
>      suite.addTest(unittest.makeSuite(ScriptTestCase))
>      suite.addTest(unittest.makeSuite(I18NCornerTestCase))
> 
> _______________________________________________
> Zope3-Checkins mailing list
> Zope3-Checkins at zope.org
> http://mail.zope.org/mailman/listinfo/zope3-checkins
> 

-- 
Simplistix - Content Management, Zope & Python Consulting
            - http://www.simplistix.co.uk


More information about the ZPT mailing list