Completed
Push — master ( d0bff5...613540 )
by P.R.
02:06
created

HeadingNode   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 176
Duplicated Lines 0 %

Test Coverage

Coverage 84.29%

Importance

Changes 4
Bugs 1 Features 0
Metric Value
wmc 26
dl 0
loc 176
ccs 59
cts 70
cp 0.8429
rs 10
c 4
b 1
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A get_hierarchy_name() 0 7 1
A is_block_command() 0 7 1
A __init__() 0 17 1
A is_inline_command() 0 7 1
A set_toc_id() 0 11 3
A number() 0 19 3
A split_text_nodes() 0 20 4
A set_numbering() 0 12 4
A prepare_content_tree() 0 13 1
C create_paragraphs() 0 39 7
1
"""
2
SDoc
3
4
Copyright 2016 Set Based IT Consultancy
5
6
Licence MIT
7
"""
8
# ----------------------------------------------------------------------------------------------------------------------
9 1
import sdoc
10 1
from sdoc.sdoc2 import in_scope, out_scope
11 1
from sdoc.sdoc2.NodeStore import NodeStore
12 1
from sdoc.sdoc2.helper.Enumerable import Enumerable
13 1
from sdoc.sdoc2.node.EndParagraphNode import EndParagraphNode
14 1
from sdoc.sdoc2.node.Node import Node
15 1
from sdoc.sdoc2.node.TextNode import TextNode
16
17
18 1
class HeadingNode(Node):
0 ignored issues
show
Bug introduced by
The method get_command which was declared abstract in the super-class Node
was not overridden.

Methods which raise NotImplementedError should be overridden in concrete child classes.

Loading history...
19
    """
20
    Abstract class for heading nodes.
21
    """
22
23
    # ------------------------------------------------------------------------------------------------------------------
24 1
    def __init__(self, io, name, options, argument):
25
        """
26
        Object constructor.
27
28
        :param None|cleo.styles.output_style.OutputStyle io: The IO object.
29
        :param str name: The (command) name of this heading.
30
        :param dict[str,str] options: The options of this heading.
31
        :param str argument: The title of this heading.
32
        """
33 1
        super().__init__(io, name, options, argument)
34
35 1
        self.numbering = True
36 1
        """
37
        The True the node must be numbered.
38
39
        :type: bool
40
        """
41
42
    # ------------------------------------------------------------------------------------------------------------------
43 1
    def get_hierarchy_name(self):
44
        """
45
        Returns 'sectioning'.
46
47
        :rtype: str
48
        """
49 1
        return 'sectioning'
50
51
    # ------------------------------------------------------------------------------------------------------------------
52 1
    def is_block_command(self):
53
        """
54
        Returns False.
55
56
        :rtype: bool
57
        """
58 1
        return False
59
60
    # ------------------------------------------------------------------------------------------------------------------
61 1
    def is_inline_command(self):
62
        """
63
        Returns True.
64
65
        :rtype: bool
66
        """
67
        return True
68
69
    # ------------------------------------------------------------------------------------------------------------------
70 1
    def number(self, enumerable_numbers):
71
        """
72
        Sets number of heading nodes.
73
74
        :param dict[str,sdoc.sdoc2.helper.Enumerable.Enumerable] enumerable_numbers:
75
        """
76 1
        if 'heading' not in enumerable_numbers:
77 1
            enumerable_numbers['heading'] = Enumerable()
78
79 1
        enumerable_numbers['heading'].generate_numeration(self.get_hierarchy_level())
80 1
        enumerable_numbers['heading'].increment_last_level()
81 1
        enumerable_numbers['heading'].remove_starting_zeros()
82
83 1
        if 'part' in enumerable_numbers:
84
            self._options['part_number'] = enumerable_numbers['part'].get_string()
85
86 1
        self._options['number'] = enumerable_numbers['heading'].get_string()
87
88 1
        super().number(enumerable_numbers)
89
90
    # ------------------------------------------------------------------------------------------------------------------
