Skip to content

Commit

Permalink
unknown node behavior now based on callable
Browse files Browse the repository at this point in the history
instead of setting the mode via a passed constant, just pass in a callable
which can handle the unknown nodes. currently this callable is an unbound
method which nevertheless expects a copy of "self" which is the
Html2CreoleEmitter, so that the child nodes can still be emitted recursively.
  • Loading branch information
Eric O'Connell committed May 24, 2011
1 parent cf26485 commit a1008c2
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 101 deletions.
137 changes: 63 additions & 74 deletions creole/html2creole.py
Expand Up @@ -552,99 +552,84 @@ def replace_entity(match):
return entities_regex.sub(replace_entity, content)



#------------------------------------------------------------------------------

RAISE_UNKNOWN_NODES = 1
HTML_MACRO_UNKNOWN_NODES = 2
ESCAPE_UNKNOWN_NODES = 3
TRANSPARENT_UNKNOWN_NODES = 4

def raise_unknown_node(self, node):
"""
Raise NotImplementedError on unknown tags.
"""
raise NotImplementedError(
"Node from type '%s' is not implemented!" % node.kind
)

class Html2CreoleEmitter(object):
def use_html_macro(self, node):
"""
Use the <<html>> macro to mask unknown tags.
"""
#node.debug()
attrs = node.get_attrs_as_string()
if attrs:
attrs = " " + attrs

def __init__(self, document_tree, unknown_emit=ESCAPE_UNKNOWN_NODES,
debug=False):
self.root = document_tree
tag_data = {
"tag": node.kind,
"attrs": attrs,
}

if unknown_emit == RAISE_UNKNOWN_NODES:
self.unknown_emit = self.raise_unknown_node
elif unknown_emit == HTML_MACRO_UNKNOWN_NODES:
self.unknown_emit = self.use_html_macro
elif unknown_emit == ESCAPE_UNKNOWN_NODES:
self.unknown_emit = self.escape_unknown_nodes
elif unknown_emit == TRANSPARENT_UNKNOWN_NODES:
self.unknown_emit = self.transparent_unknown_nodes
else:
raise AssertionError("wrong keyword argument 'unknown_emit'!")
content = self.emit_children(node)
if not content:
# single tag
return u"<<html>><%(tag)s%(attrs)s /><</html>>" % tag_data

self.last = None
self.debugging = debug
start_tag = u"<<html>><%(tag)s%(attrs)s><</html>>" % tag_data
end_tag = u"<<html>></%(tag)s><</html>>" % tag_data

self.deentity = Deentity() # for replacing html entities
self.__inner_list = ""
self.__mask_linebreak = False
return start_tag + content + end_tag

#--------------------------------------------------------------------------
def escape_unknown_nodes(self, node):
"""
All unknown tags should be escaped.
"""
#node.debug()
attrs = node.get_attrs_as_string()
if attrs:
attrs = " " + attrs

def raise_unknown_node(self, node):
"""
Raise NotImplementedError on unknown tags.
"""
raise NotImplementedError(
"Node from type '%s' is not implemented!" % node.kind
)
tag_data = {
"tag": node.kind,
"attrs": attrs,
}

def use_html_macro(self, node):
"""
Use the <<html>> macro to mask unknown tags.
"""
#node.debug()
attrs = node.get_attrs_as_string()
if attrs:
attrs = " " + attrs
content = self.emit_children(node)
if not content:
# single tag
return escape(u"<%(tag)s%(attrs)s />" % tag_data)

tag_data = {
"tag": node.kind,
"attrs": attrs,
}
start_tag = escape(u"<%(tag)s%(attrs)s>" % tag_data)
end_tag = escape(u"</%(tag)s>" % tag_data)

content = self.emit_children(node)
if not content:
# single tag
return u"<<html>><%(tag)s%(attrs)s /><</html>>" % tag_data
return start_tag + content + end_tag

start_tag = u"<<html>><%(tag)s%(attrs)s><</html>>" % tag_data
end_tag = u"<<html>></%(tag)s><</html>>" % tag_data
def transparent_unknown_nodes(self, node):
return self._emit_content(node)

return start_tag + content + end_tag

def escape_unknown_nodes(self, node):
"""
All unknown tags should be escaped.
"""
#node.debug()
attrs = node.get_attrs_as_string()
if attrs:
attrs = " " + attrs

tag_data = {
"tag": node.kind,
"attrs": attrs,
}
class Html2CreoleEmitter(object):

content = self.emit_children(node)
if not content:
# single tag
return escape(u"<%(tag)s%(attrs)s />" % tag_data)
def __init__(self, document_tree, unknown_emit=raise_unknown_node,
debug=False):
self.root = document_tree

start_tag = escape(u"<%(tag)s%(attrs)s>" % tag_data)
end_tag = escape(u"</%(tag)s>" % tag_data)
self._unknown_emit = unknown_emit

return start_tag + content + end_tag
self.last = None
self.debugging = debug

