The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Text::Yeti::Table - Render a table like "docker ps" does

VERSION

version 0.3.0

SYNOPSIS

use Text::Yeti::Table qw(render_table);

render_table( $list, $spec );

DESCRIPTION

Text::Yeti::Table renders a table of data into text. Given a table (which is an arrayref of hashrefs) and a specification, it creates output such as below.

CONTAINER ID   IMAGE                   CREATED       STATUS               NAME           
632495650e4e   alpine:latest           5 days ago    Exited 5 days ago    zealous_galileo
6459c004a7b4   postgres:9.6.1-alpine   23 days ago   Up 23 days           hardcore_sammet
63a4c1b60c9f   f348af3681e0            2 weeks ago   Exited 12 days ago   elastic_ride   

The specification can be as simple as:

[ 'key1', 'key2', 'key3' ]

For complex values, a function can be given for the text conversion.

[ 'name', 'id', 'node', 'address', [ 'tags', sub {"@{$_[0]}"} ] ]

Usually headers are computed from keys, but that can be overriden.

[ 'ServiceName', 'ServiceID', 'Node', [ 'Datacenter', undef, 'DC' ] ]

EXAMPLE

The following code illustrates a full example:

my @items = (
    {   ContainerId => '632495650e4e',
        Image       => 'alpine:latest',
        Created     => { unit => 'days', amount => 5 },
        ExitedAt    => { unit => 'days', amount => 5 },
        Name        => '/zealous_galileo',
    },
    {   ContainerId => '6459c004a7b4',
        Image       => 'postgres:9.6.1-alpine',
        Created     => { unit => 'days', amount => 23 },
        StartedAt   => { unit => 'days', amount => 23 },
        Running     => true,
        Name        => '/hardcore_sammet',
    },
    {   ContainerId => '63a4c1b60c9f',
        Image       => 'f348af3681e0',
        Created     => { unit => 'weeks', amount => 2 },
        ExitedAt    => { unit => 'days', amount => 12 },
        Name        => '/elastic_ride',
    },
);

sub status_of {
    my ( $running, $item ) = ( shift, shift );
    $running
      ? "Up $item->{StartedAt}{amount} $item->{StartedAt}{unit}"
      : "Exited $item->{ExitedAt}{amount} $item->{ExitedAt}{unit} ago";
}

my @spec = (
    'ContainerId',
    'Image',
    [ 'Created', sub {"$_[0]->{amount} $_[0]->{unit} ago"} ],
    [   'Running', \&status_of, 'STATUS' ],
    [ 'Name', sub { substr( shift, 1 ) } ],
);

render_table( \@items, \@spec );

The corresponding output is the table in "DESCRIPTION".

FUNCTIONS

Text::Yeti::Table implements the following functions, which can be imported individually.

render_table

render_table( \@items, $spec );
render_table( \@items, $spec, $io );

The $spec is an arrayref whose entries can be:

  • a string (like 'key'), which is equivalent to

    ['key']
  • an arrayref, with up to 3 entries

    ['key', $to_s, $header]

    $to_s is a function to convert the value under 'key' to text. By default, it stringifies the value, except for undef which becomes "<none>".

    $header is the header for the corresponding column. By default, it is computed from the key, as in the examples below:

    "image"       -> "IMAGE"
    "ContainerID" -> "CONTAINER ID"
  • a hashref, with keys

    k => 'key',       required
    s => $to_s,
    h => $header,
    x => $exclude,

    where

    $to_s is a function to convert the value under k to text. By default, undef becomes '<none>', and everything else is stringfied.

    $header is the header for the corresponding column. If not given, it is computed from the key as above.

    $exclude is a coderef which given all the values of a column (as an arrayref) should return true if the column should be excluded or false if the column is to be kept. As an example,

    use List::Util 'all';
    (x => sub { all { $_ eq '<none>' } @{$_[0]} })

    will exclude the corresponding column if all values collapse to '<none>'.

The $io is a handle. By default, output goes to STDOUT.

AUTHOR

Adriano Ferreira <ferreira@cpan.org>

CONTRIBUTOR

Adriano Ferreira <a.r.ferreira@gmail.com>

COPYRIGHT AND LICENSE

This software is copyright (c) 2017-2018 by Adriano Ferreira.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.