About this mini-article series. For each of the past 24 23 days, I have reviewed a module that parses command-line options (such module is usually under the Getopt::* namespace). First article is here.
This series was born out of my experimentations with option parsing and tab completion, and more broadly of my interest in doing CLI with Perl. Aside from writing this series, I've also released numerous modules related to option parsing, some of them are purely experimental in nature and some already used in production.
It has been interesting evaluating the various modules: the sometimes unconventional or seemingly odd approach that they take, or the specific features that they offer. Not all of them are worth using, but at least they provide perspectives and some lessons for us to learn.
Of course, not all modules got reviewed. There are simply far more than 24 modules (lcpan tells me that there are 180 packages in the Getopt:: namespace alone, with 94 distributions having the name Getopt-*). I tried to cover at least the must-know ones, core ones, and the popular ones. Other than that, frankly the selection is pretty much random. I picked what's interesting to me or what I can make some points about, whether they are negative or positive points.
I have skipped many modules that are just yet another Getopt::Long wrapper which adds per-option usage or some other features found in Getopt::Long::Descriptive (GLD). Not that they are worse than GLD, for some reason or another they just didn't get adopted widely or at all. A couple examples of these: Getopt::Helpful, Getopt::Fancy.
Modules which use Moose, except MooseX::Getopt, automatically get skipped by me because their applicability is severely limited by the high number of dependencies and high startup overhead (200-500ms or even more on slower computers). These include: Getopt::Flex, Getopt::Alt, Getopt::Chain.
Some others are simply too weird or high in "WTF number", but I won't name names here.
Except for App::Cmd and App::Spec, I haven't really touched CLI frameworks in general. There are no shortages of CLI frameworks on CPAN too, perhaps for another series?
I've avoided reviewing my own modules, which include Getopt::Long::Complete (Getopt::Long wrapper which adds tab completion), Getopt::Long::Subcommand (Getopt::Long wrapper, with support for subcommands), Getopt::Long::More (my most recent Getopt::Long wrapper which adds tab completion and other features), Getopt::Long::Less & Getopt::Long::EvenLess (two leaner versions of Getopt::Long for the specific goal of reducing startup overhead), Getopt::Panjang (a break from Getopt::Long interface compatibility to explore new possibilities), and a CLI framework Perinci::CmdLine (which currently uses Getopt::Long but plans to switch backend in the long run; I've written a whole series of tutorial posts for this module).
In general, I'd say that you should probably try to stick with Getopt::Long first. As far as option parsing is concerned, it's packed with features already, and it has the advantage of being a core module. But as soon as you want: automatic autohelp/automessage generation, subcommand, tab completion then you should begin looking elsewhere.
Unfortunately except for evaluating Perl ports of some option parsing libraries (like Smart::Options, Getopt::ArgParse, Getopt::Kingpin), I haven't got the chance to deeply look into how option parsing is done in other languages. Among the other languages is Perl's own sister Perl 6, which offers built-in command-line option parsing. This endeavor of researching option parsing in other languages could potentially offer more lessons and perspectives.
I hope this series is of use to some people. Merry christmas and happy holidays to everybody.
This has been a really nice advent calendar (I found it through the normal one). Long ago I looked into the Getopt, App, and CLI modules and decided Getopt::Long + Pod::Usage was vastly superior. App::Cmd was the only interesting one. But this series got me excited again. I thought there were too many back then, but it’s really gotten quite ridiculous at this point! LOL!
One U didn’t cover (because it’s just a very thin wrapper, which is what I liked) was App::CLI::Toolkit. I liked Getopt::Kingpin and Getopt::Fancy. Docopt was one I never would’ve found without U since it’s not in the normal name-spaces. I wonder how U found it! It actually seems quite cool, but good lord, so many modules! Another nice one U didn’t cover was App::Rad (probably the WTF#).
Alas, in the end, I still think nothing compares to Getopt::Long + Pod::Usage. For one, argument parsing is pretty basic, so if your module requires a bunch of other non-core modules to be installed, you’ve done it very wrong. It would be one thing if you’re working on a large application with dozens of scripts and other functionality that obviously requires tons of CPAN modules anyway. But most people are just writing a single script for some singular purpose and to make everyone that uses that script install beaucoup modules is ridiculous (yes, even if all the CPAN installers make this automatic now-a-days, in fact, even more so; it’s so easy to pollute the OS install now, sigh). And if the module itself is so convoluted and dramatic that it has to be broken down into more than a single module (maybe 2 or 3 would be acceptable), then you’ve really gone off the rails. It’s command-line parsing, get over yourself, Docopt! LOL!
I assume Perinci::CmdLine is some sort of joke to see how many CPAN modules U could get people to install just to write a script. 😉 No, I actually assume things like that are intended for people who are using the entire framework. Frameworks are nice for building medium to large applications, but not so much for just tiny scripts and command-line tools.
I wish they hadn’t removed Module::Pluggable from core, because that made subcommands pretty much cake. Of course, I’m old and thus a strong believer in the core Unix philosophy of do one thing and do it well, so subcommands seem silly to me, but if U must have them–App::Rad seems like the best option if U ignore most of the weird features and just stick to the basics; fewer modules and dependencies than App::Cmd; in fact, no non-core deps. If I needed shell completion, I guess Getopt::Complete (no non-core dependencies) is the best option, which isn’t saying much. It’d be nice if someone would make a simple shell completer module that didn’t require an entire framework of modules just to use. Bash::Completion doesn’t seem very good, but I could be wrong. Unfortunately, I think completion is just one of those “complicated” things, especially if U want to support more than one shell.
Thanks for doing this series, it was quite enjoyable even if it didn’t change my mind: Getopt::Long + Pod::Usage–core modules, still the best. 🙂
LikeLike
Hi,
Thanks for commenting. As I said in the article about Docopt, the Python library really made some splashes back in 2012, you could read it being discussed on reddit (/r/programming), HackerNews, or other forums.
The dependencies situation of Perinci::CmdLine is … a bit unfortunate 🙂 I was trying to be modular and split code into many distributions, which I think is proper and has worked really well. But hey, Perinci::CmdLine::Lite currently has a total of 90 direct/indirect non-core modules (in 83 distinct distributions), so that’s not too bad 🙂 I’m trying to reduce the number of dependencies in the long run. Especially since I write “tiny” CLI scripts using it all the time.
About shell completion: I wish people would stop thinking that completion is “complicated” or advanced. It’s almost 2017 and tab completion should be a basic feature that is taken for granted. Getopt::Complete doesn’t have non-core dependency, but it’s really still buggy at this moment. I’d recommend you try my Getopt::Long::More. It only has 14 non-core module dependency, most of those modules are small. Or at least Getopt::Long::Complete.
LikeLike
Hi. This time OK. I logged in via a WordPress un/pw.
I did wonder if you’d seen Getopt::Simple, but I have no problem with you not discussing it. I don’t use it anymore, preferring to stick with Getopt::Long.
Cheers
LikeLike
Hi Ron,
Yes, I did evaluate Getopt::Simple. It has the right basic idea of using a hash for every option, to allow specifying various stuffs from usage message to default value to association with an environment variable. Getopt::Simple doesn’t yet allow expressing that an option is required. Other than that I think Getopt::Simple is mostly OK.
LikeLike
Hi. Repeating the comment I could not enter via a G+ failed login:
Thanx for this series. I’ve added it to my module reviews page: http://savage.net.au/Module-reviews.html
LikeLike