Created
September 19, 2010 00:00
-
-
Save thisismedium/586192 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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