markdown_table.ry
module markdown_table
purpose: Render rows of text as a Markdown table with aligned columns.
import std.console
public type Table
purpose: A header row and any number of body rows.
has header: List of Text
has rows: List of List of Text
end
public function column_widths(table: Table) returns List of Integer
purpose: The width of the widest cell in every column, the header included.
example: column_widths(Table(header: ["name", "qty"], rows: [["apple", "1"]])) is [5, 3]
return for each title, index in table.header.with_index()
collect widest(table: table, index: index, minimum: title.length())
end
function widest(table: Table, index: Integer, minimum: Integer) returns Integer
let mutable width be minimum
for each row in table.rows
let cell be row.at(index) otherwise ""
if cell.length() is greater than width then change width to cell.length() end
end
return width
end
function render_row(cells: List of Text, widths: List of Integer) returns Text
let mutable padded: List of Text be []
for each width, index in widths.with_index()
let cell be cells.at(index) otherwise ""
change padded to padded.append(cell.pad_right(width))
end
let separator be " | "
return "| {padded.join(separator)} |"
end
public function render(table: Table) returns Text
purpose: The table as Markdown, every column padded to its widest cell.
tags: markdown, formatting
example: render(Table(header: ["name", "qty"], rows: [["apple", "1"], ["kiwi", "12"]])) is """
| name | qty |
| ----- | --- |
| apple | 1 |
| kiwi | 12 |
"""
let widths be column_widths(table)
let divider be for each width in widths collect "-".repeat(width)
let mutable lines be [render_row(cells: table.header, widths: widths)]
change lines to lines.append(render_row(cells: divider, widths: widths))
for each row in table.rows
change lines to lines.append(render_row(cells: row, widths: widths))
end
return lines.join("\n")
end
public function main() needs console
purpose: Print a small table of fruit prices.
let prices be Table(
header: ["fruit", "price", "stock"],
rows: [["apple", "0.50", "120"], ["kiwi", "0.80", "7"], ["watermelon", "3.20", "2"]]
)
console.print(render(prices))
end