Changeset 3
- Timestamp:
- 11/08/04 19:00:22 (4 years ago)
- Files:
-
- trunk/airspeed.py (modified) (5 diffs)
- trunk/airspeed_test.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/airspeed.py
r2 r3 3 3 import re 4 4 5 class SyntaxError(Exception): pass5 class TemplateSyntaxError(Exception): pass 6 6 7 7 class Tokeniser: 8 PLAIN, IF, PLACEHOLDER, END = range(4)8 PLAIN, IF, PLACEHOLDER, FOREACH, END = range(5) 9 9 10 10 UP_TO_NEXT_TEMPLATE_BIT = re.compile('^(.*?)((?:#|\$).*)', re.MULTILINE + re.DOTALL) 11 11 REST = '(.*)$' 12 NAME_OR_CALL = '[a-z0-9_]+(?:\(\))?' 12 NAME = '[a-z0-9_]+' 13 NAME_OR_CALL = NAME + '(?:\(\))?' 13 14 EXPRESSION = '(' + NAME_OR_CALL + '(?:\.' + NAME_OR_CALL + ')*)' 14 15 PLACEHOLDER_PATTERN = re.compile('^\$(!?)({?)' + EXPRESSION + '(}?)' + REST, re.IGNORECASE + re.DOTALL + re.MULTILINE) 15 16 BEGIN_IF_PATTERN = re.compile('^#if[ \t]*\([ \t]*\$' + EXPRESSION + '[ \t]*\)' + REST, re.IGNORECASE + re.DOTALL + re.MULTILINE) 17 BEGIN_FOREACH_PATTERN = re.compile('^#foreach[ \t]*\([ \t]*\$(' + NAME + ')[ \t]+in[ \t]+\$' + EXPRESSION + '[ \t]*\)' + REST, re.IGNORECASE + re.DOTALL + re.MULTILINE) 16 18 END_PATTERN = re.compile('^#end' + REST, re.IGNORECASE + re.DOTALL + re.MULTILINE) 17 19 … … 34 36 yield self.IF, expression 35 37 continue 38 m = self.BEGIN_FOREACH_PATTERN.match(interesting) 39 if m: 40 iter_var, expression, text = m.groups() 41 yield self.FOREACH, (expression, iter_var) 42 continue 36 43 m = self.END_PATTERN.match(interesting) 37 44 if m: … … 39 46 (text,) = m.groups() 40 47 continue 41 raise SyntaxError("invalid token: %s" % text[:40])48 raise TemplateSyntaxError("invalid token: %s" % text[:40]) 42 49 43 50 def get_placeholder(self, match): 44 51 silent, open_brace, var_name, close_brace, rest = match.groups() 45 52 if open_brace and not close_brace: 46 raise SyntaxError("unmatched braces")53 raise TemplateSyntaxError("unmatched braces") 47 54 if close_brace and not open_brace: 48 55 rest = close_brace + rest … … 61 68 output = [] 62 69 filter_output_at_nesting_level = [False] 63 tokens = Tokeniser().tokenise(str(content)) 64 for token_type, token_value in tokens: 70 tokens = list(Tokeniser().tokenise(str(content))) 71 tokens.reverse() 72 while tokens: 73 token_type, token_value = tokens.pop() 65 74 filter_at_this_level = filter_output_at_nesting_level[-1] 66 75 if token_type == Tokeniser.PLAIN: … … 82 91 filter_output_at_nesting_level.append(filter_my_content) 83 92 continue 93 if token_type == Tokeniser.FOREACH: 94 expression, iter_var = token_value 95 filter_output_at_nesting_level.append(filter_at_this_level) 96 token_type, token_value = tokens.pop() 97 values = self.find(expression) 98 if token_type == Tokeniser.PLAIN: 99 for item in values: 100 if not filter_at_this_level: output.append(token_value) 101 continue 84 102 if token_type == Tokeniser.END: 85 103 if len(filter_output_at_nesting_level) == 1: 86 raise SyntaxError("#end without beginning of block")104 raise TemplateSyntaxError("#end without beginning of block") 87 105 del filter_output_at_nesting_level[-1] 88 106 continue 89 raise SyntaxError("invalid token: %s" % text[:40])107 raise TemplateSyntaxError("invalid token: %s" % text[:40]) 90 108 91 109 if len(filter_output_at_nesting_level) > 1: 92 raise SyntaxError("Unclosed block")110 raise TemplateSyntaxError("Unclosed block") 93 111 return ''.join(output) 94 112 trunk/airspeed_test.py
r2 r3 44 44 template = airspeed.Template("Hello ${name.") 45 45 parser["name"] = "World" 46 self.assertRaises(airspeed. SyntaxError, parser.merge, template)46 self.assertRaises(airspeed.TemplateSyntaxError, parser.merge, template) 47 47 48 48 def test_unmatched_trailing_brace_preserved(self): … … 110 110 self.assertEquals("hello Steve.\nHappy Birthday\n.\nOff out later?", parser.merge(template)) 111 111 112 def test_foreach_with_plain_content_loops_correctly(self): 113 parser = airspeed.Parser() 114 template = airspeed.Template("#foreach ($name in $names)Hello you. #end") 115 parser["names"] = ["Chris", "Steve"] 116 self.assertEquals("Hello you. Hello you. ", parser.merge(template)) 112 117 113 118 if __name__ == '__main__':
