123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- __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()
|