Commits

Victor Kotseruba committed b8fdd58

RubyStringFormatter now supports expressions

Comments (0)

Files changed (1)

         super(RubyStringFormatter, self).__init__()
         self.ast = AstWrap(self)
     
-    def _var_match(self, variables, match):
-        variables.add(match.group(1))
-        return '%%(%s)s' % match.group(1)        
+    
+    def _expr(self, variables, match):
+        expr = ast.parse(_var_r(match.group(1))).body[0].value
+        variables.append(expr)
+        return '%s'
+    
     
     def visit_Str(self, node):
-        variables = set([])
-        s = re.sub(r'#{!?(\w+)}',
-                   functools.partial(self._var_match, variables),
+        variables = []
+        s = re.sub(r'#{([^}]+)}', functools.partial(self._expr, variables),
                    node.s)
         
         if not variables:
             return node
-        
-        dct = self.ast.Dict(keys=[self.ast.Str(s=k) for k in variables],
-                            values=[self.ast.Name(id=n, ctx=Load())
-                                    for n in variables],)
+
+        varl = self.ast.Tuple(elts=variables, ctx=Load())
         
         return ast.copy_location(self.ast.BinOp(left=self.ast.Str(s=s),
                                                 op=self.ast.Mod(),
-                                                right=dct), node)
+                                                right=varl), node)
 
 
 class Parser(object):
     
     
     def handle_for(self, data):
-        var, _, start, _, end = data.split()
+        var, _, start, through, end = data.split()
         var, start, end = var.lstrip('!'), int(start), int(end)
         if end < start:
             start, end = end, start
-        end += 1
+        if through == 'through':
+            end += 1
+        elif through != 'to':
+            raise RuntimeError('syntax error: @for %s' % data)
         loop = self.ast.For(target=self.ast.Name(id=var, ctx=self.ast.Store()),
                             iter=self.ast.Call(func=self.ast.Name(id='xrange', ctx=self.ast.Load()),
                                                args=[self.ast.Num(n=start), self.ast.Num(n=end)],