Changeset 18
- Timestamp:
- 17/08/04 21:39:57 (4 years ago)
- Files:
-
- trunk/airspeed.py (modified) (6 diffs)
- trunk/airspeed_test.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/airspeed.py
r17 r18 73 73 74 74 class 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) 78 82 79 83 def evaluate(self, namespace, stream): 80 84 stream.write(self.text) 85 81 86 82 87 … … 226 231 def evaluate(self, namespace, stream): pass 227 232 228 class If (_Element):233 class IfDirective(_Element): 229 234 START = re.compile(r'^#if\b\s*(.*)$', re.S + re.I) 235 START_ELSEIF = re.compile(r'^#elseif\b\s*(.*)$', re.S + re.I) 230 236 START_ELSE = re.compile(r'^#else(.*)$', re.S + re.I) 231 237 else_block = Null() … … 235 241 self.condition, text = self.next_element(Condition, text) 236 242 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)) 237 251 m = self.START_ELSE.match(text) 238 252 if m: 239 253 self.else_block, text = self.require_next_element(Block, m.group(1), 'block') 240 end, self.remaining_text = self.require_next_element(End, text, '#e nd')254 end, self.remaining_text = self.require_next_element(End, text, '#else, #elseif or #end') 241 255 242 256 def evaluate(self, namespace, stream): … … 244 258 self.block.evaluate(namespace, stream) 245 259 else: 260 for elseif, block in self.elseif_conditions: 261 if elseif.calculate(namespace): 262 block.evaluate(namespace, stream) 263 return 246 264 self.else_block.evaluate(namespace, stream) 247 265 248 266 249 class Set (_Element):267 class SetDirective(_Element): 250 268 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) 252 270 def __init__(self, text): 253 271 ## Could be cleaner b/c syntax error if no '(' … … 260 278 261 279 262 class Foreach (_Element):280 class ForeachDirective(_Element): 263 281 START = re.compile(r'^#foreach\s*\(\s*\$([a-z_][a-z0-9_]*)\s*in\s*(.*)$', re.S + re.I) 264 282 CLOSING_PATTERN = re.compile(r'^\s*\)(.*)$', re.S) … … 298 316 while text: 299 317 child = None 300 for child_type in (Text, Placeholder, Comment, If , Set, Foreach):318 for child_type in (Text, Placeholder, Comment, IfDirective, SetDirective, ForeachDirective): 301 319 try: 302 320 child, text = self.next_element(child_type, text) trunk/airspeed_test.py
r17 r18 186 186 self.assertEquals("48", template.merge(locals())) 187 187 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('''\ 196 foo 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())) 188 236 # 189 237 # TODO: 190 238 # 191 # Escaped characters in string literals192 239 # Directives inside string literals 240 # Math expressions 241 # Gobbling up whitespace (tricky!) 193 242 # #elseif 194 # Parameterised calls195 243 # #parse, #include 196 244 # #macro 197 # map literals 198 # Escaped $, #245 # map literals, range literals, list literals 246 # Comparative operators >=, ==, !=, <=, ! 199 247 # Sub-object assignment: #set( $customer.Behavior = $primate ) 200 248 # Q. What is scope of #set ($customer.Name = 'john') ??? 201 # 249 # Scope of #set across if/elseif/else? 202 250 203 251
