import repository from arizona
[raven.git] / lib / arizona-lib / arizonatemplate.py
1 # /usr/bin/env python
2
3 """
4 <Program Name>
5    arizonatemplate.py
6
7 <Started>   
8    September 8, 2007
9
10 <Author>
11    Justin Cappos
12
13 <Purpose>
14    This loads simple templates and does replacements with caller specified 
15    arguments.   Data is then returned as a string with the relevant tags 
16    replaced.   There are a few HTML specific items in some of the functions,
17    but there is nothing that is inherently HTML much of the functionality.
18
19    An example document might look like this:
20
21       <HTML>
22       <head>
23       <title>Foobar</title>
24       <LINK href="static/stork.css" rel="stylesheet" type="text/css">
25       </head>
26       <body>
27       <h1>
28       ###FOO###
29       </h1>
30       <A HREF="###BAR###">###BAZ###</A> leads to ###BAR###
31       </body>
32       </html>
33  
34    There are three different replacement tags in this example (the BAR tag is
35    listed twice).   This module replaces those tags with the appropriate text.   
36 """
37
38
39 import os
40 import arizonaconfig
41
42 #           [option, long option,      variable,  action,        data,  default, metavar, description]
43 """arizonaconfig
44    options=[["","--tagindicator","tagindicator", "store",    "string",    "###",    None, "This is the symbol that denotes the start and stop of a tag (default '###')"]]
45
46    includes=[]
47 """
48
49
50 # a directory to search for templates. If it is none, then the current
51 # directory is searched
52
53 glo_template_dir = None
54
55
56 # This class is basically just a string but the type is different so that
57 # one can discern the difference between a string and a tag.
58 #
59 # If this gets any more complex it needs to be tested and documented better.
60 class Tag:
61    tagname = ''
62    def __init__(self, tn=''):
63       self.tagname = tn
64
65
66
67
68 # We'll only load each template from disk the first time it's used.   From then
69 # on we'll just used the cached copy stored here
70 templatestore = {}
71
72 def retrieve_template(template_fn, tokendict={}):
73    """
74    <Purpose>
75       Retrieve a template and fill it in.   This is the only function you
76       need to use externally.
77
78    <Arguments>
79       template_fn: A string containing the file name of the template file.
80       tokendict: A dictionary with the keys as the replacement tags and the
81                  values the strings that should be listed there.
82
83    <Exceptions>
84       IOError:    as thrown by open(), read() and close()
85       IndexError: if there is a mismatch with tokendict and the replacement
86                   tags in the template document.
87       ValueError: if the replacement tags are malformatted
88
89    <Side Effects>
90       May read the template from disk (if it isn't already cached) and if so
91       will add the data to the global templatestore.
92
93    <Returns>
94       The HTML of the template with the items replaced.
95    """
96
97    # Argument checking needed
98
99
100    global templatestore
101
102    # Check to see if this is in my cache
103    if template_fn not in templatestore:
104       # if the glo_template_dir option was specified, then search for templates
105       # in that directory
106       if template_fn.startswith("/") or (not glo_template_dir):
107          template_pathname = template_fn
108       else:
109          template_pathname = os.path.join(glo_template_dir, template_fn)
110
111       # load it in
112       templatefileobj = open(template_pathname,"r")
113       templatestore[template_fn] = templatefileobj.read()
114       templatefileobj.close()
115
116
117    # It's now in my cache, so do the replacements...
118    usedtags = []
119    outstring = ''
120    for item in divide_string_into_taglist(templatestore[template_fn]):
121       if isinstance(item, str):
122          # append strings
123          outstring += item
124       elif isinstance(item, Tag):
125          # replace tags and append
126          thistagname = item.tagname
127
128          # put it in the used tag list
129          if thistagname not in usedtags:
130             usedtags.append(thistagname)
131          
132          # May throw an IndexError
133          outstring += tokendict[thistagname]
134       else:
135          raise Exception, "Internal Error, item not a string or tag!"
136
137    # Check that all the tokens were used
138    usedtags.sort()
139    totaltokens = tokendict.keys()
140    totaltokens.sort()
141
142    # SMBAKER - allow templates to use less than the tokens that are supplied
143    # if usedtags != totaltokens:
144    #   raise IndexError, "Mismatch between the used tags ("+str(usedtags)+") and the token keys ("+str(tokendict)+") in retrieve template"
145  
146    return outstring
147    
148          
149          
150        
151    
152    
153    
154
155
156
157         
158 def divide_string_into_taglist(instring):
159    """
160    <Purpose>
161       Take a string and return a list comprised of strings and tags.
162       This is intended to be private, but I can't figure out how to make 
163       the unit test module test a function starting with __.
164
165    <Arguments>   
166       instring:  The string to manipulate
167
168    <Exceptions>
169       ValueError: if the tags are malformatted
170
171    <Side Effects>
172       None
173
174    <Returns>
175       A list containing strings and tags.   This can be used by the caller to
176       do replacements on tags.   There will never be two consecutive
177       strings or tags in the returned list.   However the strings may be '' if
178       there are consecutive tags.
179    """
180
181    # I need to add argument checking...
182
183
184    
185    tagindicator = arizonaconfig.get_option("tagindicator")
186
187    # Break the file into a list of strings.   The even should be tags and the 
188    # odd should be strings.   
189    stringlist = instring.split(tagindicator)
190
191    # If the list has even length then there was an odd number of tag indicators
192    if len(stringlist) % 2 == 0:
193       raise ValueError, "Odd number of tag indicators in arizonatemplate"
194
195    retlist = []
196    for index in range(0, len(stringlist)):
197       # if an odd element it's okay as is 
198       # The code checks for even because list indices start at 0
199       if index % 2 == 0:
200          retlist.append(stringlist[index])
201       # otherwise make it into a tag
202       else:
203          retlist.append(Tag(stringlist[index]))
204       
205    return retlist
206       
207    
208
209
210      
211
212