Skip to content

Instantly share code, notes, and snippets.

@thisismedium
Created September 19, 2010 00:00
Show Gist options
  • Select an option

  • Save thisismedium/586192 to your computer and use it in GitHub Desktop.

Select an option

Save thisismedium/586192 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
"""# mud.py #
Mustache, Markdown, and YAML templates.
## Installation ##
Mud requires `python >= 2.5` and depends on the `yaml`, `pystache`,
and `markdown` packages.
## Using Mud ##
./mud layout.mustache page.md
where `layout.mustache` is a mustache template with a `{{{ body }}}`
like this:
<!DOCTYPE html>
<html>
<head>{{ title }}</head>
<body>
<h1>{{ title }}</h1>
<p class="abstract">{{{ abstract }}}</p>
{{{ body }}}
</body>
</html>
and `page.md` is a markdown document optionally ended with
a triple-hyphen followed by YAML data like this:
# Title Here #
Abstract paragraph...
More markdown with {{ mustache }}...
---
foo: yaml data
...
## Rendering Process ##
The YAML data is used as a template context when rendering a mud
document. Rendering happens in this way:
1. Read in the mud document and context.
2. Expand the document with mustache.
3. Render as markdown.
4. Extend the context with:
- `title` - content of the H1
- `abstract` - content of the first P
- `body` - remaining document
5. Using this context, render the layout.mustache template.
"""
from __future__ import with_statement
import sys, re, contextlib
import yaml, markdown as md, pystache
import xml.etree.ElementTree as ET
def mud(filename):
with contextlib.closing(open(filename)) as port:
text, context = read(port)
return bind(markstache(text, context), context)
def read(port):
parts = port.read().split('\n---\n')
if len(parts) == 1:
return (parts[0], {})
else:
return (parts[0], yaml.load(parts[1]))
def markstache(template, context):
return md.Markdown().convert(pystache.render(template, context))
def bind(body, context):
doc = ET.fromstring('<html>%s</html>' % body)
top = list(doc)
take(top, context, 'h1', 'title')
take(top, context, 'p', 'abstract')
context['body'] = ''.join(ET.tostring(e, 'utf-8') for e in top)
return context
def take(elems, context, tag, name):
if not elems or elems[0].tag != tag:
raise RuntimeError('Expected %s' % tag)
context[name] = elems.pop(0).text
return context
def page(layout, article):
with contextlib.closing(open(layout)) as port:
return pystache.render(port.read(), mud(article))
## Main ##
def main(layout, article):
print page(layout, article)
if __name__ == '__main__':
main(*sys.argv[1:])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment