Commits

Andriy Kornatskyy committed 12c2431

Added support for variable filters.

  • Participants
  • Parent commits 27f5d5a

Comments (0)

Files changed (2)

src/wheezy/template/ext/core.py

 # region: config
 
 end_tokens = ['end']
-continue_tokens = ['else', 'elif']
-compound_tokens = ['for', 'if', 'def', 'extends'] + continue_tokens
+continue_tokens = ['else:', 'elif ']
+compound_tokens = ['for ', 'if ', 'def ', 'extends'] + continue_tokens
 reserved_tokens = ['require', '#', 'include']
 all_tokens = end_tokens + compound_tokens + reserved_tokens
 out_tokens = ['markup', 'var', 'include']
 
 
 RE_VAR = re.compile('(\.\w+)+')
+RE_VAR_FILTER = re.compile('(?<!!)!\w+(!\w+)*')
 
 
 def var_token(m):
         if not m:
             break
         pos = m.end()
-    return end, 'var', str(source[start:end])
+    value = str(source[start:end])
+    m = RE_VAR_FILTER.match(source, end)
+    if m:
+        end = m.end()
+        value += '!' + m.group()
+    return end, 'var', value
 
 
 def markup_token(m):
     return value.rstrip()[8:-1]
 
 
+def parse_var(value):
+    if '!!' not in value:
+        return value, None
+    var, var_filter = value.rsplit('!!', 1)
+    return var, var_filter.split('!')
+
+
 def parse_markup(value):
-    return repr(value.replace('\\\n', ''))
+    value = value.replace('\\\n', '')
+    if value:
+        return repr(value)
+    else:
+        return None
 
 
 # region: block_builders
         return False
     extends, nodes = value
     for lineno, token, value in nodes:
-        if token == 'def':
-            builder.build_token(lineno, 'def', value)
+        if token in ('def ', 'require'):
+            builder.build_token(lineno, token, value)
     lineno = builder.lineno
     builder.add(lineno + 1, 'return _r(' + extends +
-            ')(ctx, local_defs, super_defs)')
+            ', ctx, local_defs, super_defs)')
     return True
 
 
     return True
 
 
+def build_def_empty(builder, lineno, token, value):
+    assert token == 'def '
+    stmt, nodes = value
+    if nodes:
+        return False
+    def_name = stmt[4:stmt.index('(', 5)]
+    builder.add(lineno, stmt)
+    builder.start_block()
+    builder.add(lineno, "return ''")
+    builder.end_block()
+    builder.add(lineno + 1, def_name.join([
+        "super_defs['", "'] = ", "; ",
+        " = local_defs.setdefault('", "', ", ")"
+    ]))
+    return True
+
+
 def build_def(builder, lineno, token, value):
-    assert token == 'def'
+    assert token == 'def '
     stmt, nodes = value
     def_name = stmt[4:stmt.index('(', 5)]
     builder.add(lineno, stmt)
     lineno = builder.lineno
     builder.add(lineno, "return ''.join(_b)")
     builder.end_block()
-    builder.add(lineno + 1, "super_defs['%s'] = %s; "\
-            "%s = local_defs.setdefault('%s', %s)" % tuple(
-                    [def_name] * 5))
+    builder.add(lineno + 1, def_name.join([
+        "super_defs['", "'] = ", "; ",
+        " = local_defs.setdefault('", "', ", ")"
+    ]))
     return True
 
 
     assert token == 'out'
     for lineno, token, value in nodes:
         if token == 'include':
-            builder.add(lineno, 'w(_r(' + value +
-                ')(ctx, local_defs, super_defs))')
-        else:
+            builder.add(lineno, 'w(' + '_r(' + value +
+                ', ctx, local_defs, super_defs)' + ')')
+        elif token == 'var':
+            var, var_filters = value
+            if var_filters:
+                for f in reversed(var_filters):
+                    var = f + '(' + var + ')'
+            builder.add(lineno, 'w(' + var + ')')
+        elif value:
             builder.add(lineno, 'w(' + value + ')')
     return True
 
             'require': parse_require,
             'extends': parse_extends,
             'include': parse_include,
-            'markup': parse_markup
+            'var': parse_var,
+            'markup': parse_markup,
     }
 
     parser_configs = [configure_parser]
             ('render', build_render),
             ('require', build_require),
             ('out', build_out),
-            ('def', build_def),
-            ('if', build_compound),
-            ('elif', build_compound),
-            ('else', build_compound),
-            ('for', build_compound),
+            ('def ', build_def_empty),
+            ('def ', build_def),
+            ('if ', build_compound),
+            ('elif ', build_compound),
+            ('else:', build_compound),
+            ('for ', build_compound),
             ('#', build_comment),
     ]

src/wheezy/template/ext/tests/test_core.py

         tokens = self.tokenize('@user.pref[i].fmt() ')
         assert (1, 'var', 'user.pref[i].fmt()') == tokens[0]
 
+    def test_var_token_filter(self):
+        """ Test variable token filter.
+        """
+        tokens = self.tokenize('@user.age!s')
+        assert (1, 'var', 'user.age!!s') == tokens[0]
+        tokens = self.tokenize('@user.age!s!h')
+        assert (1, 'var', 'user.age!!s!h') == tokens[0]
+        # escape or ignore !
+        tokens = self.tokenize('@user.age!s!')
+        assert (1, 'var', 'user.age!!s') == tokens[0]
+        tokens = self.tokenize('@user.age!!s')
+        assert (1, 'var', 'user.age') == tokens[0]
+        tokens = self.tokenize('@user! ')
+        assert (1, 'var', 'user') == tokens[0]
+
     def test_markup_token(self):
         """ Test markup token.
         """
 """)
         assert [(1, 'out', [
                     (1, 'markup', "'\\n Welcome, '"),
-                    (2, 'var', 'name'),
+                    (2, 'var', ('name', None)),
                     (2, 'markup', "'!\\n'")
                 ])] == nodes
 
+    def test_var(self):
+        """ Test parse_markup.
+        """
+        nodes = self.parse("""@name!h!""")
+        assert [(1, 'out', [
+                    (1, 'var', ('name', ['h'])),
+                    (1, 'markup', "'!'")
+                ])] == nodes
+        nodes = self.parse("""@name!s!h!""")
+        assert [(1, 'out', [
+                    (1, 'var', ('name', ['s', 'h'])),
+                    (1, 'markup', "'!'")
+                ])] == nodes
+
 
 class BuilderTestCase(unittest.TestCase):
     """ Test the ``CoreExtension`` generators.
         """
         assert """\
 def render(ctx, local_defs, super_defs):
-    return _r("base.html")(ctx, local_defs, super_defs)\
+    return _r("base.html", ctx, local_defs, super_defs)\
 """ == self.build_render("""\
 @extends("base.html")
 """)