sub create-table(:@headers, :@columns, Bool :$markdown = False --> Nil) {
unless @headers.elems == @columns.elems {
$*ERR.spurt: "Table is out of shape: Number of headers must be equal to number of columns.\n";
$*ERR.flush;
return;
}
unless [==] @columns».elems {
$*ERR.spurt: "Table is out of shape: All columns must have the same length.\n";
$*ERR.flush;
return;
}
my constant $ADDITIONAL-SPACING = 2;
my constant $COLUMN-SEPARATOR = '| ';
my constant $LEFT-BOUNDARY = '| ';
my constant $JOIN-SEPARATOR = '+';
my constant $MARKDOWN-BOUNDARY = '|:';
#
# HEADING
#
my Str:D $row-separator = '';
my @headers-to-max-col-values = [];
for @headers.kv -> $idx, $header {
my Int:D $max-col-value = @columns[$idx].max(:by(&chars)).chars;
@headers-to-max-col-values.push($header => $max-col-value) for 0..^@columns[$idx].elems;
my Str:D $heading-row =
~ ($idx == 0 ?? $LEFT-BOUNDARY !! '')
~ $header
~ (' ' x ($max-col-value + $ADDITIONAL-SPACING + ($idx == 0 ?? 1 !! 0)))
~ $COLUMN-SEPARATOR
;
$*OUT.spurt: $heading-row;
if $markdown {
$row-separator ~=
~ ($idx == 0 ?? $MARKDOWN-BOUNDARY !! '')
~ '-' x ($header.chars + $max-col-value + $ADDITIONAL-SPACING + ($idx == 0 ?? $LEFT-BOUNDARY.chars !! 0) - 1)
~ $MARKDOWN-BOUNDARY
~ ($idx != @headers.end ?? '-' !! '');
$row-separator .= chop(1) if $idx == @headers.end;
}
else {
$row-separator ~=
~ ($idx == 0 ?? $JOIN-SEPARATOR !! '')
~ '-' x ($header.chars + $max-col-value + $ADDITIONAL-SPACING + ($idx == 0 ?? $LEFT-BOUNDARY.chars !! 0))
~ $JOIN-SEPARATOR
~ ($idx != @headers.end ?? '-' !! '');
}
if $idx eq @headers.end {
$*OUT.spurt: "\n$row-separator\n";
}
}
#
# ROWS
#
my Int:D $aligned-data-offset = @columns.min(:by(&elems)).elems;
my Int:D $row-count = @headers.elems;
my Int:D $next-idx = 0;
my Int:D $newrow-indicator = 0;
my Int:D $iterations = 0;
my Str:D @values = @columns.map(*.Slip);
my $m = @values.elems div @columns.head.elems;
for 0 ..^ @values.elems -> $n {
my $first-row = $n %% $m;
my $pair = @headers-to-max-col-values[$next-idx];
my Int:D $chars = $pair.value + $pair.key.chars + $ADDITIONAL-SPACING + ($first-row ?? 1 !! 0);
my Str:D $row-part = sprintf("%-{$chars}s", @values[$next-idx]) ~ $COLUMN-SEPARATOR;
if $next-idx >= @values.elems - $aligned-data-offset {
$next-idx = $iterations + 1;
$iterations += 1;
}
else {
$next-idx += $aligned-data-offset
}
if $newrow-indicator >= $row-count {
$*OUT.flush;
$*OUT.spurt: "\n$LEFT-BOUNDARY";
$newrow-indicator = 0;
}
else {
$*OUT.spurt: $LEFT-BOUNDARY if $n == 0;
}
$*OUT.spurt: $row-part;
$newrow-indicator += 1;
}
$*OUT.spurt: ("\n$row-separator" unless $markdown) ~ "\n";
$*OUT.flush;
}
create-table
headers => ["Process Name", "Arrival Time", "Service Time", "Turnaround Time"],
columns => [
["P1", "P2", "P3", "P4", "P5"],
["1", "3", "6", "2", "3"],
["3", "1", "8", "1", "4"],
["3", "1", "8", "1", "4"],
],
:markdown,
;
| Process Name | Arrival Time | Service Time | Turnaround Time |
|:-----------------|:---------------|:---------------|:------------------|
| P1 | 1 | 3 | 3 |
| P2 | 3 | 1 | 1 |
| P3 | 6 | 8 | 8 |
| P4 | 2 | 1 | 1 |
| P5 | 3 | 4 | 4 |