Changeset 29

Show
Ignore:
Timestamp:
23/08/04 12:57:25 (4 years ago)
Author:
steve
Message:

range literals, and prevent resolution of properties in LocalNamespace? instances

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/airspeed.py

    r28 r29  
    11#!/usr/bin/env python 
    22 
    3 import re, operator 
     3import re, operator, os 
    44 
    55try: import cStringIO as StringIO 
    66except ImportError: import StringIO 
    77 
    8 __all__ = ['Template', 'TemplateError', 'TemplateSyntaxError', 'FileLoader'] 
     8__all__ = ['Template', 'TemplateError', 'TemplateSyntaxError', 'CachingFileLoader'] 
    99 
    1010 
     
    2323        return output.getvalue() 
    2424 
     25    def ensure_compiled(self): 
     26        if not self.root_element: 
     27            self.root_element = TemplateBody(self.content) 
     28 
    2529    def merge_to(self, namespace, fileobj, loader=None): 
    2630        if loader is None: loader = NullLoader() 
    27         if not self.root_element: 
    28             self.root_element = TemplateBody(self.content) 
     31        self.ensure_compiled() 
    2932        self.root_element.evaluate(namespace, fileobj, loader) 
    3033 
     
    6467 
    6568 
    66 class FileLoader: 
     69class CachingFileLoader: 
    6770    def __init__(self, basedir): 
    6871        self.basedir = basedir 
     72        self.known_templates = {} # name -> (template, file_mod_time) 
     73 
     74    def filename_of(self, name): 
     75        return os.path.join(self.basedir, name) 
    6976 
    7077    def load_text(self, name): 
    71         import os 
    7278        f = open(os.path.join(self.basedir, name)) 
    7379        try: return f.read() 
     
    7581 
    7682    def load_template(self, name): 
    77         return Template(self.load_text(name)) 
     83        mtime = os.path.getmtime(self.filename_of(name)) 
     84        if name in self.known_templates: 
     85            template, prev_mtime = self.known_templates[name] 
     86            if mtime <= prev_mtime: 
     87                return template 
     88        template = Template(self.load_text(name)) 
     89        template.ensure_compiled() 
     90        self.known_templates[name] = (template, mtime) 
     91        return template 
    7892 
    7993 
     
    216230 
    217231 
     232class RangeLiteral(_Element): 
     233    RANGE = re.compile(r'\[[ \t]*(\-?\d+)[ \t]*\.\.[ \t]*(\-?\d+)[ \t]*\](.*)$') 
     234 
     235    def parse(self): 
     236        self.value1, self.value2 = map(int, self.identity_match(self.RANGE)) 
     237 
     238    def calculate(self, namespace): 
     239        if self.value2 < self.value1: 
     240            return xrange(self.value1, self.value2 - 1, -1) 
     241        return xrange(self.value1, self.value2 + 1) 
     242 
     243 
    218244class Value(_Element): 
    219245    def parse(self): 
    220         self.expression = self.next_element((SimpleReference, IntegerLiteral, StringLiteral, SingleQuotedStringLiteral)) 
     246        self.expression = self.next_element((SimpleReference, IntegerLiteral, StringLiteral, SingleQuotedStringLiteral, RangeLiteral)) 
    221247 
    222248    def calculate(self, namespace): 
     
    234260 
    235261    def calculate(self, current_object, top_namespace): 
    236         try: result = getattr(current_object, self.name) 
    237         except AttributeError: 
     262        look_in_dict = True 
     263        if not isinstance(current_object, LocalNamespace): 
     264            try: 
     265                result = getattr(current_object, self.name) 
     266                look_in_dict = False 
     267            except AttributeError: 
     268                pass 
     269        if look_in_dict: 
    238270            try: result = current_object[self.name] 
    239271            except KeyError: result = None 
     
    423455    def parse(self): 
    424456        self.var_name, = self.identity_match(self.START) 
    425         self.value = self.next_element(Value
     457        self.value = self.require_next_element(Value, "value"
    426458        self.require_match(self.END, ')') 
    427459 
     
    556588        iterable = self.value.calculate(namespace) 
    557589        counter = 1 
    558         for item in iterable: 
    559             namespace = LocalNamespace(namespace) 
    560             namespace['velocityCount'] = counter 
    561             namespace[self.loop_var_name] = item 
    562             self.block.evaluate(namespace, stream, loader) 
    563             counter += 1 
     590        try: 
     591            for item in iterable: 
     592                namespace = LocalNamespace(namespace) 
     593                namespace['velocityCount'] = counter 
     594                namespace[self.loop_var_name] = item 
     595                self.block.evaluate(namespace, stream, loader) 
     596                counter += 1 
     597        except TypeError: 
     598            print iterable 
     599            raise 
    564600 
    565601 
  • trunk/airspeed_test.py

    • Property svn:executable set to *
    r28 r29  
    371371        self.assertEquals('Message is: hola!', template.merge({'foo': 'foo.tmpl', 'message': 'hola'}, loader=WorkingLoader())) 
    372372 
     373    def test_assign_range_literal(self): 
     374        template = airspeed.Template('#set($values = [1..5])#foreach($value in $values)$value,#end') 
     375        self.assertEquals('1,2,3,4,5,', template.merge({})) 
     376        template = airspeed.Template('#set($values = [2..-2])#foreach($value in $values)$value,#end') 
     377        self.assertEquals('2,1,0,-1,-2,', template.merge({})) 
     378 
     379    def test_local_namespace_methods_not_available(self): 
     380        template = airspeed.Template('#macro(tryme)$values#end#tryme()') 
     381        self.assertEquals('$values', template.merge({})) 
     382 
    373383# 
    374384# TODO: 
     
    379389#  list literals 
    380390#  Bind #macro calls at compile time? 
     391#  #stop ? 
    381392#  Interpolated strings 
    382393#  Directives inside string literals 
     
    385396#  Q. What is scope of #set ($customer.Name = 'john')  ??? 
    386397#  Scope of #set across if/elseif/else? 
    387 #  Scope of namespace for #include etc 
     398#  Scope of namespace for #parse etc 
    388399# 
    389400