Changeset 18

Show
Ignore:
Timestamp:
17/08/04 21:39:57 (4 years ago)
Author:
steve
Message:

elseif

Files:

Legend:

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

    r17 r18  
    7373 
    7474class Text(_Element): 
    75     MY_PATTERN = re.compile(r'^((?:[^\\\$#]|\\[\$#])+|\$[^!\{a-z0-9_]|\$$)(.*)$', re.S + re.I) 
    76     def __init__(self, text): 
    77         self.text, self.remaining_text = self.match_or_reject(self.MY_PATTERN, text) 
     75    MY_PATTERN = re.compile(r'^((?:[^\\\$#]|\\[\$#])+|\$[^!\{a-z0-9_]|\$$|\\\\)(.*)$', re.S + re.I) 
     76    ESCAPED_CHAR = re.compile(r'\\([\\\$#])') 
     77    def __init__(self, text): 
     78        text, self.remaining_text = self.match_or_reject(self.MY_PATTERN, text) 
     79        def unescape(match): 
     80            return match.group(1) 
     81        self.text = self.ESCAPED_CHAR.sub(unescape, text) 
    7882 
    7983    def evaluate(self, namespace, stream): 
    8084        stream.write(self.text) 
     85 
    8186 
    8287 
     
    226231    def evaluate(self, namespace, stream): pass 
    227232 
    228 class If(_Element): 
     233class IfDirective(_Element): 
    229234    START = re.compile(r'^#if\b\s*(.*)$', re.S + re.I) 
     235    START_ELSEIF = re.compile(r'^#elseif\b\s*(.*)$', re.S + re.I) 
    230236    START_ELSE = re.compile(r'^#else(.*)$', re.S + re.I) 
    231237    else_block = Null() 
     
    235241        self.condition, text = self.next_element(Condition, text) 
    236242        self.block, text = self.next_element(Block, text) 
     243        self.elseif_conditions = [] 
     244        while True: 
     245            m = self.START_ELSEIF.match(text) 
     246            if not m: break 
     247            text = m.group(1) 
     248            elseif_condition, text = self.require_next_element(Condition, text, 'condition') 
     249            elseif_block, text = self.require_next_element(Block, text, 'block') 
     250            self.elseif_conditions.append((elseif_condition, elseif_block)) 
    237251        m = self.START_ELSE.match(text) 
    238252        if m: 
    239253            self.else_block, text = self.require_next_element(Block, m.group(1), 'block') 
    240         end, self.remaining_text = self.require_next_element(End, text, '#end') 
     254        end, self.remaining_text = self.require_next_element(End, text, '#else, #elseif or #end') 
    241255 
    242256    def evaluate(self, namespace, stream): 
     
    244258            self.block.evaluate(namespace, stream) 
    245259        else: 
     260            for elseif, block in self.elseif_conditions: 
     261                if elseif.calculate(namespace): 
     262                    block.evaluate(namespace, stream) 
     263                    return 
    246264            self.else_block.evaluate(namespace, stream) 
    247265 
    248266 
    249 class Set(_Element): 
     267class SetDirective(_Element): 
    250268    START = re.compile(r'^#set\s*\(\s*\$([a-z_][a-z0-9_]*)\s*=\s*(.*)$', re.S + re.I) 
    251     CLOSING_PATTERN = re.compile(r'^\s*\)(.*)$', re.S
     269    CLOSING_PATTERN = re.compile(r'^\s*\)(?:[ \t]*\r?\n)?(.*)$', re.S + re.M
    252270    def __init__(self, text): 
    253271        ## Could be cleaner b/c syntax error if no '(' 
     
    260278 
    261279 
    262 class Foreach(_Element): 
     280class ForeachDirective(_Element): 
    263281    START = re.compile(r'^#foreach\s*\(\s*\$([a-z_][a-z0-9_]*)\s*in\s*(.*)$', re.S + re.I) 
    264282    CLOSING_PATTERN = re.compile(r'^\s*\)(.*)$', re.S) 
     
    298316        while text: 
    299317            child = None 
    300             for child_type in (Text, Placeholder, Comment, If, Set, Foreach): 
     318            for child_type in (Text, Placeholder, Comment, IfDirective, SetDirective, ForeachDirective): 
    301319                try: 
    302320                    child, text = self.next_element(child_type, text) 
  • trunk/airspeed_test.py

    r17 r18  
    186186        self.assertEquals("48", template.merge(locals())) 
    187187 
     188    def test_velocity_style_escaping(self): # example from Velocity docs 
     189        template = airspeed.Template('''\ 
     190#set( $email = "foo" ) 
     191$email 
     192\\$email 
     193\\\\$email 
     194\\\\\\$email''') 
     195        self.assertEquals('''\ 
     196foo 
     197$email 
     198\\foo 
     199\\$email''', template.merge({})) 
     200 
     201#    def test_velocity_style_escaping_when_var_unset(self): # example from Velocity docs 
     202#        template = airspeed.Template('''\ 
     203#$email 
     204#\$email 
     205#\\$email 
     206#\\\$email''') 
     207#        self.assertEquals('''\ 
     208#$email 
     209#\$email 
     210#\\$email 
     211#\\\$email''', template.merge({})) 
     212 
     213    def test_true_elseif_evaluated_when_if_is_false(self): 
     214        template = airspeed.Template('#if ($value1) one #elseif ($value2) two #end') 
     215        value1, value2 = False, True 
     216        self.assertEquals(' two ', template.merge(locals())) 
     217 
     218    def test_false_elseif_skipped_when_if_is_true(self): 
     219        template = airspeed.Template('#if ($value1) one #elseif ($value2) two #end') 
     220        value1, value2 = True, False 
     221        self.assertEquals(' one ', template.merge(locals())) 
     222 
     223    def test_first_true_elseif_evaluated_when_if_is_false(self): 
     224        template = airspeed.Template('#if ($value1) one #elseif ($value2) two #elseif($value3) three #end') 
     225        value1, value2, value3 = False, True, True 
     226        self.assertEquals(' two ', template.merge(locals())) 
     227 
     228    def test_illegal_to_have_elseif_after_else(self): 
     229        template = airspeed.Template('#if ($value1) one #else two #elseif($value3) three #end') 
     230        self.assertRaises(airspeed.TemplateSyntaxError, template.merge, {}) 
     231 
     232    def test_else_evaluated_when_if_and_elseif_are_false(self): 
     233        template = airspeed.Template('#if ($value1) one #elseif ($value2) two #else three #end') 
     234        value1, value2 = False, False 
     235        self.assertEquals(' three ', template.merge(locals())) 
    188236# 
    189237# TODO: 
    190238# 
    191 #  Escaped characters in string literals 
    192239#  Directives inside string literals 
     240#  Math expressions 
     241#  Gobbling up whitespace (tricky!) 
    193242#  #elseif 
    194 #  Parameterised calls 
    195243#  #parse, #include 
    196244#  #macro 
    197 #  map literals 
    198 Escaped $, # 
     245#  map literals, range literals, list literals 
     246Comparative operators >=, ==, !=, <=, ! 
    199247#  Sub-object assignment:  #set( $customer.Behavior = $primate ) 
    200248#  Q. What is scope of #set ($customer.Name = 'john')  ??? 
    201 # 
     249#  Scope of #set across if/elseif/else? 
    202250 
    203251