def transparent_unknown_nodes(self, node):
return self._emit_content(node)
self.deentity = Deentity() # for replacing html entities
self.__inner_list = ""
self.__mask_linebreak = False

#--------------------------------------------------------------------------

Expand Down Expand Up @@ -877,9 +862,13 @@ def emit_node(self, node):
self.debug_msg("emit_node", "%s: %r" % (node.kind, node.content))

method_name = "%s_emit" % node.kind
emit_method = getattr(self, method_name, self.unknown_emit)
emit_method = getattr(self, method_name, None)

content = emit_method(node)
if emit_method:
content = emit_method(node)
else:
content = self._unknown_emit(self, node)

if not isinstance(content, unicode):
raise AssertionError(
"Method '%s' returns no unicode (returns: %r)" % (
Expand Down
58 changes: 33 additions & 25 deletions tests/test_html2creole.py
Expand Up @@ -20,8 +20,8 @@
from tests.utils.base_unittest import BaseCreoleTest

from creole import html2creole
from creole.html2creole import RAISE_UNKNOWN_NODES, HTML_MACRO_UNKNOWN_NODES, \
ESCAPE_UNKNOWN_NODES, TRANSPARENT_UNKNOWN_NODES
from creole.html2creole import raise_unknown_node, use_html_macro, \
escape_unknown_nodes, transparent_unknown_nodes


class TestHtml2Creole(unittest.TestCase):
Expand Down Expand Up @@ -58,18 +58,18 @@ def test_not_used(self):

def test_raise_unknown_node(self):
"""
Test creole.html2creole.RAISE_UNKNOWN_NODES mode:
Test creole.html2creole.raise_unknown_node callable:
Raise NotImplementedError on unknown tags.
"""
self.assertRaises(NotImplementedError,
html2creole,
html_string=u"<unknwon>",
unknown_emit=RAISE_UNKNOWN_NODES
unknown_emit=raise_unknown_node
)

def test_escape_unknown_nodes(self):
"""
Test creole.html2creole.ESCAPE_UNKNOWN_NODES mode:
Test creole.html2creole.escape_unknown_nodes callable:
All unknown tags should be escaped.
"""
self.assertCreole(r"""
Expand All @@ -83,8 +83,35 @@ def test_escape_unknown_nodes(self):
<p>555<unknown />666</p>
""",
unknown_emit=ESCAPE_UNKNOWN_NODES
unknown_emit=escape_unknown_nodes
)

def test_transparent_unknown_nodes(self):
"""
Test creole.html2creole.transparent_unknown_nodes callable:
All unknown tags should be "transparent" and show only
their child nodes' content.
"""
self.assertCreole(r"""
//baz//, **quux**
""", """
<form class="foo" id="bar"><label><em>baz</em></label>, <strong>quux</strong></form>
""", unknown_emit = transparent_unknown_nodes)

def test_transparent_unknown_nodes_block_elements(self):
"""
Test that block elements insert linefeeds into the stream.
"""
self.assertCreole(r"""
//baz//,
**quux**
spam, ham, and eggs
""", """
<div><em>baz</em>,</div> <fieldset><strong>quux</strong></fieldset>
<span>spam, </span><label>ham, </label>and eggs
""", unknown_emit = transparent_unknown_nodes)

def test_entities(self):
"""
Expand Down Expand Up @@ -237,25 +264,6 @@ def test_empty_tags_are_not_escaped(self):
<div class="foo" id="bar"><span><em>baz</em></span>, <strong>quux</strong></div>
""")

def test_transparent_unknown_nodes(self):
self.assertCreole(r"""
//baz//, **quux**
""", """
<form class="foo" id="bar"><label><em>baz</em></label>, <strong>quux</strong></form>
""", unknown_emit = TRANSPARENT_UNKNOWN_NODES)

def test_linefeeds_after_block_elements(self):
self.assertCreole(r"""
//baz//,
**quux**
spam, ham, and eggs
""", """
<div><em>baz</em>,</div> <fieldset><strong>quux</strong></fieldset>
<span>spam, </span><label>ham, </label>and eggs
""", unknown_emit = TRANSPARENT_UNKNOWN_NODES)

#--------------------------------------------------------------------------
# TODOs:

Expand Down
4 changes: 2 additions & 2 deletions tests/utils/base_unittest.py
Expand Up @@ -18,7 +18,7 @@
from utils import MarkupTest

from creole import creole2html, html2creole
from creole.html2creole import HTML_MACRO_UNKNOWN_NODES
from creole.html2creole import use_html_macro


class BaseCreoleTest(MarkupTest):
Expand Down Expand Up @@ -107,6 +107,6 @@ def assertCreole(self, source_string, should_string, debug=False):
self.assert_Creole2html(source_string, should_string, debug)
self.assert_html2Creole(
source_string, should_string, debug,
unknown_emit=HTML_MACRO_UNKNOWN_NODES
unknown_emit=use_html_macro
)

0 comments on commit a1008c2

Please sign in to comment.