Skip to content

Commit 0d03c87

Browse files
committed
Refactoring body and footer
1 parent 1ed97d1 commit 0d03c87

File tree

2 files changed

+124
-130
lines changed

2 files changed

+124
-130
lines changed

table2ascii/__init__.py

Lines changed: 121 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import List
1+
from typing import List, Union
22
from math import floor, ceil
33

44
# constants
@@ -14,26 +14,17 @@ def __init__(self, header_row: List, body: List[List], footer_row: List):
1414
self.__header_row = header_row
1515
self.__body = body
1616
self.__footer_row = footer_row
17-
self.__cell_width = 5 # ! TODO: Remove
1817
self.__cell_widths = [5, 5, 5, 5, 5] # TODO: make this automatic
18+
1919
"""
20-
╔═════╦═══════════════════════╗
21-
║ # ║ G H R S ║
22-
╟─────╫───────────────────────╢
23-
║ 1 ║ 30 40 35 30 ║
24-
║ 2 ║ 30 40 35 30 ║
25-
╟─────╫───────────────────────╢
26-
║ SUM ║ 130 140 135 130 ║
27-
╚═════╩═══════════════════════╝
28-
29-
0111112111113111113111113111114
30-
5 6 7 7 7 5
31-
899999a99999b99999b99999b99999c
32-
5 6 7 7 7 5
33-
5 6 7 7 7 5
34-
deeeeefeeeeegeeeeegeeeeegeeeeeh
35-
5 6 7 7 7 5
36-
i11111j11111k11111k11111k11111l
20+
╔═════╦═══════════════════════╗ 0111112111113111113111113111114
21+
║ # ║ G H R S ║ 5 6 7 7 7 5
22+
╟─────╫───────────────────────╢ 899999a99999b99999b99999b99999c
23+
║ 1 ║ 30 40 35 30 ║ 5 6 7 7 7 5
24+
║ 2 ║ 30 40 35 30 ║ 5 6 7 7 7 5
25+
╟─────╫───────────────────────╢ deeeeefeeeeegeeeeegeeeeegeeeeeh
26+
║ SUM ║ 130 140 135 130 ║ 5 6 7 7 7 5
27+
╚═════╩═══════════════════════╝ i11111j11111k11111k11111k11111l
3728
"""
3829
self.parts = {
3930
"top_left_corner": "╔", # 0
@@ -60,136 +51,138 @@ def __init__(self, header_row: List, body: List[List], footer_row: List):
6051
}
6152

6253
def __pad(self, text: str, width: int, alignment: int = ALIGN_CENTER):
54+
"""Pad a string of text to a given width with specified alignment"""
6355
if alignment == ALIGN_LEFT:
6456
return f" {text} " + (" " * (width - len(text) - 2))
6557
if alignment == ALIGN_CENTER:
66-
before = " " * floor((width - len(text) - 2) / 2)
67-
after = " " * ceil((width - len(text) - 2) / 2)
58+
before = " " * ceil((width - len(text) - 2) / 2)
59+
after = " " * floor((width - len(text) - 2) / 2)
6860
return before + f" {text} " + after
6961
if alignment == ALIGN_RIGHT:
7062
return (" " * (width - len(text) - 2)) + f" {text} "
7163
raise ValueError(f"The value '{alignment}' is not valid for alignment.")
7264

