Code

That's gadfly done, mostly. Things left:
[roundup.git] / roundup / template_parser.py
1 import htmllib, formatter
3 class Require:
4     ''' Encapsulates a parsed <require attributes>...[<else>...]</require>
5     '''
6     def __init__(self, attributes):
7         self.attributes = attributes
8         self.current = self.ok = []
9         self.fail = []
10     def __len__(self):
11         return len(self.current)
12     def __getitem__(self, n):
13         return self.current[n]
14     def __setitem__(self, n, data):
15         self.current[n] = data
16     def append(self, data):
17         self.current.append(data)
18     def elseMode(self):
19         self.current = self.fail
20     def __repr__(self):
21         return '<Require %r ok:%r fail:%r>'%(self.attributes, self.ok,
22             self.fail)
24 class Display:
25     ''' Encapsulates a parsed <display attributes>
26     '''
27     def __init__(self, attributes):
28         self.attributes = attributes
29     def __repr__(self):
30         return '<Display %r>'%self.attributes
32 class Property:
33     ''' Encapsulates a parsed <property attributes>
34     '''
35     def __init__(self, attributes):
36         self.attributes = attributes
37         self.current = self.ok = []
38     def __len__(self):
39         return len(self.current)
40     def __getitem__(self, n):
41         return self.current[n]
42     def __setitem__(self, n, data):
43         self.current[n] = data
44     def append(self, data):
45         self.current.append(data)
46     def __repr__(self):
47         return '<Property %r %r>'%(self.attributes, self.structure)
49 class RoundupTemplate(htmllib.HTMLParser):
50     ''' Parse Roundup's HTML template structure into a list of components:
52         'string': this is just plain data to be displayed
53         Display : instances indicate that display functions are to be called
54         Require : if/else style check using the conditions in the attributes,
55                   displaying the "ok" list of components or "fail" list
57     '''
58     def __init__(self):
59         htmllib.HTMLParser.__init__(self, formatter.NullFormatter())
60         self.current = self.structure = []
61         self.stack = []
63     def handle_data(self, data):
64         self.append_data(data)
66     def append_data(self, data):
67         if self.current and isinstance(self.current[-1], type('')):
68             self.current[-1] = self.current[-1] + data
69         else:
70             self.current.append(data)
72     def unknown_starttag(self, tag, attributes):
73         self.append_data('<%s' % tag)
74         closeit = 1
75         for name, value in attributes:
76             pos = value.find('<')
77             if pos > -1:
78                 self.append_data(' %s="%s' % (name, value[:pos]))
79                 closeit = 0
80             else:
81                 self.append_data(' %s="%s"' % (name, value))
82         if closeit:
83             self.append_data('>')
85     def handle_starttag(self, tag, method, attributes):
86         if tag in ('require', 'else', 'display', 'property'):
87             method(attributes)
88         else:
89             self.unknown_starttag(tag, attributes)
91     def unknown_endtag(self, tag):
92         if tag in ('require','property'):
93             self.current = self.stack.pop()
94         else:
95             self.append_data('</%s>'%tag)
97     def handle_endtag(self, tag, method):
98         self.unknown_endtag(tag)
100     def close(self):
101         htmllib.HTMLParser.close(self)
103     def do_display(self, attributes):
104         self.current.append(Display(attributes))
106     def do_property(self, attributes):
107         p = Property(attributes)
108         self.current.append(p)
109         self.stack.append(self.current)
110         self.current = p
112     def do_require(self, attributes):
113         r = Require(attributes)
114         self.current.append(r)
115         self.stack.append(self.current)
116         self.current = r
118     def do_else(self, attributes):
119         self.current.elseMode()
121     def __repr__(self):
122         return '<RoundupTemplate %r>'%self.structure
124 def display(structure, indent=''):
125     ''' Pretty-print the parsed structure for debugging
126     '''
127     l = []
128     for entry in structure:
129         if isinstance(entry, type('')):
130             l.append("%s%s"%(indent, entry))
131         elif isinstance(entry, Require):
132             l.append('%sTEST: %r\n'%(indent, entry.attributes))
133             l.append('%sOK...'%indent)
134             l.append(display(entry.ok, indent+' '))
135             if entry.fail:
136                 l.append('%sFAIL...'%indent)
137                 l.append(display(entry.fail, indent+' '))
138         elif isinstance(entry, Display):
139             l.append('%sDISPLAY: %r'%(indent, entry.attributes))
140         elif isinstance(entry, Property):
141             l.append('%sPROPERTY: %r'%(indent, entry.attributes))
142             l.append(display(entry.ok, indent+' '))
143     return ''.join(l)
145 if __name__ == '__main__':
146     import sys
147     parser = RoundupTemplate()
148     parser.feed(open(sys.argv[1], 'r').read())
149     print display(parser.structure)