##language:zh ''' 含有章节索引的中文 文章模板 ''' -- limodou [<>] <> = Meteor源程序 = ''程序不长,因此列在这里'' == Template程序代码 == {{{#!python #coding=utf-8 # Programmer: limodou # E-mail: chatme@263.net # # Copyleft 2004 limodou # # Distributed under the terms of the GPL (GNU Public License) # # NewEdit is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # $Id$ import re import sets import types import csv import os import shutil import os.path class TemplateException(Exception): pass class ObjectType(TemplateException): pass class NoPreprocess(TemplateException): pass class T: def __init__(self, string): self.text = string def getText(self): return self.text #预处理器基类 class PreprocessBase: #ptype 为处理器的名字,如'py' def __init__(self, ptype, beginchars='<#', endchars='#>'): self.ptype = ptype self.beginchars = beginchars #define template var's left delimeter chars self.endchars = endchars #define template var's right delimeter chars #进行模板分析,应返回T对象的一个字典和相应的相关集 def process(self, obj): return {}, {} def getPattern(self): return r'%s(\w+)%s' % (self.beginchars, self.endchars) class PyPreprocess(PreprocessBase): def process(self, modulename): mod = __import__(modulename) components = modulename.split('.') for comp in components[1:]: mod = getattr(mod, comp) vars = {} nodes = {} for vn in dir(mod): v = getattr(mod, vn) if hasattr(v, '__class__') and v.__class__.__name__ == 'T': vars[vn] = v nodes[vn] = self._get_rely_on_node(v.getText()) return vars, nodes #取模板元素的相关集 def _get_rely_on_node(self, s): #search for %(name)s format, make a dict re_node = re.compile(self.getPattern()) return list(sets.Set(re_node.findall(s))) #定义模板处理类 class Template: preprocess ={} def __init__(self): self.vars = {} self.nodes = {} #装入模板 def load(self, tplfile, tpltype='py'): self.pre = self.preprocess.get(tpltype, None) if not self.pre: raise NoPreprocess, 'No proper preprocess' vars, nodes = self.pre.process(tplfile) self.vars.update(vars) self.nodes.update(nodes) #生成模板值 #values应为字典的字典。即每一个模板元素如果引用有外部的变量,那么在values中应有此模板元素的一个键。 #同时它的值应为所有外部变量的一个字典 def value(self, target, values={}): self.global_values = values.get(target, {}) self.target = target return self._value(target, self.global_values) def _value(self, target, values=None): text = self.OnReplace(target, values) if text is not None: return text nodes = self.nodes[target] if not isinstance(values, types.ListType): values = [values] s = [] for v in values: vals = {} for node in nodes: if not v.has_key(node): if node in self.vars.keys(): vals[node] = self._value(node, self.global_values.get(node, {})) else: if node in self.vars.keys(): #如果node是一个模板变量,则继续替换 vals[node] = self._value(node, v[node]) else: #说明为一个外部变量 vals[node] = v[node] s.append(self._replace(target, self.vars[target].getText(), vals)) return ''.join(s) #可以自已写处理函数 #name为模板元素的名字 #text为要替换的引用变量的名字 def OnReplace(self, name, values): return None #把一段文件本的可替换信息使用values中的变量进行替换 #text是段字符串 #values是一个对应替换信息的字典 def _replace(self, name, text, values): def dosup(matchobj, name=name, text=text, values=values): if values: result = values.get(matchobj.groups()[0], matchobj.group()) else: result = matchobj.group() return result if not text: return text return re.sub(self.pre.getPattern(), dosup, text) def writeDot(self, f=None): s = [] for key, values in self.nodes.items(): for v in values: s.append('%s -> %s;\n' % (key, v)) text = 'digraph G{\n' + ''.join(s) + '}\n' if isinstance(f, types.FileType): f.write(text) return text #注册预处理器函数,是一个处理器实例 def register(preprocess): Template.preprocess[preprocess.ptype] = preprocess register(PyPreprocess('py')) class TemplateScript: def __init__(self): self.template = Template() #script为一个cvs格式的迭代器对象。需要有next方法。可以直接传入打开的文件对象 def __call__(self, script, vars=None): if not vars: vars = {} lines = csv.reader(script, delimiter=' ') for v in lines: if v: self._do(vars, *v) def _do(self, vars, *args): para = args cmd = para[0].lower() if cmd and cmd[0] == '#': return if cmd == 'mkdir': if not os.path.exists(para[1]): os.makedirs(para[1]) elif cmd == 'copy': if os.path.isdir(para[2]): dstfile = os.path.join(para[2], para[1]) else: dstfile = para[2] shutil.copyfile(para[1], dstfile) elif cmd == 'run': self.template.load(para[1], para[2]) file(para[4], 'wb').write(self.template.value(para[3], vars)) if __name__ == '__main__': vars = { 'program':{ 'hello':[ {'var' :'var1'}, {'var' :'var2'}, {'var' :'var3'}, ], }, } # template = Template() # template.load('tmp2') # print template.value('program', vars) import StringIO buf = StringIO.StringIO("""mkdir src/doc mkdir build copy dict.xml src/doc run tmp2 py "program" build/s.py """) ts = TemplateScript() ts(buf, vars) }}} == Tree模块程序 == {{{#!python #coding=utf-8 # Programmer: limodou # E-mail: chatme@263.net # # Copyleft 2004 limodou # # Distributed under the terms of the GPL (GNU Public License) # # NewEdit is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # $Id$ """ 本模块是用于保存树状结构的数据。保存和存储时均以树的引用方式来引用,如tree["/root/node"] 内部使用字典来保存,有多种接口可以将内容保存为其它的形式或从其它的形式读出数据 """ import types #import xml.sax import xml.dom.minidom class UnsupportType(Exception): pass class Tree: def __init__(self, dicts=None): if not dicts: self.dicts = {} else: self.dicts = dicts self.tab = ' ' * 4 def __getitem__(self, key): path = self._path(key) dict = self.getNode(self.dicts, path) return dict.get(path[-1], None) def __setitem__(self, key, value): path = self._path(key) dict = self.getNode(self.dicts, path) dict[path[-1]] = value def append(self, key, value): path = self._path(key) key = path[-1] dict = self.getNode(self.dicts, path) print 'dict', dict if dict.has_key(key): if isinstance(dict[key], types.ListType): dict[key].append(value) elif isinstance(dict[key], types.TupleType): dict[key] = dict[key] + (value,) else: dict[key] = [dict[key], value] else: dict[key] = value def getNode(self, dicts, path): if len(path) > 1: node = path[0] if not dicts.has_key(node): dicts[node] = {} return self.getNode(dicts[node], path[1:]) return dicts def _path(self, key): if key.startswith('/'): key = key[1:] return key.split('/') def write_to_xml(self): s = [] s.append('\n') s.append('\n') self._write_dict(s, self.dicts, level = 1) s.append('\n') return ''.join(s) def _write_dict(self, s, dicts, level): for key, value in dicts.items(): if isinstance(value, types.DictType): s.append(self.tab * level + '<%s>\n' % key) self._write_dict(s, value, level + 1) s.append(self.tab * level + '\n' % key) elif isinstance(value, types.BooleanType): s.append(self.tab * level + '<%s type="boolean">%s\n' % (key, str(value), key)) elif isinstance(value, types.StringType): s.append(self.tab * level + '<%s type="string">%s\n' % (key, self._quoteText(value), key)) elif isinstance(value, types.UnicodeType): s.append(self.tab * level + '<%s type="unicode">%s\n' % (key, self._quoteText(value.encode('utf-8')), key)) elif isinstance(value, types.IntType): s.append(self.tab * level + '<%s type="int">%d\n' % (key, value, key)) elif isinstance(value, types.LongType): s.append(self.tab * level + '<%s type="long">%ld\n' % (key, value, key)) elif isinstance(value, types.FloatType): s.append(self.tab * level + '<%s type="float">%f\n' % (key, value, key)) elif isinstance(value, types.ListType) or isinstance(value, types.TupleType): for v in value: dic = {key:v} self._write_dict(s, dic, level) else: raise UnsupportType, 'Unsupport type' def read_from_xml(self, text): self.dicts = {} dom = xml.dom.minidom.parseString(text) root = dom.documentElement self._read_from_xml(self.dicts, root) def _read_from_xml(self, dicts, root): for node in root.childNodes: name = node.nodeName.encode('utf-8') if node.nodeType == node.ELEMENT_NODE: if node.hasAttribute('type'): t = node.getAttribute('type') content = self._getTagText(node) if t == 'int': value = int(content) elif t == 'long': value = long(content) elif t == 'string': value = content.encode('utf-8') elif t == 'unicode': value = content elif t == 'boolean': if content == 'True': value = True else: value = False elif t == 'float': value = float(content) else: raise UnsupportType, 'Unsupport type' if dicts.has_key(name): v = dicts[name] if isinstance(v, types.ListType): v.append(value) else: dicts[name] = [dicts[name], value] else: dicts[name] = value else: dic = {} if dicts.has_key(name): v = dicts[name] if isinstance(v, types.ListType): v.append(dic) else: dicts[name] = [dicts[name], dic] else: dicts[name] = dic self._read_from_xml(dic, node) def _getTagText(self, tag): rc = '' for node in tag.childNodes: if node.nodeType in ( node.TEXT_NODE, node.CDATA_SECTION_NODE): rc = rc + node.data return rc def _quoteText(self, text): text = text.replace('&', '&') text = text.replace('<', '<') return text def getDict(self): return self.dicts if __name__ == '__main__': tree = Tree() name = '中国' tree['/root/command/test1'] =[{ 'var':'<&>'}, {'var':'limodou'}] tree['/root/command/ttt'] =[unicode(name, 'utf-8'), 100, {'a':False}] tree['/root/command/ttt'] =[(1,2), ('aaa', 'bbb', 'cccc')] #this form is not support text = tree.write_to_xml() file("dict.xml", 'w').write(text) text = file('dict.xml').read() tree.read_from_xml(text) print tree.dicts }}}