Mercurial > wikicreole
changeset 23:2347b60b96ea
added Genshi emitter
| author | Radomir Dopieralski <creole@sheep.art.pl> |
|---|---|
| date | Tue, 01 Jun 2010 23:10:59 +0200 |
| parents | 173702c38d36 |
| children | 1420e292597d |
| files | creole/__init__.py creole/genshi_emitter.py examples/creole2html.py tests/test_genshi_emitter.py |
| diffstat | 4 files changed, 308 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/creole/__init__.py Tue Jun 01 22:12:46 2010 +0200 +++ b/creole/__init__.py Tue Jun 01 23:10:59 2010 +0200 @@ -28,5 +28,4 @@ from creole.rules import Rules from creole.parser import Parser from creole.document import DocNode -from creole.html_emitter import HtmlEmitter
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/creole/genshi_emitter.py Tue Jun 01 23:10:59 2010 +0200 @@ -0,0 +1,293 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +ur""" +Test cases contributed by Jan Klopper (janklopper@underdark.nl), +modified by Radomir Dopieralski (MoinMoin:RadomirDopieralski). + +>>> import lxml.html.usedoctest +>>> import creole +>>> def parse(text): +... text = GenshiEmitter(creole.Parser(text).parse()).emit().render() +... print unicode(text, 'utf-8') +>>> def wiki_parse(text): +... rules = creole.Rules(wiki_words=True) +... print GenshiEmitter(creole.Parser(text, rules).parse()).emit().render() + +>>> parse(u'test') +<p>test</p> + +>>> parse(u'test\ntest') +<p>test test</p> + +>>> parse(u'test\n\ntest') +<p>test</p><p>test</p> + +>>> parse(u'test\\\\test') +<p>test<br>test</p> + +>>> parse(u'ÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïñòóôõöøùúûüýÿŒœ%0A') +<p>ÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïñòóôõöøùúûüýÿŒœ%0A</p> + +>>> parse(u'----') +<hr> + +>>> parse(u'==test==') +<h2>test</h2> + +>>> parse(u'== test') +<h2>test</h2> + +>>> parse(u'==test====') +<h2>test</h2> + +>>> parse(u'=====test') +<h5>test</h5> + +>>> parse(u'==test==\ntest\n===test===') +<h2>test</h2> +<p>test</p> +<h3>test</h3> + +>>> parse(u'test\n* test line one\n * test line two\ntest\n\ntest') +<p>test</p> +<ul> + <li>test line one</li> + <li>test line two test</li> +</ul> +<p>test</p> + +>>> parse(u'* test line one\n* test line two\n** Nested item') +<ul> + <li>test line one</li> + <li>test line two<ul> + <li>Nested item</li> + </ul></li> +</ul> + +>>> parse(u'* test line one\n* test line two\n# Nested item') +<ul> + <li>test line one</li> + <li>test line two<ol> + <li>Nested item</li> + </ol></li> +</ul> + +>>> parse(u'test //test test// test **test test** test') +<p>test <i>test test</i> test <b>test test</b> test</p> + +>>> parse(u'test //test **test// test** test') +<p>test <i>test <b>test<i> test<b> test</b></i></b></i></p> + +>>> parse(u'**test') +<p><b>test</b></p> + +>>> parse(u'|x|y|z|\n|a|b|c|\n|d|e|f|\ntest') +<table> + <tr><td>x</td><td>y</td><td>z</td></tr> + <tr><td>a</td><td>b</td><td>c</td></tr> + <tr><td>d</td><td>e</td><td>f</td></tr> +</table> +<p>test</p> + +>>> parse(u'|=x|y|=z=|\n|a|b|c|\n|d|e|f|') +<table> + <tr><th>x</th><td>y</td><th>z</th></tr> + <tr><td>a</td><td>b</td><td>c</td></tr> + <tr><td>d</td><td>e</td><td>f</td></tr> +</table> + +>>> parse(u'test http://example.com/test test') +<p>test <a href="http://example.com/test" class="external">http://example.com/test</a> test</p> + +>>> parse(u'http://example.com/,test, test') +<p><a href="http://example.com/,test" class="external">http://example.com/,test</a>, test</p> + +>>> parse(u'(http://example.com/test)') +<p>(<a href="http://example.com/test" class="external">http://example.com/test</a>)</p> + +XXX This might be considered a bug, but it's impossible to detect in general. +>>> parse(u'http://example.com/(test)') +<p><a href="http://example.com/(test" class="external">http://example.com/(test</a>)</p> + +>>> parse(u'http://example.com/test?test&test=1') +<p><a href="http://example.com/test?test&test=1" class="external">http://example.com/test?test&test=1</a></p> + +>>> parse(u'~http://example.com/test') +<p>http://example.com/test</p> + +>>> parse(u'http://example.com/~test') +<p><a href="http://example.com/~test" class="external">http://example.com/~test</a></p> + +>>> parse(u'[[test]] [[tset|test]]') +<p><a href="test" class="internal">test</a> <a href="tset" class="internal">test</a></p> + +>>> parse(u'[[http://example.com|test]]') +<p><a href="http://example.com" class="external">test</a></p> + +>>> wiki_parse(u'Lorem WikiWord iPsum sit ameT.') +<p>Lorem <a href="WikiWord" class="internal">WikiWord</a> iPsum sit ameT.</p> + +""" + + +import re + +from creole.parser import Parser +from creole.rules import LinkRules + +from genshi import Stream, QName, Attrs + +START, END, TEXT = Stream.START, Stream.END, Stream.TEXT + +POS = (None, None, None) + +class GenshiEmitter(object): + """ + Generate Genshi stream output for the document + tree consisting of DocNodes. + """ + + def __init__(self, root, link_rules=None): + self.root = root + self.link_rules = link_rules or LinkRules() + + def get_text(self, node): + """Try to emit whatever text is in the node.""" + + try: + return node.children[0].content or '' + except: + return node.content or '' + + def wrap(self, tag, node): + yield START, (QName(tag), Attrs()), POS + for part in self.emit_children(node): + yield part + yield END, QName(tag), POS + + # *_emit methods for emitting nodes of the document: + + def document_emit(self, node): + return self.emit_children(node) + + def text_emit(self, node): + yield TEXT, node.content, POS + + def separator_emit(self, node): + yield START, (QName('hr'), Attrs()), POS + yield END, QName('hr'), POS + + def paragraph_emit(self, node): + return self.wrap('p', node) + + def bullet_list_emit(self, node): + return self.wrap('ul', node) + + def number_list_emit(self, node): + return self.wrap('ol', node) + + def list_item_emit(self, node): + return self.wrap('li', node) + + def table_emit(self, node): + return self.wrap('table', node) + + def table_row_emit(self, node): + return self.wrap('tr', node) + + def table_cell_emit(self, node): + return self.wrap('td', node) + + def table_head_emit(self, node): + return self.wrap('th', node) + + def emphasis_emit(self, node): + return self.wrap('i', node) + + def strong_emit(self, node): + return self.wrap('b', node) + + def header_emit(self, node): + yield START, (QName('h%d' % node.level), Attrs()), POS + yield TEXT, node.content, POS + yield END, QName('h%d' % node.level), POS + + def code_emit(self, node): + return self.wrap('tt', node) + + def link_emit(self, node): + target = node.content + class_ = "internal" + m = self.link_rules.addr_re.match(target) + if m: + if m.group('extern_addr'): + class_ = "external" + elif m.group('inter_wiki'): + raise NotImplementedError + yield START, (QName('a'), + Attrs([ + (QName('href'), target), + (QName('class'), class_), + ])), POS + if node.children: + for part in self.emit_children(node): + yield part + else: + yield TEXT, target, POS + yield END, QName('a'), POS + + def image_emit(self, node): + target = node.content + text = self.get_text(node) + class_ = "internal" + m = self.link_rules.addr_re.match(target) + if m: + if m.group('extern_addr'): + class_ = "external" + elif m.group('inter_wiki'): + raise NotImplementedError + yield START, (QName('img'), + Attrs([ + (QName('src'), target), + (QName('alt'), text), + (QName('class'), class_), + ])), POS + yield END, QName('img'), POS + + def macro_emit(self, node): + raise NotImplementedError + + def break_emit(self, node): + yield START, (QName('br'), Attrs()), POS + yield END, QName('br'), POS + + def preformatted_emit(self, node): + yield START, (QName('pre'), Attrs()), POS + yield TEXT, node.content, POS + yield END, QName('pre'), POS + + def default_emit(self, node): + """Fallback function for emitting unknown nodes.""" + + raise TypeError('Unknown node type') + + def emit_children(self, node): + """Emit all the children of a node.""" + + for child in node.children: + for part in self.emit_node(child): + yield part + + def emit_node(self, node): + """Emit a single node.""" + + emit = getattr(self, '%s_emit' % node.kind, self.default_emit) + return emit(node) + + def emit(self): + """Emit the document represented by self.root DOM tree.""" + + return Stream(self.emit_node(self.root)) + +
--- a/examples/creole2html.py Tue Jun 01 22:12:46 2010 +0200 +++ b/examples/creole2html.py Tue Jun 01 23:10:59 2010 +0200 @@ -3,7 +3,8 @@ import sys -from creole import Parser, HtmlEmitter +from creole import Parser +from creole.html_emitter import HtmlEmitter if __name__=="__main__": document = Parser(unicode(sys.stdin.read(), 'utf-8', 'ignore')).parse()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_genshi_emitter.py Tue Jun 01 23:10:59 2010 +0200 @@ -0,0 +1,13 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import os +import sys +import doctest + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) + +import creole.genshi_emitter + +if __name__ == "__main__": + doctest.testmod(creole.genshi_emitter)