91 1
    def set_toc_id(self):
92
        """
93
        Set ID for table of contents.
94
        """
95
        if 'id' not in self._options:
96
            if 'part_number' in self._options:
97
                self._options['id'] = '{}:{}:{}'.format(self.name,
98
                                                        self._options['part_number'],
99
                                                        self._options['number'])
100
            else:
101
                self._options['id'] = '{}:{}'.format(self.name, self._options['number'])
102
103
    # ------------------------------------------------------------------------------------------------------------------
104 1
    def prepare_content_tree(self):
105
        """
106
        Prepares the content tree. Create paragraph nodes.
107
        """
108 1
        super().prepare_content_tree()
109
110 1
        self.set_numbering()
111
112
        # Adding the id's of splitted text in 'new_child_nodes1' list.
113 1
        self.split_text_nodes()
114
115
        # Creating paragraphs and add all id's in 'new_child_nodes2' list.
116 1
        self.create_paragraphs()
117
118
    # ------------------------------------------------------------------------------------------------------------------
119 1
    def set_numbering(self):
120
        """
121
        Sets the numbering status to the heading node.
122
        """
123 1
        if 'numbering' in self._options:
124
            if self._options['numbering'] == 'off':
125
                self.numbering = False
126
            elif self._options['numbering'] == 'on':
127
                self.numbering = True
128
            else:
129
                NodeStore.error("Invalid value '{}' for attribute 'numbering'. Allowed values are 'on' and 'off'.".
130
                                format(self._options['numbering']), self)
131
132
    # ------------------------------------------------------------------------------------------------------------------
133 1
    def split_text_nodes(self):
134
        """
135
        Replaces single text nodes that contains a paragraph separator (i.e. a double new line) with multiple text nodes
136
        without paragraph separator.
137
        """
138 1
        new_child_nodes = []
139
140 1
        for node_id in self.child_nodes:
141 1
            node = in_scope(node_id)
142
143 1
            if isinstance(node, TextNode):
144 1
                list_ids = node.split_by_paragraph()
145 1
                for ids in list_ids:
146 1
                    new_child_nodes.append(ids)
147
            else:
148 1
                new_child_nodes.append(node.id)
149
150 1
            out_scope(node)
151
152 1
        self.child_nodes = new_child_nodes
153
154
    # ------------------------------------------------------------------------------------------------------------------
155 1
    def create_paragraphs(self):
156
        """
157
        Create paragraph nodes.
158
159
        A paragraph consists of phrasing nodes only. Each continuous slice of phrasing child nodes is move to a
160
        paragraph node.
161
        """
162 1
        new_child_nodes = []
163 1
        paragraph_node = None
164
165 1
        for node_id in self.child_nodes:
166 1
            node = in_scope(node_id)
167
168 1
            if node.is_phrasing():
169 1
                if not paragraph_node:
170 1
                    paragraph_node = sdoc.sdoc2.node_store.create_inline_node('paragraph')
171 1
                    new_child_nodes.append(paragraph_node.id)
172
173 1
                paragraph_node.append_child_node(node)
174
            else:
175 1
                if paragraph_node:
176 1
                    paragraph_node.prune_whitespace()
177 1
                    sdoc.sdoc2.node_store.store_node(paragraph_node)
178 1
                    paragraph_node = None
179
180
                # End paragraph nodes are created temporary to separate paragraphs in a flat list of (text) node. There
181
                # role ae replaced by the content hierarchy now. So, we must no store end paragraph nodes.
182 1
                if not isinstance(node, EndParagraphNode):
183 1
                    new_child_nodes.append(node.id)
184
185 1
            out_scope(node)
186
187 1
        if paragraph_node:
188 1
            paragraph_node.prune_whitespace()
189 1
            sdoc.sdoc2.node_store.store_node(paragraph_node)
190
            # paragraph_node = None
191
192
        # Setting child nodes.
193 1
        self.child_nodes = new_child_nodes
194
195
# ----------------------------------------------------------------------------------------------------------------------
196