I'm trying to get my head in the Scala game, and would welcome feedback on the following code, which produces a table from data.
class TabulatorTest extends FunSuite with ShouldMatchers {
test("format") {
Tabulator.format(List(
List("head1", "head2", "head3"),
List("one", "two", "three"),
List("four", "five", "six"))) should be ("""
+-----+-----+-----+
|head1|head2|head3|
+-----+-----+-----+
| one| two|three|
| four| five| six|
+-----+-----+-----+
""".trim)
}
test("format empty") {
Tabulator.format(List()) should be ("")
Tabulator.format(List(List())) should be ("""
++
||
++
++
""".trim)
}
test("uneven rows") {
try {
Tabulator.format(List(
List("head1", "head2", "head3"),
List("one", "two")))
fail()
} catch {
case e: IllegalArgumentException =>
}
}
}
object Tabulator {
def format(table: Seq[Seq[Any]]) = table match {
case Seq() => ""
case _ =>
val cellSizes = for (row <- table) yield
(for (cell <- row) yield
if (cell == null) 0 else cell.toString.length)
val colSizes = for (col <- cellSizes.transpose) yield col.max
val rows = for (row <- table) yield formatRow(row, colSizes)
formatRows(rowSeparator(colSizes), rows)
}
def formatRow(row: Seq[Any], colSizes: Seq[Int]) = {
val cells = (for ((item, size) <- row.zip(colSizes)) yield
if (size == 0) "" else ("%" + size + "s").format(item))
cells.mkString("|", "|", "|")
}
def formatRows(rowSeparator: String, rows: Seq[String]): String = (
rowSeparator ::
rows.head ::
rowSeparator ::
rows.tail.toList :::
rowSeparator ::
List()).mkString("\n")
private def rowSeparator(colSizes: Seq[Int]) =
colSizes map { "-" * _ } mkString("+", "+", "+")
}