##// END OF EJS Templates
move repeated work out of inner loops.
Vadim Gelfer -
r1900:f2815605 default
parent child Browse files
Show More
@@ -1,120 +1,125 b''
1 import re
1 from demandload import demandload
2 from demandload import demandload
2 demandload(globals(), "cgi os re time urllib util")
3 demandload(globals(), "cgi os time urllib util")
3
4
4 class templater(object):
5 class templater(object):
5 def __init__(self, mapfile, filters={}, defaults={}):
6 def __init__(self, mapfile, filters={}, defaults={}):
6 self.cache = {}
7 self.cache = {}
7 self.map = {}
8 self.map = {}
8 self.base = os.path.dirname(mapfile)
9 self.base = os.path.dirname(mapfile)
9 self.filters = filters
10 self.filters = filters
10 self.defaults = defaults
11 self.defaults = defaults
11
12
12 for l in file(mapfile):
13 for l in file(mapfile):
13 m = re.match(r'(\S+)\s*=\s*(".*"|\'.*\')$', l)
14 m = re.match(r'(\S+)\s*=\s*(".*"|\'.*\')$', l)
14 if m:
15 if m:
15 self.cache[m.group(1)] = eval(m.group(2))
16 self.cache[m.group(1)] = eval(m.group(2))
16 else:
17 else:
17 m = re.match(r'(\S+)\s*=\s*(\S+)', l)
18 m = re.match(r'(\S+)\s*=\s*(\S+)', l)
18 if m:
19 if m:
19 self.map[m.group(1)] = os.path.join(self.base, m.group(2))
20 self.map[m.group(1)] = os.path.join(self.base, m.group(2))
20 else:
21 else:
21 raise LookupError(_("unknown map entry '%s'") % l)
22 raise LookupError(_("unknown map entry '%s'") % l)
22
23
23 def __contains__(self, key):
24 def __contains__(self, key):
24 return key in self.cache
25 return key in self.cache
25
26
26 def __call__(self, t, **map):
27 def __call__(self, t, **map):
27 m = self.defaults.copy()
28 m = self.defaults.copy()
28 m.update(map)
29 m.update(map)
29 try:
30 try:
30 tmpl = self.cache[t]
31 tmpl = self.cache[t]
31 except KeyError:
32 except KeyError:
32 tmpl = self.cache[t] = file(self.map[t]).read()
33 tmpl = self.cache[t] = file(self.map[t]).read()
33 return self.template(tmpl, self.filters, **m)
34 return self.template(tmpl, self.filters, **m)
34
35
36 template_re = re.compile(r"#([a-zA-Z_][a-zA-Z0-9_]*)"
37 r"((%[a-zA-Z_][a-zA-Z0-9_]*)*)"
38 r"((\|[a-zA-Z_][a-zA-Z0-9_]*)*)#")
39
35 def template(self, tmpl, filters={}, **map):
40 def template(self, tmpl, filters={}, **map):
41 lm = map.copy()
36 while tmpl:
42 while tmpl:
37 m = re.search(r"#([a-zA-Z_][a-zA-Z0-9_]*)"
43 m = self.template_re.search(tmpl)
38 r"((%[a-zA-Z_][a-zA-Z0-9_]*)*)"
39 r"((\|[a-zA-Z_][a-zA-Z0-9_]*)*)#", tmpl)
40 if m:
44 if m:
41 yield tmpl[:m.start(0)]
45 start = m.start(0)
46 if start:
47 yield tmpl[:start]
42 v = map.get(m.group(1), "")
48 v = map.get(m.group(1), "")
43 v = callable(v) and v(**map) or v
49 v = callable(v) and v(**map) or v
44
50
45 format = m.group(2)
51 format = m.group(2)
46 fl = m.group(4)
52 fl = m.group(4)
47
53
48 if format:
54 if format:
49 q = v.__iter__
55 q = v.__iter__
50 for i in q():
56 for i in q():
51 lm = map.copy()
52 lm.update(i)
57 lm.update(i)
53 yield self(format[1:], **lm)
58 yield self(format[1:], **lm)
54
59
55 v = ""
60 v = ""
56
61
57 elif fl:
62 elif fl:
58 for f in fl.split("|")[1:]:
63 for f in fl.split("|")[1:]:
59 v = filters[f](v)
64 v = filters[f](v)
60
65
61 yield v
66 yield v
62 tmpl = tmpl[m.end(0):]
67 tmpl = tmpl[m.end(0):]
63 else:
68 else:
64 yield tmpl
69 yield tmpl
65 return
70 break
71
72 agescales = [("second", 1),
73 ("minute", 60),
74 ("hour", 3600),
75 ("day", 3600 * 24),
76 ("week", 3600 * 24 * 7),
77 ("month", 3600 * 24 * 30),
78 ("year", 3600 * 24 * 365)]
79
80 agescales.reverse()
66
81
67 def age(x):
82 def age(x):
68 def plural(t, c):
83 def plural(t, c):
69 if c == 1:
84 if c == 1:
70 return t
85 return t
71 return t + "s"
86 return t + "s"
72 def fmt(t, c):
87 def fmt(t, c):
73 return "%d %s" % (c, plural(t, c))
88 return "%d %s" % (c, plural(t, c))
74
89
75 now = time.time()
90 now = time.time()
76 then = x[0]
91 then = x[0]
77 delta = max(1, int(now - then))
92 delta = max(1, int(now - then))
78
93
79 scales = [["second", 1],
94 for t, s in agescales:
80 ["minute", 60],
81 ["hour", 3600],
82 ["day", 3600 * 24],
83 ["week", 3600 * 24 * 7],
84 ["month", 3600 * 24 * 30],
85 ["year", 3600 * 24 * 365]]
86
87 scales.reverse()
88
89 for t, s in scales:
90 n = delta / s
95 n = delta / s
91 if n >= 2 or s == 1:
96 if n >= 2 or s == 1:
92 return fmt(t, n)
97 return fmt(t, n)
93
98
94 def nl2br(text):
99 def nl2br(text):
95 return text.replace('\n', '<br/>\n')
100 return text.replace('\n', '<br/>\n')
96
101
97 def obfuscate(text):
102 def obfuscate(text):
98 return ''.join(['&#%d;' % ord(c) for c in text])
103 return ''.join(['&#%d;' % ord(c) for c in text])
99
104
100 common_filters = {
105 common_filters = {
101 "escape": lambda x: cgi.escape(x, True),
106 "escape": lambda x: cgi.escape(x, True),
102 "urlescape": urllib.quote,
107 "urlescape": urllib.quote,
103 "strip": lambda x: x.strip(),
108 "strip": lambda x: x.strip(),
104 "age": age,
109 "age": age,
105 "date": lambda x: util.datestr(x),
110 "date": lambda x: util.datestr(x),
106 "addbreaks": nl2br,
111 "addbreaks": nl2br,
107 "obfuscate": obfuscate,
112 "obfuscate": obfuscate,
108 "short": (lambda x: x[:12]),
113 "short": (lambda x: x[:12]),
109 "firstline": (lambda x: x.splitlines(1)[0]),
114 "firstline": (lambda x: x.splitlines(1)[0]),
110 "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--"),
115 "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--"),
111 "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S"),
116 "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S"),
112 }
117 }
113
118
114 def templatepath(name=None):
119 def templatepath(name=None):
115 for f in 'templates', '../templates':
120 for f in 'templates', '../templates':
116 fl = f.split('/')
121 fl = f.split('/')
117 if name: fl.append(name)
122 if name: fl.append(name)
118 p = os.path.join(os.path.dirname(__file__), *fl)
123 p = os.path.join(os.path.dirname(__file__), *fl)
119 if (name and os.path.exists(p)) or os.path.isdir(p):
124 if (name and os.path.exists(p)) or os.path.isdir(p):
120 return os.path.normpath(p)
125 return os.path.normpath(p)
General Comments 0
You need to be logged in to leave comments. Login now