Completed
Push — master ( 32cfa8...ec62d3 )
by Dongxin
48s
created

RawHtmlPostprocessor.run()   F

Complexity

Conditions 12

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
c 1
b 0
f 0
dl 0
loc 24
rs 2.8641

How to fix   Complexity   

Complexity

Complex classes like RawHtmlPostprocessor.run() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""
2
POST-PROCESSORS
3
=============================================================================
4
5
Markdown also allows post-processors, which are similar to preprocessors in
6
that they need to implement a "run" method. However, they are run after core
7
processing.
8
9
"""
10
11
from __future__ import absolute_import
12
from __future__ import unicode_literals
13
from collections import OrderedDict
14
from . import util
15
from . import odict
16
import re
17
18
19
def build_postprocessors(md_instance, **kwargs):
20
    """ Build the default postprocessors for Markdown. """
21
    postprocessors = odict.OrderedDict()
22
    postprocessors["raw_html"] = RawHtmlPostprocessor(md_instance)
23
    postprocessors["amp_substitute"] = AndSubstitutePostprocessor()
24
    postprocessors["unescape"] = UnescapePostprocessor()
25
    return postprocessors
26
27
28
class Postprocessor(util.Processor):
29
    """
30
    Postprocessors are run after the ElementTree it converted back into text.
31
32
    Each Postprocessor implements a "run" method that takes a pointer to a
33
    text string, modifies it as necessary and returns a text string.
34
35
    Postprocessors must extend markdown.Postprocessor.
36
37
    """
38
39
    def run(self, text):
40
        """
41
        Subclasses of Postprocessor should implement a `run` method, which
42
        takes the html document as a single text string and returns a
43
        (possibly modified) string.
44
45
        """
46
        pass  # pragma: no cover
47
48
49
class RawHtmlPostprocessor(Postprocessor):
50
    """ Restore raw html to the document. """
51
52
    def run(self, text):
53
        """ Iterate over html stash and restore "safe" html. """
54
        replacements = OrderedDict()
55
        for i in range(self.markdown.htmlStash.html_counter):
56
            html, safe = self.markdown.htmlStash.rawHtmlBlocks[i]
57
            if self.markdown.safeMode and not safe:
58
                if str(self.markdown.safeMode).lower() == 'escape':
59
                    html = self.escape(html)
60
                elif str(self.markdown.safeMode).lower() == 'remove':
61
                    html = ''
62
                else:
63
                    html = self.markdown.html_replacement_text
64
            if (self.isblocklevel(html) and
65
               (safe or not self.markdown.safeMode)):
66
                replacements["<p>%s</p>" %
67
                             (self.markdown.htmlStash.get_placeholder(i))] = \
68
                    html + "\n"
69
            replacements[self.markdown.htmlStash.get_placeholder(i)] = html
70
71
        if replacements:
72
            pattern = re.compile("|".join(re.escape(k) for k in replacements))
73
            text = pattern.sub(lambda m: replacements[m.group(0)], text)
74
75
        return text
76
77
    def escape(self, html):
78
        """ Basic html escaping """
79
        html = html.replace('&', '&amp;')
80
        html = html.replace('<', '&lt;')
81
        html = html.replace('>', '&gt;')
82
        return html.replace('"', '&quot;')
83
84
    def isblocklevel(self, html):
85
        m = re.match(r'^\<\/?([^ >]+)', html)
86
        if m:
87
            if m.group(1)[0] in ('!', '?', '@', '%'):
88
                # Comment, php etc...
89
                return True
90
            return util.isBlockLevel(m.group(1))
91
        return False
92
93
94
class AndSubstitutePostprocessor(Postprocessor):
95
    """ Restore valid entities """
96
97
    def run(self, text):
98
        text = text.replace(util.AMP_SUBSTITUTE, "&")
99
        return text
100
101
102
class UnescapePostprocessor(Postprocessor):
103
    """ Restore escaped chars """
104
105
    RE = re.compile(r'%s(\d+)%s' % (util.STX, util.ETX))
106
107
    def unescape(self, m):
108
        return util.int2str(int(m.group(1)))
109
110
    def run(self, text):
111
        return self.RE.sub(self.unescape, text)
112