Completed
Push — master ( 57e7bf...8a74a7 )
by P.R.
01:36
created

TableNode   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 169
Duplicated Lines 0 %
Metric Value
wmc 23
dl 0
loc 169
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A has_header() 0 21 4
A prepare_content_tree() 0 12 2
A is_block_command() 0 7 1
A prune_whitespace() 0 15 2
B extract_table() 0 28 5
A is_inline_command() 0 7 1
B __init__() 0 28 1
B get_column_alignments() 0 22 6
A get_command() 0 7 1
1
"""
2
SDoc
3
4
Copyright 2016 Set Based IT Consultancy
5
6
Licence MIT
7
"""
8
# ----------------------------------------------------------------------------------------------------------------------
9
import re
10
import csv
11
import io
12
from sdoc.sdoc2 import node_store, in_scope, out_scope
13
from sdoc.sdoc2.node.Node import Node
14
15
16
class TableNode(Node):
17
    """
18
    SDoc2 node for table.
19
    """
20
21
    # ------------------------------------------------------------------------------------------------------------------
22
    def __init__(self, options):
23
        """
24
        Object constructor.
25
26
        :param dict[str,str] options: The options of this table.
27
        """
28
        super().__init__('table', options)
29
30
        self.rows = []
31
        """
32
        The table rows.
33
34
        :type: list[list[str]]
35
        """
36
37
        self.column_headers = []
38
        """
39
        The column headers of the table (if any).
40
41
        :type: list[str]
42
        """
43
44
        self.alignments = []
45
        """
46
        The text alignments in the table columns.
47
48
        :type: list[str|None]
49
        """
50
51
    # ------------------------------------------------------------------------------------------------------------------
52
    def get_command(self):
53
        """
54
        Returns the command of this node, i.e. table.
55
56
        :rtype: str
57
        """
58
        return 'table'
59
60
    # ------------------------------------------------------------------------------------------------------------------
61
    def is_block_command(self):
62
        """
63
        Returns True.
64
65
        :rtype: bool
66
        """
67
        return True
68
69
    # ------------------------------------------------------------------------------------------------------------------
70
    def is_inline_command(self):
71
        """
72
        Returns False.
73
74
        :rtype: bool
75
        """
76
        return False
77
78
    # ------------------------------------------------------------------------------------------------------------------
79
    def prepare_content_tree(self):
80
        """
81
        Prepares this node for further processing.
82
        """
83
        for node_id in self.child_nodes:
84
            node = in_scope(node_id)
85
86
            self.extract_table(node)
87
88
            node.prepare_content_tree()
89
90
            out_scope(node)
91
92
    # ------------------------------------------------------------------------------------------------------------------
93
    def extract_table(self, node):
94
        """
95
        Extract the table data from a TextNode.
96
97
        :param sdoc.sdoc2.node.Node.Node node: The node which may be interpreted as table.
98
        """
99
        temp_table_items = node.argument.split('\n')
100
101
        # Remove empty rows.
102
        while '' in temp_table_items:
103
            temp_table_items.remove('')
104
105
        # Derive table data.
106
        rows = []
107
        for item in temp_table_items:
108
            string = io.StringIO(item)
109
            reader = csv.reader(string, delimiter='|')
110
            for line in reader:
111
                row = line
112
                row = self.prune_whitespace(row)
113
                rows.append(row)
114
115
        if self.has_header(rows):
116
            self.column_headers = rows[0]
117
            self.rows = rows[2:]
118
            self.alignments = self.get_column_alignments(rows[1])
119
        else:
120
            self.rows = rows
121
122
    # ------------------------------------------------------------------------------------------------------------------
123
    @staticmethod
124
    def has_header(row):
125
        """
126
        Returns True if the table has a table header.
127
128
        :param list[str] row: The second row of the table.
129
130
        :rtype: bool
131
        """
132
        is_header = True
133
134
        if len(row) == 1:
135
            return False
136
137
        for align in row[1]:
138
            header_part = re.findall(':?---+-*:?', align)
139
            if not header_part:
140
                is_header = False
141
                break
142
143
        return is_header
144
145
    # ------------------------------------------------------------------------------------------------------------------
146
    @staticmethod
147
    def get_column_alignments(row):
148
        """
149
        Sets alignments on table columns.
150
151
        :param list[str] row: The row with hyphens for creating column headers.
152
153
        :rtype: list[str]
154
        """
155
        alignments = []
156
        for hyphens in row:
157
            hyphens = hyphens.strip()
158
            if hyphens.startswith(':') and hyphens.endswith(':'):
159
                alignments.append('center')
160
            elif hyphens.startswith(':'):
161
                alignments.append('left')
162
            elif hyphens.endswith(':'):
163
                alignments.append('right')
164
            else:
165
                alignments.append('')
166
167
        return alignments
168
169
    # ------------------------------------------------------------------------------------------------------------------
170
    @staticmethod
171
    def prune_whitespace(row):
172
        """
173
        Strips whitespaces from the text of an each cell.
174
175
        :param list[str] row: The row with text of an each cell.
176
        :rtype: list[str]
177
        """
178
        clear_row = []
179
        for item in row:
180
            clear_text = item.strip()
181
            clear_text = re.sub(r'\s+', ' ', clear_text)
182
            clear_row.append(clear_text)
183
184
        return clear_row
185
186
# ----------------------------------------------------------------------------------------------------------------------
187
node_store.register_block_command('table', TableNode)
188