summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Vilcans <martin@librador.com>2011-09-08 23:03:13 +0200
committerMartin Vilcans <martin@librador.com>2011-09-09 00:00:19 +0200
commit579fa278aeaa26dccbdfe28b4b5ce0db3390c0b8 (patch)
tree4059ba95886bea7f743b3f303176079ca1669069
parentf29785e72f42a6f9d6f69f031f00883348e91824 (diff)
Split code into more modules.
-rw-r--r--screenplain/export/pdf.py2
-rw-r--r--screenplain/export/text.py2
-rw-r--r--screenplain/format.py19
-rw-r--r--screenplain/main.py2
-rw-r--r--screenplain/parsers/__init__.py0
-rw-r--r--screenplain/parsers/spmd.py66
-rw-r--r--screenplain/types.py (renamed from screenplain/parse.py)84
-rw-r--r--tests/spmd_test.py (renamed from tests/parse_test.py)30
8 files changed, 103 insertions, 102 deletions
diff --git a/screenplain/export/pdf.py b/screenplain/export/pdf.py
index 48eeab8..f7c9f24 100644
--- a/screenplain/export/pdf.py
+++ b/screenplain/export/pdf.py
@@ -3,7 +3,7 @@ import fileinput
from reportlab.pdfgen import canvas
from reportlab.lib import pagesizes
-from screenplain.parse import parse, get_pages
+from screenplain.format import get_pages
def to_pdf(screenplay, output_file):
# pagesizes.letter, pagesizes.A4
diff --git a/screenplain/export/text.py b/screenplain/export/text.py
index 8f7cb3d..12b8723 100644
--- a/screenplain/export/text.py
+++ b/screenplain/export/text.py
@@ -1,6 +1,6 @@
import sys
import codecs
-from screenplain.parse import parse, get_pages
+from screenplain.format import get_pages
def to_text(screenplay, output_file):
out = codecs.open(output_file, 'w', 'utf-8')
diff --git a/screenplain/format.py b/screenplain/format.py
new file mode 100644
index 0000000..be5298b
--- /dev/null
+++ b/screenplain/format.py
@@ -0,0 +1,19 @@
+# Numbers from http://www.emacswiki.org/emacs/ScreenPlay
+# According to http://johnaugust.com/2004/how-many-lines-per-page
+lines_per_page = 56
+
+
+def get_pages(paragraphs):
+ """Generates one list of lines per page."""
+ lines_on_page = []
+ for paragraph in paragraphs:
+ top_margin = paragraph.top_margin if lines_on_page else 0
+ para_lines = list(paragraph.format())
+
+ if len(lines_on_page) + top_margin + len(para_lines) > lines_per_page:
+ yield lines_on_page
+ lines_on_page = []
+ else:
+ lines_on_page += [''] * top_margin
+ lines_on_page += para_lines
+ yield lines_on_page
diff --git a/screenplain/main.py b/screenplain/main.py
index 79ff3eb..469da0f 100644
--- a/screenplain/main.py
+++ b/screenplain/main.py
@@ -8,7 +8,7 @@ import sys
import codecs
from optparse import OptionParser
-from parse import parse
+from screenplain.parsers.spmd import parse
usage = 'Usage: %prog [options] input-file output-file'
diff --git a/screenplain/parsers/__init__.py b/screenplain/parsers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/screenplain/parsers/__init__.py
diff --git a/screenplain/parsers/spmd.py b/screenplain/parsers/spmd.py
new file mode 100644
index 0000000..3da8864
--- /dev/null
+++ b/screenplain/parsers/spmd.py
@@ -0,0 +1,66 @@
+import itertools
+from screenplain.types import Slug, Action, Dialog, DualDialog, Transition
+
+slug_prefixes = (
+ 'INT. ',
+ 'EXT. ',
+ 'INT./EXT. ',
+ 'INT/EXT. ',
+ 'INT ',
+ 'EXT ',
+ 'INT/EXT ',
+ 'I/E ',
+)
+
+TWOSPACE = ' ' * 2
+
+def is_blank(string):
+ return string == '' or string.isspace() and string != ' '
+
+def is_slug(blanks_before, string):
+ if blanks_before >= 2:
+ return True
+ upper = string.upper()
+ return any(upper.startswith(s) for s in slug_prefixes)
+
+def _create_dialog(line_list):
+ try:
+ dual_index = line_list.index('||')
+ except ValueError:
+ return Dialog(line_list)
+ else:
+ return DualDialog(line_list[:dual_index], line_list[dual_index + 1:])
+
+def create_paragraph(blanks_before, line_list):
+ if is_slug(blanks_before, line_list[0]):
+ return Slug(line_list)
+ if (
+ len(line_list) > 1 and
+ line_list[0].isupper() and
+ not line_list[0].endswith(TWOSPACE)
+ ):
+ return _create_dialog(line_list)
+ elif len(line_list) == 1 and line_list[0].endswith(':') and line_list[0].isupper():
+ # TODO: need to check whether the *next* paragraph is a slug
+ # before assuming this is a transition.
+ return Transition(line_list)
+ else:
+ return Action(line_list)
+
+def clean_line(line):
+ """Strips leading whitespace and trailing end of line characters in a string.
+
+ Leading whitespace is insignificant in SPMD, and trailing EOL
+ appear when reading from a file or HTML form.
+ """
+ return line.lstrip().rstrip('\r\n')
+
+def parse(source):
+ """Reads raw text input and generates paragraph objects."""
+ blank_count = 0
+ source = (clean_line(line) for line in source)
+ for blank, lines in itertools.groupby(source, is_blank):
+ if blank:
+ blank_count = len(list(lines))
+ else:
+ yield create_paragraph(blank_count, list(lines))
diff --git a/screenplain/parse.py b/screenplain/types.py
index 9e97eed..4b12418 100644
--- a/screenplain/parse.py
+++ b/screenplain/types.py
@@ -1,23 +1,4 @@
-import itertools
import textwrap
-import re
-
-# Numbers from http://www.emacswiki.org/emacs/ScreenPlay
-# According to http://johnaugust.com/2004/how-many-lines-per-page
-lines_per_page = 56
-
-slug_prefixes = (
- 'INT. ',
- 'EXT. ',
- 'INT./EXT. ',
- 'INT/EXT. ',
- 'INT ',
- 'EXT ',
- 'INT/EXT ',
- 'I/E ',
-)
-
-TWOSPACE = ' ' * 2
class Slug(object):
indent = ''
@@ -115,68 +96,3 @@ class Transition(object):
for line in textwrap.wrap(self.text, width=self.fill):
yield self.indent + line
-def is_blank(string):
- return string == '' or string.isspace() and string != ' '
-
-def is_slug(blanks_before, string):
- if blanks_before >= 2:
- return True
- upper = string.upper()
- return any(upper.startswith(s) for s in slug_prefixes)
-
-def _create_dialog(line_list):
- try:
- dual_index = line_list.index('||')
- except ValueError:
- return Dialog(line_list)
- else:
- return DualDialog(line_list[:dual_index], line_list[dual_index + 1:])
-
-def create_paragraph(blanks_before, line_list):
- if is_slug(blanks_before, line_list[0]):
- return Slug(line_list)
- if (
- len(line_list) > 1 and
- line_list[0].isupper() and
- not line_list[0].endswith(TWOSPACE)
- ):
- return _create_dialog(line_list)
- elif len(line_list) == 1 and line_list[0].endswith(':') and line_list[0].isupper():
- # TODO: need to check whether the *next* paragraph is a slug
- # before assuming this is a transition.
- return Transition(line_list)
- else:
- return Action(line_list)
-
-def clean_line(line):
- """Strips leading whitespace and trailing end of line characters in a string.
-
- Leading whitespace is insignificant in SPMD, and trailing EOL
- appear when reading from a file or HTML form.
- """
- return line.lstrip().rstrip('\r\n')
-
-def parse(source):
- """Reads raw text input and generates paragraph objects."""
- blank_count = 0
- source = (clean_line(line) for line in source)
- for blank, lines in itertools.groupby(source, is_blank):
- if blank:
- blank_count = len(list(lines))
- else:
- yield create_paragraph(blank_count, list(lines))
-
-def get_pages(paragraphs):
- """Generates one list of lines per page."""
- lines_on_page = []
- for paragraph in paragraphs:
- top_margin = paragraph.top_margin if lines_on_page else 0
- para_lines = list(paragraph.format())
-
- if len(lines_on_page) + top_margin + len(para_lines) > lines_per_page:
- yield lines_on_page
- lines_on_page = []
- else:
- lines_on_page += [''] * top_margin
- lines_on_page += para_lines
- yield lines_on_page
diff --git a/tests/parse_test.py b/tests/spmd_test.py
index 1eabdb2..cb349a1 100644
--- a/tests/parse_test.py
+++ b/tests/spmd_test.py
@@ -1,6 +1,6 @@
import unittest2
-from screenplain import parse
-from screenplain.parse import Slug, Action, Dialog, DualDialog, Transition
+from screenplain.parsers.spmd import parse
+from screenplain.types import Slug, Action, Dialog, DualDialog, Transition
class ParseTests(unittest2.TestCase):
@@ -14,7 +14,7 @@ class ParseTests(unittest2.TestCase):
# least one blank line preceding it.
# NOTE: Actually the list used in Appendix 1
def test_slug_with_prefix(self):
- paras = list(parse.parse([
+ paras = list(parse([
'INT. SOMEWHERE - DAY',
'',
'THIS IS JUST ACTION',
@@ -22,14 +22,14 @@ class ParseTests(unittest2.TestCase):
self.assertEquals([Slug, Action], [type(p) for p in paras])
def test_action_is_not_a_slug(self):
- paras = list(parse.parse([
+ paras = list(parse([
'',
'THIS IS JUST ACTION',
]))
self.assertEquals([Action], [type(p) for p in paras])
def test_two_lines_creates_a_slug(self):
- types = [type(p) for p in parse.parse([
+ types = [type(p) for p in parse([
'',
'',
'This is a slug',
@@ -40,7 +40,7 @@ class ParseTests(unittest2.TestCase):
# A Character element is any line entirely in caps, with one empty
# line before it and without an empty line after it.
def test_all_caps_is_character(self):
- paras = [p for p in parse.parse([
+ paras = [p for p in parse([
'SOME GUY',
'Hello',
])]
@@ -52,7 +52,7 @@ class ParseTests(unittest2.TestCase):
# SPMD would not be able to support a character named "23". We
# might need a syntax to force a character element.
def test_nonalpha_character(self):
- paras = list(parse.parse([
+ paras = list(parse([
'23',
'Hello',
]))
@@ -61,14 +61,14 @@ class ParseTests(unittest2.TestCase):
# See
# http://prolost.com/storage/downloads/spmd/SPMD_proposal.html#section-br
def test_twospaced_line_is_not_character(self):
- paras = list(parse.parse([
+ paras = list(parse([
'SCANNING THE AISLES... ',
'Where is that pit boss?',
]))
self.assertEquals([Action], [type(p) for p in paras])
def test_simple_parenthetical(self):
- paras = list(parse.parse([
+ paras = list(parse([
'STEEL',
'(starting the engine)',
'So much for retirement!',
@@ -80,7 +80,7 @@ class ParseTests(unittest2.TestCase):
self.assertEqual((False, 'So much for retirement!'), dialog.blocks[1])
def test_dual_dialog(self):
- paras = list(parse.parse([
+ paras = list(parse([
'BRICK',
'Fuck retirement.',
'||',
@@ -96,7 +96,7 @@ class ParseTests(unittest2.TestCase):
def test_standard_transition(self):
- paras = list(parse.parse([
+ paras = list(parse([
'Jack begins to argue vociferously in Vietnamese (?)',
'',
'CUT TO:',
@@ -107,7 +107,7 @@ class ParseTests(unittest2.TestCase):
def test_standard_transition(self):
- paras = list(parse.parse([
+ paras = list(parse([
'Jack begins to argue vociferously in Vietnamese (?)',
'',
'CUT TO:',
@@ -117,7 +117,7 @@ class ParseTests(unittest2.TestCase):
self.assertEquals([Action, Transition, Slug], [type(p) for p in paras])
def test_transition_needs_to_be_upper_case(self):
- paras = list(parse.parse([
+ paras = list(parse([
'Jack begins to argue vociferously in Vietnamese (?)',
'',
'cut to:',
@@ -127,7 +127,7 @@ class ParseTests(unittest2.TestCase):
self.assertEquals([Action, Action, Slug], [type(p) for p in paras])
def test_not_a_transition_on_trailing_whitespace(self):
- paras = list(parse.parse([
+ paras = list(parse([
'Jack begins to argue vociferously in Vietnamese (?)',
'',
'CUT TO: ',
@@ -139,7 +139,7 @@ class ParseTests(unittest2.TestCase):
# Not implemented yet
@unittest2.expectedFailure
def test_transition_must_be_followed_by_slug(self):
- paras = list(parse.parse([
+ paras = list(parse([
'Bill lights a cigarette.',
'',
'CUT TO:',