|
@@ -0,0 +1,133 @@
|
|
|
+__author__ = 'marcos.medeiros'
|
|
|
+
|
|
|
+
|
|
|
+class RtfTemplate(object):
|
|
|
+ """
|
|
|
+ A file object that when read fills an RTF template with context data.
|
|
|
+ The template variables must come between brackets "[]", instead of braces "{}",
|
|
|
+ and will be interpreted with the builtin format rules (that means you can reference
|
|
|
+ fields and elements, apply formatting rules (with comma ":") to the returned values, etc).
|
|
|
+
|
|
|
+ Use two open brackets to represent an open bracket. Close brackets without an equivalent
|
|
|
+ open bracket are repeated verbatim. Thus, to represent the text "[]", the original document
|
|
|
+ must contain the text "[[]".
|
|
|
+
|
|
|
+ Brackets were chosen because they aren't parsed by the RTF format, and thus can be inserted
|
|
|
+ directly from WYSIWYG editors.
|
|
|
+ """
|
|
|
+ def __init__(self, file, context):
|
|
|
+ """
|
|
|
+ Open the template for reading, replacing the variables with the values from the
|
|
|
+ given context.
|
|
|
+ :param file: Template that will be read.
|
|
|
+ :param context: Values that will be inserted at the place of the variables.
|
|
|
+ """
|
|
|
+ self.name = file
|
|
|
+ self.template = open(file, 'r')
|
|
|
+ self.encoding = self.template.encoding
|
|
|
+ self.context = context
|
|
|
+ self.pattern = ''
|
|
|
+ self.brackets = 0
|
|
|
+ self.partial = ''
|
|
|
+ self.softspace = 0
|
|
|
+
|
|
|
+ def format(self, template):
|
|
|
+ """
|
|
|
+ Formats the template with this object's context.
|
|
|
+ Notice that a template may contain only part of a variable,
|
|
|
+ what will make its value appear only at a later call of format.
|
|
|
+ :param template: Original template text.
|
|
|
+ :return: The formatted text.
|
|
|
+ """
|
|
|
+ ret = ''
|
|
|
+ for c in template:
|
|
|
+ if self.brackets == 0 and c != '[':
|
|
|
+ ret += c
|
|
|
+ else:
|
|
|
+ if c == '[':
|
|
|
+ if self.brackets != 0:
|
|
|
+ self.pattern += c
|
|
|
+ self.brackets += 1
|
|
|
+ if self.brackets == 2 and self.pattern == '[':
|
|
|
+ ret += '['
|
|
|
+ self.brackets = 0
|
|
|
+ self.pattern = ''
|
|
|
+ elif c == ']':
|
|
|
+ self.brackets -= 1
|
|
|
+ if self.brackets == 0:
|
|
|
+ ret += ('{'+self.pattern+'}').format(**self.context)
|
|
|
+ self.pattern = ''
|
|
|
+ else:
|
|
|
+ self.pattern += c
|
|
|
+ else:
|
|
|
+ self.pattern += c
|
|
|
+ return ret
|
|
|
+
|
|
|
+ def _next_with(self, func):
|
|
|
+ buf = func()
|
|
|
+ f = self.format(buf)
|
|
|
+ if buf and not f:
|
|
|
+ return self._next_with(func)
|
|
|
+ return f
|
|
|
+
|
|
|
+ def next(self):
|
|
|
+ return self._next_with(self.template.next)
|
|
|
+
|
|
|
+ def __next__(self):
|
|
|
+ return self._next_with(self.template.__next__)
|
|
|
+
|
|
|
+ def _read_by(self, func, size):
|
|
|
+ actual_size = size
|
|
|
+ if self.partial:
|
|
|
+ actual_size = size - len(self.partial)
|
|
|
+ if actual_size < 0 < size:
|
|
|
+ f = self.partial[0:size]
|
|
|
+ self.partial = self.partial[size:]
|
|
|
+ return f
|
|
|
+ buf = func(actual_size)
|
|
|
+ f = self.partial + self.format(buf)
|
|
|
+ if buf and not f:
|
|
|
+ return self.read(size)
|
|
|
+ if 0 < size < len(f):
|
|
|
+ self.partial = f[size:]
|
|
|
+ return f[0:size]
|
|
|
+ self.partial = ''
|
|
|
+ return f
|
|
|
+
|
|
|
+ def read(self, size=-1):
|
|
|
+ return self._read_by(self.template.read, size)
|
|
|
+
|
|
|
+ def readline(self, size):
|
|
|
+ return self._read_by(self.template.readline, size)
|
|
|
+
|
|
|
+ def close(self):
|
|
|
+ self.template.close()
|
|
|
+
|
|
|
+ def isatty(self):
|
|
|
+ return self.template.isatty()
|
|
|
+
|
|
|
+ def __iter__(self):
|
|
|
+ return self
|
|
|
+
|
|
|
+ @property
|
|
|
+ def closed(self):
|
|
|
+ return self.template.closed
|
|
|
+
|
|
|
+ @property
|
|
|
+ def newlines(self):
|
|
|
+ return self.template.newlines
|
|
|
+
|
|
|
+ @classmethod
|
|
|
+ def format_into(cls, template, context, file):
|
|
|
+ """
|
|
|
+ Formats the template, writing the resulting data into the given file.
|
|
|
+ :param template: Name of the template file.
|
|
|
+ :param context: Context where variables will be evaluated.
|
|
|
+ :param file: Name of the file that will be written with the formatted data.
|
|
|
+ """
|
|
|
+ t = RtfTemplate(template, context)
|
|
|
+ f = open(file, 'w')
|
|
|
+ for l in t:
|
|
|
+ f.write(l)
|
|
|
+ f.close()
|
|
|
+ t.close()
|