llvmbot monitor: Convert table output to a builder class
We could import a library to do this but it doesn't seem
worth it just for tables.
This uses a content manager so you don't have to write the
begin and end of each cell/row/table. Each method returns
self so you can just keep calling methods to build what you
need.
Change-Id: I8eef664f41039a9fbc662a148f292efd61866694
diff --git a/monitor/make_table.py b/monitor/make_table.py
new file mode 100644
index 0000000..2f115b5
--- /dev/null
+++ b/monitor/make_table.py
@@ -0,0 +1,132 @@
+# This file contains a basic "builder" style API for making HTML tables
+# and writing them to a file once finished.
+#
+# Use it as follows:
+# with Table(outfile) as table:
+# table.AddRow().AddCell("foo")
+#
+# To get:
+# <table>
+# <td>foo</td>
+# </table>
+#
+# Methods return a reference to self, or to the new thing you added.
+# This means you can keep chaining calls to build what you want.
+#
+# table.AddRow().AddCell("foo").Colspan(1).Style("mystyle")
+
+
+class TableCell(object):
+ def __init__(self, name, content=None):
+ self.name = name
+ self.content = content
+ self.style = None
+ self.colspan = None
+
+ def Style(self, style):
+ self.style = style
+ return self
+
+ def Colspan(self, colspan):
+ self.colspan = colspan
+ return self
+
+ def Content(self, content):
+ self.content = content
+ return self
+
+ def __str__(self):
+ return " <{}{}{}>{}</{}>".format(
+ self.name,
+ "" if self.style is None else ' style="{}"'.format(self.style),
+ "" if self.colspan is None else " colspan={}".format(self.colspan),
+ " " if self.content is None else self.content,
+ self.name,
+ )
+
+
+class Cell(TableCell):
+ def __init__(self, content=None):
+ super(Cell, self).__init__("td", content)
+
+
+class Header(TableCell):
+ def __init__(self, content=None):
+ super(Header, self).__init__("th", content)
+
+
+class Row(object):
+ def __init__(self):
+ self.cells = []
+
+ def AddCell(self, content=None):
+ self.cells.append(Cell(content))
+ return self.cells[-1]
+
+ def AddHeader(self, content=None):
+ self.cells.append(Header(content))
+ return self.cells[-1]
+
+ def __str__(self):
+ return "\n".join([" <tr>", *map(str, self.cells), " </tr>"])
+
+
+class TableBody(object):
+ def __init__(self, close=False):
+ self.close = close
+
+ def __str__(self):
+ return "<{}tbody>".format("/" if self.close else "")
+
+
+class Table(object):
+ def __init__(self, out):
+ self.out = out
+ self.rows = []
+ self.border = None
+ self.cellspacing = None
+ self.cellpadding = None
+ self.body_begins = None
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ self.out.write("\n" + str(self))
+
+ def __str__(self):
+ open_tag = "<table{}{}{}>".format(
+ "" if self.border is None else " border={}".format(self.border),
+ ""
+ if self.cellspacing is None
+ else " cellspacing={}".format(self.cellspacing),
+ ""
+ if self.cellpadding is None
+ else " cellpadding={}".format(self.cellpadding),
+ )
+ rows = map(str, self.rows)
+ close_tag = "</table>"
+
+ return "\n".join([open_tag, *rows, close_tag])
+
+ def AddRow(self):
+ self.rows.append(Row())
+ return self.rows[-1]
+
+ def Border(self, border):
+ self.border = border
+ return self
+
+ def Cellspacing(self, cellspacing):
+ self.cellspacing = cellspacing
+ return self
+
+ def Cellpadding(self, cellpadding):
+ self.cellpadding = cellpadding
+ return self
+
+ def BeginBody(self):
+ self.rows.append(TableBody())
+
+ def EndBody(self):
+ self.rows.append(TableBody(close=True))