changeset 3:6019eee799bf

Add base classes for rendering.
author Ludovic Chabant <ludovic@chabant.com>
date Tue, 03 Jan 2017 09:05:48 -0800
parents 59fe8cb6190d
children 9053902c750e
files fontaine/renderer.py tests/test_renderer.py
diffstat 2 files changed, 132 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/fontaine/renderer.py	Tue Jan 03 09:05:28 2017 -0800
+++ b/fontaine/renderer.py	Tue Jan 03 09:05:48 2017 -0800
@@ -1,4 +1,102 @@
 import re
+from fontaine.document import (
+    TYPE_ACTION, TYPE_CENTEREDACTION, TYPE_CHARACTER, TYPE_DIALOG,
+    TYPE_PARENTHETICAL, TYPE_TRANSITION, TYPE_LYRICS, TYPE_PAGEBREAK)
+
+
+class BaseDocumentRenderer:
+    def __init__(self, text_renderer=None):
+        self.text_renderer = text_renderer
+        if not text_renderer:
+            self.text_renderer = NullTextRenderer()
+
+        self._para_rdrs = {
+            TYPE_ACTION: self.write_action,
+            TYPE_CENTEREDACTION: self.write_centeredaction,
+            TYPE_CHARACTER: self.write_character,
+            TYPE_DIALOG: self.write_dialog,
+            TYPE_PARENTHETICAL: self.write_parenthetical,
+            TYPE_TRANSITION: self.write_transition,
+            TYPE_LYRICS: self.write_lyrics,
+            TYPE_PAGEBREAK: self.write_pagebreak,
+        }
+
+    def _tr(self, text):
+        return self.text_renderer.render_text(text)
+
+    def render_doc(self, doc):
+        self.write_header(doc)
+        self.render_title_page(doc.title_values)
+        for s in doc.scenes:
+            self.render_scene(s)
+        self.write_footer(doc)
+
+    def render_title_page(self, values):
+        # Render known metadata.
+        title = values.get('title')
+        credit = values.get('credit')
+        author = values.get('author') or values.get('authors')
+        source = values.get('source')
+        center_text = '\n\n'.join([
+            i for i in [title, credit, author, source]
+            if i is not None])
+        self.write_title_heading(self._tr(center_text))
+
+        ddate = values.get('date') or values.get('draft date')
+        contact = values.get('contact')
+        bottom_text = '\n\n'.join([
+            i for i in [ddate, contact]
+            if i is not None])
+        self.write_title_footer(self._tr(bottom_text))
+
+    def render_scene(self, scene):
+        if scene.header is not None:
+            self.write_scene_heading(scene.header)
+        for p in scene.paragraphs:
+            rdr_func = self._para_rdrs[p.type]
+            if p.type != TYPE_PAGEBREAK:
+                rdr_func(self._tr(p.text))
+            else:
+                rdr_func()
+
+    def write_header(self, doc):
+        pass
+
+    def write_footer(self, doc):
+        pass
+
+    def write_title_heading(self, text):
+        raise NotImplementedError()
+
+    def write_title_footer(self, text):
+        raise NotImplementedError()
+
+    def write_scene_heading(self, text):
+        raise NotImplementedError()
+
+    def write_action(self, text):
+        raise NotImplementedError()
+
+    def write_centeredaction(self, text):
+        raise NotImplementedError()
+
+    def write_character(self, text):
+        raise NotImplementedError()
+
+    def write_dialog(self, text):
+        raise NotImplementedError()
+
+    def write_parenthetical(self, text):
+        raise NotImplementedError()
+
+    def write_transition(self, text):
+        raise NotImplementedError()
+
+    def write_lyrics(self, text):
+        raise NotImplementedError()
+
+    def write_pagebreak(self):
+        raise NotImplementedError()
 
 
 RE_ITALICS = re.compile(
@@ -9,41 +107,52 @@
     r"(?P<before>^|\s)(?P<esc>\\)?_(?P<text>.*[^\s])_(?=[^a-zA-Z0-9]|$)")
 
 
-class BaseRenderer:
+class BaseTextRenderer:
     def render_text(self, text):
         # Replace bold stuff to catch double asterisks.
-        text = RE_BOLD.sub(self._do_write_bold, text)
-        text = RE_ITALICS.sub(self._do_write_italics, text)
-        text = RE_UNDERLINE.sub(self._do_write_underline, text)
+        text = RE_BOLD.sub(self._do_make_bold, text)
+        text = RE_ITALICS.sub(self._do_make_italics, text)
+        text = RE_UNDERLINE.sub(self._do_make_underline, text)
 
         return text
 
-    def _do_write_italics(self, m):
+    def _do_make_italics(self, m):
         if m.group('esc'):
             return m.group('before') + '*' + m.group('text') + '*'
         return (
             m.group('before') +
-            self.write_italics(m.group('text')))
+            self.make_italics(m.group('text')))
 
-    def _do_write_bold(self, m):
+    def _do_make_bold(self, m):
         if m.group('esc'):
             return m.group('before') + '**' + m.group('text') + '**'
         return (
             m.group('before') +
-            self.write_bold(m.group('text')))
+            self.make_bold(m.group('text')))
 
-    def _do_write_underline(self, m):
+    def _do_make_underline(self, m):
         if m.group('esc'):
             return m.group('before') + '_' + m.group('text') + '_'
         return (
             m.group('before') +
-            self.write_underline(m.group('text')))
+            self.make_underline(m.group('text')))
+
+    def make_italics(self, text):
+        raise NotImplementedError()
 
-    def write_italics(self, text):
+    def make_bold(self, text):
+        raise NotImplementedError()
+
+    def make_underline(self, text):
         raise NotImplementedError()
 
-    def write_bold(self, text):
-        raise NotImplementedError()
+
+class NullTextRenderer(BaseTextRenderer):
+    def make_bold(self, text):
+        return text
 
-    def write_underline(self, text):
-        raise NotImplementedError()
+    def make_italics(self, text):
+        return text
+
+    def make_underline(self, text):
+        return text
--- a/tests/test_renderer.py	Tue Jan 03 09:05:28 2017 -0800
+++ b/tests/test_renderer.py	Tue Jan 03 09:05:48 2017 -0800
@@ -1,15 +1,15 @@
 import pytest
-from fontaine.renderer import BaseRenderer
+from fontaine.renderer import BaseTextRenderer
 
 
-class TestRenderer(BaseRenderer):
-    def write_bold(self, text):
+class TestTextRenderer(BaseTextRenderer):
+    def make_bold(self, text):
         return 'B:' + text + ':B'
 
-    def write_italics(self, text):
+    def make_italics(self, text):
         return 'I:' + text + ':I'
 
-    def write_underline(self, text):
+    def make_underline(self, text):
         return 'U:' + text + ':U'
 
 
@@ -25,7 +25,7 @@
     ("This is an \_escaped_ one.", "This is an _escaped_ one.")
 ])
 def test_underline(intext, expected):
-    r = TestRenderer()
+    r = TestTextRenderer()
     out = r.render_text(intext)
     assert out == expected
 
@@ -42,7 +42,7 @@
     ("This is some \*escaped* one.", "This is some *escaped* one.")
 ])
 def test_italics(intext, expected):
-    r = TestRenderer()
+    r = TestTextRenderer()
     out = r.render_text(intext)
     assert out == expected
 
@@ -59,6 +59,6 @@
     ("This is some \**escaped** one.", "This is some **escaped** one.")
 ])
 def test_bold(intext, expected):
-    r = TestRenderer()
+    r = TestTextRenderer()
     out = r.render_text(intext)
     assert out == expected