2020 twenty-four merry days of Perl Feed

Choices, choices, so many choices!

Term::Choose - 2020-12-24

2020 has been time consuming - a global pandemic, giant fires, horrific floods and political unrest - which has left us little time for side projects. This year we're looking back to happier times into the 20+ year archive with the Best of the Perl Advent Calendar.

Every day we have to tell our computers about the hundreds of choices we make each day. Yes, I'd like to get the blue scarf, not the green one. Change into this directory not that one. Please force push those changes all over that branch. Yes, of course I'm sure!

Being the command line geeks we are, most of the time this comes in the form of passing arguments to command line programs. Passing option flags. Setting environment variables before we run the script. All of these things are awesome. We can script them. There's command history. We can use command line tab completion (if we've setup bash or zsh just right.)

But sometimes this can get complex. Maybe as users we don't (or can't) know what all the options are without starting to run the script. Maybe we need to be presented with more choices depending on some of the choices we've already made. Maybe the program needs to ask the user something after it's done something with a remote server, and there was no way to predict what questions it needed to have the answer for when the program was originally run. Or maybe we just want something more user friendly than forcing the user to look up in the man page what options they need to pass.

In these situations we tend to build an interactive GUI app or a web app. However, both of these are much harder to do than writing a program that parses simple command line options - there's event loops to consider, callbacks, possibly listening on various ports. Maybe there's a better, er, choice.

Introducing Term::Choose

Term::Choose is a module that allows us to interactively pick from the terminal from several options. It's really simple to use:

use Term::Choose qw( choose );
my $reindeer = choose([qw(
    Dasher Dancer Prancer Vixen
    Comet Cupid Dunder Blixem
], { prompt => 'Who is your favourite reindeer?' }) or exit;
say "Cool I like $reindeer too!";

Terminal demo

The user simply moves the selection around with the cursor keys and hits RETURN to pick one. Easy!

Coding this is considerably more simple than developing a GUI or web app, and because it's running on a terminal you can make use of it anywhere - even on a remote server you're connected to over ssh without the overhead and the complexity of doing something tricky with an X-server.

Note also that Term::Choose is a good terminal citizen. It cleans up after itself, removing the interactive prompt from the screen.

More options than fit on the screen

If you have more options than fit on the screen then the screen scrolls when you move down past the last option:

use Term::Choose qw( choose );
my $film = choose(
   { prompt => 'What Christmas movie shall I rent?' },
) or exit;
say "Renting $film";

Terminal demo

Neat! You really don't have to think about it.

Picking More Than One Option

If you use the choose function in list context you can pick more than one option. Just hitting RETURN works as before, picking just the one option. However, hitting SPACE selects multiple options, and then RETURN submits them all.

use Term::Choose qw( choose );
my @options = choose([
    'with wrapping paper',
    'with a bow on it',
    'with ribbons',
    'with a gift tag',
], { prompt => 'How should I wrap up the present?' });
say "Wrapping up the present with $_" for @options;

Terminal demo

The Right Choice

Like all my favourite Perl modules, Term::Choose is powerful but simple to use. It does one thing, and does it well. It's the right choice.

Gravatar Image This article contributed by: Mark Fowler <mark@twoshortplanks.com>