pericmd 044: Customizing output

The functions we use as backend of our CLI application return pure data structure, and Perinci::CmdLine’s formatter figures out how to best display this information. There are, however, some ways to customize how the output looks in our CLI application by setting some attributes in the result metadata.

As you might remember, result metadata is the fourth element in the enveloped result structure:

[$status, $message, $actual_result, $meta]

The result metadata is a hash (a DefHash actually, but for most purposes you don’t care about the difference). There are some attributes (keys) you can set in this metadata to give hints to Perinci::CmdLine on how to render the result in CLI application.

cmdline.result

The first one is cmdline.result. This sets alternative result to use when in CLI context. For example:

sub func {
    [200, "OK", "foo", {'cmdline.result'=>'bar'}];
}

This way, if you are calling the function, you’ll get “foo” (in the third element), but if this function is run on the command-line, user will see “bar”.

Why would this be useful? An example would be functions that return bool values, like for example user_exists(). In Perl, we probably will only care about getting 1/0. But in CLI, you might want to display a more user-friendly message. So instead of:

% user-exists ujang
0
% user-exists kadek
1

If your function does this:

sub user_exists {
    my %args = @_;
    my $exists = actual_check_for_existence($args{user});
    [200, "OK", $exists, {'cmdline.result' => "User $args{user}" . ($exists ? " exists":"does not exist")}];
}

then you can have:

% user-exists ujang
User ujang does not exist
% user-exists kadek
User kadek exists

Another example where this is applied is in
Git::Bunch
. In function check_bunch, the result is a hash of every repo in the bunch and their check statuses, e.g.:

[200, "OK", {repo1=>[200,"clean"], repo2=>[500,"Needs commit"], ...}]

The function also happens to use progress bar to report unclean repositories as the checking is being done. Unclean repos get reported/logged to the screen. Thus, it is not very useful to display this hash on the CLI (but useful when we are using the function from Perl). So check_bunch() sets the CLI output to empty string:

[200, "OK", ..., {'cmdline.result'=>''}]

cmdline.default_format

This attribute picks the default format. For example:

[200, "OK", ..., {'cmdline.default_format'=>'json'}]

This way, when CLI is run, the output defaults to JSON instead of text, unless user explicitly specify the output format that she wants, e.g. --format text.

One common use-case for this is to force the simple or pretty version of text format. By default, for DWIM-ness, the text format becomes simpler when the program is run through pipes (e.g. formatted ASCII table becomes lines of tab-separated values). For example (I’m using the list-files script mentioned in pericmd 039):

% list-files -v
+----------------+------+------+
| name           | size | type |
+----------------+------+------+
| hello          | 1131 | f    |
| list-files     | 988  | f    |
| list-files2    | 1187 | f    |
| mycomp         | 902  | f    |
| mycomp2a       | 608  | f    |
| mycomp2b       | 686  | f    |
| mycomp2b+comp  | 1394 | f    |
| pause          | 4096 | d    |
| perl-App-hello | 4096 | d    |
+----------------+------+------+

% list-files -v | cat
hello   1131    f
list-files      988     f
list-files2     1187    f
mycomp  902     f
mycomp2a        608     f
mycomp2b        686     f
mycomp2b+comp   1394    f
pause   4096    d
perl-App-hello  4096    d

Sometimes you always want to default to the pretty version (even though your CLI program is run through pipes), and sometimes the other way around. To do this you can instruct in the result metadata 'cmdline.default_format' => 'text-pretty' (or text-simple).

Note that the cmdline.default_format attribute can also be specified in the Rinci function metadata, but specifying this in the result metadata is more flexible as we can customize on a per-invocation basis.

cmdline.exit_code

This is not actually related to output format, but somewhat related. This attribute explicitly chooses an exit code for the CLI program. By default, as you might also remember, status code is determined as follow: “if status is 2xx or 304, then 0, else status-300”.

cmdline.skip_format

If you set this attribute to true, the result will be printed as-is without any formatting. You might want to use this if you are outputting a preformatted text. Which defeats the whole point of convenience given by Perinci::CmdLine, but sometimes it’s useful.

cmdline.page_result and cmdline.pager

This is also not directly related to formatting, but somewhat related. If you set cmdline.page_result to true, you can instruct Perinci::CmdLine to run a pager (like less). This might be useful for programs that output long text. The cmdline.pager can be used to specifically choose another program instead of the default $ENV{PAGER} (or less).

In the next blog post I’ll discuss more ways to customize table output.

Leave a comment