65+
def __row_to_ascii(
66+
self,
67+
left: str,
68+
first_col_sep: str,
69+
col_sep: str,
70+
right: str,
71+
filler: Union[str, List],
72+
) -> str:
73+
"""Assembles a row of the ascii table"""
74+
# left edge of the row
75+
output: str = left
76+
# content across the first column
77+
output += (
78+
# edge or row separator if filler is specified
79+
filler * self.__cell_widths[0]
80+
if isinstance(filler, str)
81+
# otherwise, first column content
82+
else self.__pad(str(filler[0]), self.__cell_widths[0])
83+
)
84+
# separation of first column from the rest of the table
85+
output += first_col_sep
86+
# add remaining columns
87+
for i in range(1, len(self.__header_row)):
88+
# content between separators
89+
output += (
90+
# edge or row separator if filler is specified
91+
filler * self.__cell_widths[i]
92+
if isinstance(filler, str)
93+
# otherwise, column content
94+
else self.__pad(str(filler[i]), self.__cell_widths[i])
95+
)
96+
# add a separator
97+
output += col_sep
98+
# replace last seperator with symbol for edge of the row
99+
output = output[0:-1] + right
100+
return output + "\n"
101+
73102
def __top_edge_to_ascii(self) -> str:
74103
"""Assembles the top edge of the ascii table"""
75-
# top-left corner of the table
76-
output: str = self.parts["top_left_corner"]
77-
# top edge above the first column
78-
output += self.parts["top_and_bottom_edge"] * self.__cell_widths[0]
79-
# tee separating first column from the rest of the table
80-
output += self.parts["first_col_top_tee"]
81-
# add remaining columns
82-
for i in range(len(self.__header_row) - 1):
83-
output += self.parts["top_and_bottom_edge"] * self.__cell_widths[i]
84-
output += self.parts["top_tee"]
85-
# replace last top tee with top-right corner
86-
output = output[0:-1] + self.parts["top_right_corner"]
87-
return output
104+
return self.__row_to_ascii(
105+
left=self.parts["top_left_corner"],
106+
first_col_sep=self.parts["first_col_top_tee"],
107+
col_sep=self.parts["top_tee"],
108+
right=self.parts["top_right_corner"],
109+
filler=self.parts["top_and_bottom_edge"],
110+
)
111+
112+
def __bottom_edge_to_ascii(self) -> str:
113+
"""Assembles the top edge of the ascii table"""
114+
return self.__row_to_ascii(
115+
left=self.parts["bottom_left_corner"],
116+
first_col_sep=self.parts["first_col_bottom_tee"],
117+
col_sep=self.parts["bottom_tee"],
118+
right=self.parts["bottom_right_corner"],
119+
filler=self.parts["top_and_bottom_edge"],
120+
)
88121

