[Checkins] SVN: z3c.pt/trunk/z3c/pt/ Implemented support for path expressions.

Malthe Borch mborch at gmail.com
Sun Mar 16 14:44:49 EDT 2008


Log message for revision 84714:
  Implemented support for path expressions.

Changed:
  U   z3c.pt/trunk/z3c/pt/expressions.py
  U   z3c.pt/trunk/z3c/pt/generation.py
  U   z3c.pt/trunk/z3c/pt/interfaces.py
  U   z3c.pt/trunk/z3c/pt/translation.txt
  U   z3c.pt/trunk/z3c/pt/utils.py

-=-
Modified: z3c.pt/trunk/z3c/pt/expressions.py
===================================================================
--- z3c.pt/trunk/z3c/pt/expressions.py	2008-03-16 18:43:59 UTC (rev 84713)
+++ z3c.pt/trunk/z3c/pt/expressions.py	2008-03-16 18:44:45 UTC (rev 84714)
@@ -1,5 +1,8 @@
 import zope.interface
+import zope.traversing.adapters
+
 import parser
+import re
 
 from interfaces import IExpressionTranslation
 
@@ -213,36 +216,27 @@
 
         return defs[0]
 
-class PythonTranslation(ExpressionTranslation):
     def value(self, string):
         """
-        Specification:
+        We need to implement a ``value``-method. Let's define that an
+        expression is valid if it contains an odd number of
+        characters.
+        
+        >>> class MockExpressionTranslation(ExpressionTranslation):
+        ...     def validate(self, string):
+        ...         return True
+        ...
+        ...     def translate(self, string):
+        ...         return '<translated %s>' % string
+        
+        >>> value = MockExpressionTranslation().value
 
-        value :: = python_expression [ |* value ]
-        python_expresion ::= a python expression string
+        >>> value('a')
+        ('<translated a>',)
 
-        *) Using | as logical or is not supported.
-
-            >>> value = PythonTranslation().value
-            
-            >>> value("4 + 5")
-            ['4 + 5']
-
-        Complex expressions:
-
-            >>> value("a.non_defined_method() | 1")
-            ['a.non_defined_method() ', '1']
-
-        Expression with non-semantic horizontal bar.
-
-            >>> value("'|'")
-            ["'|'"]
-
-        Expression with non-semantic horizontal bar and semantic bar.
-
-            >>> value("a.non_defined_method() | '|'")
-            ['a.non_defined_method() ', "'|'"]
-
+        >>> value('a|b')
+        ('<translated a>', '<translated b>')
+    
         """
 
         string = string.replace('\n', '').strip()
@@ -261,16 +255,64 @@
             expr = string[i:j].lstrip()
 
             try:
-                # we use the ``parser`` module to determine if
-                # an expression is a valid python expression
-                parser.expr(expr.encode('utf-8'))
-            except SyntaxError, e:
+                self.validate(expr)
+            except Exception, e:
                 if j < len(string):
                     continue
 
                 raise e
 
-            expressions.append(expr)
+            expressions.append(self.translate(expr))
             i = j + 1
 
-        return expressions
+        return tuple(expressions)
+
+class PythonTranslation(ExpressionTranslation):
+    def validate(self, string):
+        """We use the ``parser`` module to determine if
+        an expression is a valid python expression."""
+        
+        parser.expr(string.encode('utf-8'))
+
+    def translate(self, string):
+        return string
+
+class PathTranslation(ExpressionTranslation):
+    path_regex = re.compile(r'^([A-Za-z_]+)(/[A-Za-z_ at -]+)+$')
+
+    @classmethod
+    def traverse(cls, base, request, *path_items):
+        """See ``zope.app.pagetemplate.engine``."""
+
+        for i in range(len(path_items)):
+            name = path_items[i]
+            
+            # special-case dicts for performance reasons        
+            if getattr(base, '__class__', None) == dict:
+                base = base[name]
+            else:
+                base = zope.traversing.adapters.traversePathElement(
+                    base, name, path_items[i+1:], request=request)
+                
+        return base
+
+    def validate(self, string):
+        if not self.path_regex.match(string):
+            raise ValueError("Not a valid path-expression.")
+
+    def translate(self, string):
+        """
+            >>> translate = PathTranslation().translate
+            >>> translate("a/b")
+            "_path(a, request, 'b')"
+
+            >>> translate("context/@@view")
+            "_path(context, request, '@@view')"
+        """
+
+        parts = string.split('/')
+
+        base = parts[0]
+        components = [repr(part) for part in parts[1:]]
+                
+        return '_path(%s, request, %s)' % (base, ', '.join(components))

Modified: z3c.pt/trunk/z3c/pt/generation.py
===================================================================
--- z3c.pt/trunk/z3c/pt/generation.py	2008-03-16 18:43:59 UTC (rev 84713)
+++ z3c.pt/trunk/z3c/pt/generation.py	2008-03-16 18:44:45 UTC (rev 84714)
@@ -9,6 +9,7 @@
 \t(_attributes, repeat) = utils.initialize_tal()
 \t(_domain, _translate) = utils.initialize_i18n()
 \t(_escape, _marker) = utils.initialize_helpers()
+\t_path = utils.initialize_traversal()
 
 \t_target_language = target_language
 %s

