Commits

Peter Ward committed 072f563

Added MIME stuff and new lyrics handler.

Comments (0)

Files changed (4)

shinypress/__init__.py

-import traceback
-import codecs
-import os
+from shinypress.handlers import text, lyrics, pdf, images, hacks
 
-from shinypress.handlers import handlers
-from shinypress.themes import themes
+handlers = dict(
+    text=text.render,
+    title=text.title,
+    lyrics=lyrics.render,
+    pdf=pdf.render,
+    images=images.render,
 
-from shinypress.latex import render_pdf
+    background=hacks.background,
+)
 
-# TODO: use something nicer?
-def warning(line_no, msg):
-    print 'Warning (line %s): %s' % (line_no, msg)
-
-def read_presentation(filename):
-    lines = codecs.open(filename, 'rU', 'utf-8')
-
-    # FIXME: hack to ensure relative paths work
-    old = os.getcwd()
-    new = os.path.dirname(filename)
-    if new:
-        os.chdir(new)
-
-    content = []
-    extras = []
-
-    for i, line in enumerate(lines):
-        line = line.strip()
-        if not line or line.startswith('#') or line.startswith('//'):
-            continue
-
-        handler, filename = line.split(':', 1)
-        handler = handler.strip()
-        filename = filename.strip()
-
-        # handle included files
-        # FIXME: no recursion detection! :)
-        if handler == 'include':
-            c, e = read_presentation(filename)
-            content.extend(c)
-            extras.extend(e)
-            continue
-
-        if handler not in handlers:
-            warning(i, 'Undefined handler: %s' % handler)
-            continue
-
-        handler_func = handlers[handler]
-        try:
-            c, e = handler_func(filename)
-        except Exception, e:
-            tb = traceback.format_exc()
-            warning(i, 'Caught exception, traceback follows:\n%s' % (tb,))
-        else:
-            content.append((c, handler))
-            extras.extend(e)
-
-    os.chdir(old)
-    return content, extras
-
-# thing for reading the presentation format
-class Presentation(object):
-    def __init__(self, filename, theme):
-        self.theme = theme
-        self.content, self.extras = read_presentation(filename)
-
-    def render_pdf(self):
-        source, extras = self.theme.render(self.content)
-        extras.extend(self.extras)
-        return render_pdf(source, extras)
-

shinypress/lyrics/__init__.py

-import codecs
+from .parser import parse_lyrics
+from .. import mime_utils
 
-from shinypress.jinja import get_template
-from .parser import parse_lyrics
+class LyricsConverter(object):
+    input_mimetypes = [
+        'text/plain',
+    ]
 
-template = get_template('handlers/lyrics/template.tex')
+    output_mimetypes = [
+        'text/html',
+        'text/x-tex',
+    ]
 
-def render(filename):
-    source = codecs.open(filename, 'rU', encoding='utf-8')
-    info, verses = parse_lyrics(source)
-    return (template.render(info=info, verses=verses), [])
+    def save(self, file, mime):
+        assert mime_utils.any_matches(mime, self.output_mimetypes)
 
+    @classmethod
+    def from_file(cls, file, mime):
+        assert mime_utils.any_matches(mime, cls.input_mimetypes)
+
+        info, verses = parse_lyrics(file)

shinypress/lyrics/parser.py

-from shinypress.utils import group_paragraphs
+from ..utils import group_paragraphs
 
 class LyricsFormatError(ValueError):
     pass

shinypress/mime_utils.py

+from itertools import izip as zip
+import re
+
+def matches(mime, exp):
+    """
+    Check if the given MIME type mime matches the MIME type expression exp.
+
+    If the two MIME types are exactly equal, this will return True:
+    >>> mime_matches('text/plain', 'text/plain')
+    True
+
+    This also supports wildcard matches, but not across multiple components
+    >>> mime_matches('text/plain', 'text/*')
+    True
+    >>> mime_matches('text/plain/quack', 'text/*')
+    False
+
+    It also works fine with prefixes and suffixes on the wildcard:
+    >>> mime_matches('text/x-tex', 'text/x*ex')
+    True
+    >>> mime_matches('text/x-tex', 'text/a*b')
+    False
+    """
+    # TODO: read the MIME type spec (is it a RFC?), to find out if this is sane.
+    if mime == exp:
+        return True
+
+    all_matched = True
+
+    mime_components = mime.split('/')
+    exp_components = exp.split('/')
+
+    if len(mime_components) != len(exp_components):
+        return False
+
+    for left, right in zip(mime_components, exp_components):
+        regex = '.*'.join(re.escape(x) for x in right.split('*'))
+        if not re.match(regex, left):
+            all_matched = False
+            break
+
+    return all_matched
+
+def any_matches(mime, exps):
+    return any(
+        matches(mime, exp)
+        for exp in exps
+    )
+
+def get_preferred(mime, preferred):
+    """
+    Find the first mime type expression in preferred which matches the given
+    mime type. If no mime type matches, return None.
+
+    >>> get_preferred_mime_type('text/plain', ['text/plain', 'text/*'])
+    'text/plain'
+    >>> get_preferred_mime_type('text/plain', ['text/*', 'text/plain'])
+    'text/*'
+    >>> get_preferred_mime_type('image/jpeg', ['text/plain', 'image/*', '*/*'])
+    'image/*'
+    >>> get_preferred_mime_type('image/jpeg', ['*/*', 'image/jpeg', 'image/*'])
+    '*/*'
+    >>> get_preferred_mime_type('image/jpeg', ['image/png', 'text/*'])
+    """
+    for target in preferred:
+        if matches(mime, target):
+            return target
+