89122
def __header_row_to_ascii(self) -> str:
90123
"""Assembles the header row line of the ascii table"""
91-
# add left edge of table
92-
output: str = self.parts["left_and_right_edge"]
93-
# add first column contents and padding
94-
output += self.__pad(str(self.__header_row[0]), self.__cell_widths[0])
95-
# separate first column from the rest of the table
96-
output += self.parts["first_col_sep"]
97-
# add the rest of the headers
98-
output += self.parts["middle_edge"].join(
99-
self.__pad(str(val), self.__cell_widths[i + 1])
100-
for i, val in enumerate(self.__header_row[1:])
124+
return self.__row_to_ascii(
125+
left=self.parts["left_and_right_edge"],
126+
first_col_sep=self.parts["first_col_sep"],
127+
col_sep=self.parts["middle_edge"],
128+
right=self.parts["left_and_right_edge"],
129+
filler=self.__header_row,
130+
)
131+
132+
def __footer_row_to_ascii(self) -> str:
133+
"""Assembles the header row line of the ascii table"""
134+
return self.__row_to_ascii(
135+
left=self.parts["left_and_right_edge"],
136+
first_col_sep=self.parts["first_col_sep"],
137+
col_sep=self.parts["middle_edge"],
138+
right=self.parts["left_and_right_edge"],
139+
filler=self.__footer_row,
101140
)
102-
# add right edge of the table
103-
output += self.parts["left_and_right_edge"]
104-
return output
105141

106142
def __header_sep_to_ascii(self) -> str:
107143
"""Assembles the seperator below the header of the ascii table"""
108-
# add left edge tee
109-
output: str = self.parts["header_left_tee"]
110-
# top edge above the first column
111-
output += self.parts["header_row_sep"] * self.__cell_widths[0]
112-
# tee separating first column from the rest of the table
113-
output += self.parts["first_col_header_cross"]
114-
# add remaining columns
115-
for i in range(len(self.__header_row) - 1):
116-
output += self.parts["header_row_sep"] * self.__cell_widths[i]
117-
output += self.parts["header_row_cross"]
118-
# replace last top tee with top-right corner
119-
output = output[0:-1] + self.parts["right_tee"]
144+
return self.__row_to_ascii(
145+
left=self.parts["header_left_tee"],
146+
first_col_sep=self.parts["first_col_header_cross"],
147+
col_sep=self.parts["header_row_cross"],
148+
right=self.parts["right_tee"],
149+
filler=self.parts["header_row_sep"],
150+
)
151+
152+
def __footer_sep_to_ascii(self) -> str:
153+
"""Assembles the seperator below the header of the ascii table"""
154+
return self.__row_to_ascii(
155+
left=self.parts["footer_left_tee"],
156+
first_col_sep=self.parts["first_col_footer_cross"],
157+
col_sep=self.parts["footer_row_cross"],
158+
right=self.parts["right_tee"],
159+
filler=self.parts["header_row_sep"],
160+
)
161+
162+
def __body_to_ascii(self) -> str:
163+
output: str = ""
164+
for row in self.__body:
165+
output += self.__row_to_ascii(
166+
left=self.parts["left_and_right_edge"],
167+
first_col_sep=self.parts["first_col_sep"],
168+
col_sep=self.parts["middle_edge"],
169+
right=self.parts["left_and_right_edge"],
170+
filler=row,
171+
)
120172
return output
121173

122174
def to_ascii(self) -> str:
123-
cols = len(self.__header_row)
124-
# create table header
125-
table = [
126-
self.__top_edge_to_ascii(),
127-
self.__header_row_to_ascii(),
128-
self.__header_sep_to_ascii(),
129-
]
175+
# add table header
176+
table: str = self.__top_edge_to_ascii()
177+
table += self.__header_row_to_ascii()
178+
table += self.__header_sep_to_ascii()
130179
# add table body
131-
for p in self.__body:
132-
# add table row
133-
table += [
134-
# ║
135-
self.parts["left_and_right_edge"]
136-
+
137-
# 1 ║
138-
f" {p[0]} "
139-
+ self.parts["first_col_sep"]
140-
# 40 40 40 40
141-
+ self.parts["middle_edge"].join(
142-
f"{p[i].rjust(4)} " for i in range(1, cols)
143-
)
144-
# ║
145-
+ self.parts["left_and_right_edge"]
146-
]
147-
# footer row
148-
table += [
149-
# ╟
150-
self.parts["footer_left_tee"]
151-
# ─────╫
152-
+ (
153-
self.parts["footer_row_sep"] * self.__cell_width
154-
+ self.parts["first_col_footer_cross"]
155-
)
156-
# ───────────────────────
157-
+ (
158-
(
159-
self.parts["footer_row_sep"] * self.__cell_width
160-
+ self.parts["footer_row_cross"]
161-
)
162-
* (cols - 1)
163-
)[0:-1]
164-
# ╢
165-
+ self.parts["right_tee"],
166-
# ║
167-
self.parts["left_and_right_edge"]
168-
# SUM ║
169-
+ f"{self.__footer_row[0].rjust(4)} " + self.parts["first_col_sep"]
170-
# 120 ║ 120 ║ 120 ║ 120 ║
171-
+ self.parts["middle_edge"].join(
172-
f"{self.__footer_row[i].rjust(4)} " for i in range(1, cols)
173-
)
174-
# ║
175-
+ self.parts["left_and_right_edge"],
176-
# ╚
177-
self.parts["bottom_left_corner"]
178-
# ═════╩
179-
+ self.parts["top_and_bottom_edge"] * self.__cell_width
180-
+ self.parts["first_col_bottom_tee"]
181-
# ════════════════════════
182-
+ (
183-
(
184-
self.parts["top_and_bottom_edge"] * self.__cell_width
185-
+ self.parts["bottom_tee"]
186-
)
187-
* (cols - 1)
188-
)[0:-1]
189-
# ╗
190-
+ self.parts["bottom_right_corner"],
191-
]
192-
return "\n".join(table)
180+
table += self.__body_to_ascii()
181+
# add table footer
182+
table += self.__footer_sep_to_ascii()
183+
table += self.__footer_row_to_ascii()
184+
table += self.__bottom_edge_to_ascii()
185+
return table
193186

194187

195188
def table2ascii(header_row: List, body: List[List], footer_row: List) -> str:

tests/test_convert.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ def test_normal():
77
body=[["1", "30", "40", "35", "30"], ["2", "30", "40", "35", "30"]],
88
footer_row=["SUM", "130", "140", "135", "130"],
99
)
10-
assert text == (
10+
expected = (
1111
"╔═════╦═══════════════════════╗\n"
1212
"║ # ║ G H R S ║\n"
1313
"╟─────╫───────────────────────╢\n"
1414
"║ 1 ║ 30 40 35 30 ║\n"
1515
"║ 2 ║ 30 40 35 30 ║\n"
1616
"╟─────╫───────────────────────╢\n"
1717
"║ SUM ║ 130 140 135 130 ║\n"
18-
"╚═════╩═══════════════════════╝"
18+
"╚═════╩═══════════════════════╝\n"
1919
)
20+
assert text == expected

0 commit comments

Comments
 (0)