Modified: z3c.pt/trunk/z3c/pt/interfaces.py
===================================================================
--- z3c.pt/trunk/z3c/pt/interfaces.py	2008-03-16 18:43:59 UTC (rev 84713)
+++ z3c.pt/trunk/z3c/pt/interfaces.py	2008-03-16 18:44:45 UTC (rev 84714)
@@ -8,7 +8,22 @@
         usually be the identity function."""
     
     def value(string):
-        """Translate ``string`` to a Python value-expression."""
+        """Translate ``string`` to a value-expression tuple.
+
+        Specification:
+
+           value :: = expression [ |* value ]
+           expresion ::= an expression string
+
+           *) Using | as _logical or_ is not supported.
+
+        """
+
+    def validate(string):
+        """Raises exception if ``string`` is not a valid exception."""
+
+    def translate(string):
+        """Translates ``string``."""
         
     def search(string):
         """Extracts the longest valid expression from the beginning of

Modified: z3c.pt/trunk/z3c/pt/translation.txt
===================================================================
--- z3c.pt/trunk/z3c/pt/translation.txt	2008-03-16 18:43:59 UTC (rev 84713)
+++ z3c.pt/trunk/z3c/pt/translation.txt	2008-03-16 18:44:45 UTC (rev 84714)
@@ -1,9 +1,9 @@
 Translation
------------
+===========
 
 This document contains functional template tests.
 
-We use a generic render-method for convenience.
+A generic render-method is used for convenience.
 
   >>> def render(body, translator, **kwargs):
   ...    source, _globals = translator(body)
@@ -11,12 +11,19 @@
   ...    exec source in _globals, _locals
   ...    return _locals['render'](**kwargs)
 
-We'll first register the Python expression translator.
+Expressions
+-----------
+  
+First we'll register the expression translation utilities:
 
+  >>> from zope.component import provideUtility
+
   >>> from z3c.pt.expressions import PythonTranslation
-  >>> from zope.component import provideUtility
   >>> provideUtility(PythonTranslation(), name="python")
 
+  >>> from z3c.pt.expressions import PathTranslation
+  >>> provideUtility(PathTranslation(), name="path")
+
 TAL templates
 -------------
 
@@ -28,7 +35,8 @@
 
   >>> body = """\
   ... <div xmlns="http://www.w3.org/1999/xhtml"
-  ...      xmlns:tal="http://xml.zope.org/namespaces/tal">
+  ...      xmlns:tal="http://xml.zope.org/namespaces/tal"
+  ...      tal:default-expression="python">
   ...   <span id="test"
   ...         class="dummy"
   ...         tal:define="a 'abc'"
@@ -65,7 +73,16 @@
   ...   <img alt="La Peña, oh ${'La Peña'}" />
   ...   ${unicode('La Pe\xc3\xb1a', 'utf-8')}
   ...   <img alt="${unicode('La Pe\xc3\xb1a', 'utf-8')}" />
-  ...   <img alt="Hello ${unicode('La Pe\xc3\xb1a', 'utf-8').encode('utf-8')}!" />  
+  ...   <img alt="Hello ${unicode('La Pe\xc3\xb1a', 'utf-8').encode('utf-8')}!" />
+  ...   <tal:path-expression-testing 
+  ...         define="request object();
+  ...                 mydict {'a': 1, 'c': {'a': 2}}">
+  ...       <div tal:default-expression="path">
+  ...          <span tal:replace="mydict/a" />
+  ...          <span tal:replace="mydict/b|mydict/a" />
+  ...          <span tal:replace="mydict/c/a" />
+  ...       </div>
+  ...   </tal:path-expression-testing>
   ... </div>
   ... """
 
@@ -117,7 +134,14 @@
     <img alt="La Peña, oh La Peña" />
     La Peña
     <img alt="La Peña" />
-    <img alt="Hello La Peña!" />  
+    <img alt="Hello La Peña!" />
+  <BLANKLINE>
+        <div>
+           1
+           1
+           2
+        </div>
+  <BLANKLINE>
   </div>
 
 Text templates

Modified: z3c.pt/trunk/z3c/pt/utils.py
===================================================================
--- z3c.pt/trunk/z3c/pt/utils.py	2008-03-16 18:43:59 UTC (rev 84713)
+++ z3c.pt/trunk/z3c/pt/utils.py	2008-03-16 18:44:45 UTC (rev 84714)
@@ -5,6 +5,7 @@
 import sys
 import cgi
 import logging
+import expressions
 
 # check if we're able to coerce unicode to str
 try:
@@ -13,7 +14,10 @@
 except UnicodeEncodeError:
     unicode_required_flag = True
     log = logging.getLogger('z3c.pt')
-    log.info("Default system encoding is set to '%s'; the template engine will perform better if an encoding that coerces gracefully to unicode is used ('utf-8' recommended)." % sys.getdefaultencoding())
+    log.info("Default system encoding is set to '%s'; "
+             "the template engine will perform better if "
+             "an encoding that coerces gracefully to "
+             "unicode is used ('utf-8' recommended)." % sys.getdefaultencoding())
 
 def handler(key=None):
     def decorate(f):
@@ -36,7 +40,10 @@
 
 def initialize_stream():
     return StringIO()
-    
+
+def initialize_traversal():
+    return expressions.PathTranslation.traverse
+
 def getLanguage(request):
     return ''
 



More information about the Checkins mailing list