When writing a program, one of the best ways to make it reusable is by accepting parameters on the command line.
For example if you are writing a program that needs to parse a log file, you might want to supply the name of the logfile on the command line.
If the application needs to send an e-mail report, it is more generic if the user can supply the address as a command line parameter: --to boss@company
How can you let your Perl 6 application to accept command line arguments?
When Perl 6 is launched it fills the system variable @*ARGS with all the values from the command line. A simple script like the following can demonstrate what we get:
use v6; say @*ARGS.perl;
Save as cli.pl6 and run
perl6 cli.pl6 first --second "third and fourth"
The output will be
Array.new("first", "--second", "third and fourth")
The @*ARGS in Perl 6 is the same as @ARGV in Perl 5. It does NOT contain the name of the executable itself as it is done in C and Python for example.
We could now write some code that goes over the values in @*ARGS, but luckily Perl 6 provides a built-in mechanism for that. It is the same mechanism that works for Perl 6 subroutines. After all the command line parameters of a program are very similar to the arguments of a function.
There is a special name in Perl 6 called MAIN. If your main program file contains a subroutine called MAIN, that subroutine will be executed when the program is launched.
Furthermore, the signature of that subroutine is the expected list of arguments of the whole program.
Let's see a simple example:
use v6; sub MAIN($source) { say "source: $source"; }
Save it as cli.pl6 and run it as perl6 cli.pl6.
You will get:
Usage: cli.pl6 <source>
That's because the MAIN subroutine expects a single positional argument that will be assigned t the $source variable.
Now run perl6 cli.pl6 input.txt.
The output will be:
source: input.txt
That means, the command line parameter was accepted and the MAIN sub was called with $source having the value "input.txt".
In the next example, we extended the signature. In addition to the $source field we are now expecting a boolean value to be assigned to $debug. We also gave it a default value, making this parameter optional.
use v6; sub MAIN($source, Bool $debug = False) { say "source: $source"; say "debug: $debug"; }
Save the code and run it as perl6 cli.pl6.
You will find the output quite clear. We have to supply the source parameter and optionally the debug parameter.
Usage: cli.pl6 <source> [<debug>]
Let's try it again running it with one parameter: perl6 cli.pl6 data.txt
We get this output:
source: data.txt debug: False
And try it again, now supplying both parameters: perl6 cli.pl6 data.txt True
source: data.txt debug: True
You cannot pass the values in the opposite order and the boolean values must be True or False.
If we try something else: perl6 cli.pl6 data.txt 1 we get the usage message again:
Usage: cli.pl6 <source> [<debug>]
As in regular subroutines, Perl 6 allows to turn arguments into named parameter.
Put a colon : in front of the variable name to turn it into a named variable:
use v6; sub MAIN($source, Bool :$debug = False) { say "source: $source"; say "debug: $debug"; }
Let's see what happens if we execute the code without any parameter: perl6 cli.pl6
The usage message indicated that now we need to used the --debug flag if we want to turn on debugging and that the named parameters must come before the positional parameters.
Usage: cli.pl6 [--debug] <source>
Try this: perl6 cli.pl6 data.txt
source: data.txt debug: False
And now try perl6 cli.pl6 --debug data.txt
source: data.txt debug: True
You cannot change the order of the parameters as positional parameters have to arrive after the named parameters. try perl6 cli.pl6 data.txt --debug and you'll get the usage message.
In the next example we turn the source parameter to be named as well by preceding it with a colon ::
use v6; sub MAIN(:$source, Bool :$debug = False) { say "source: $source"; say "debug: $debug"; }
Try without any parameters: perl6 cli.pl6 and get:
use of uninitialized value of type Any in string context in method Str at ... source: debug: True
That happens because named parameters are optional and the code will run without any parameter. When we try to print the content of the $source variable, it will be undef and generate this warning.
There are several ways to fix this:
We could set a default value, even if that is an empty string:
sub MAIN(:$source = '', Bool :$debug = False) {
We could also tell Perl, that $source is a required parameter by adding a trailing exclamation point !.
sub MAIN(:$source!, Bool :$debug = False) {
Try to run the program now without any parameter perl6 cli.pl6
and you'll get the new usage message.
Usage: code\cli.pl6 --source=<Any> [--debug]
You could, of course, declare that the $source variable should be an integer Int or some other data type, if that was the requirement. For example like this:
sub MAIN(Int :$source!, Bool :$debug = False) {
In that case the usage message will indicate the required data type:
Usage: code\cli.pl6 --source=<Int> [--debug]
In order to supply the value for the source, currently you have to use exactly the above form
perl6 cli.pl6 --source=data.txt
source: data.txt debug: False
If you happen to try the other common way:
perl6 cli.pl6 --source data.txt
You will get the usage message as Rakudo currently does not yet support this form.
There is more of course, but I think this can already get you started writing applications Perl 6 that accept parameters on the command line.
Email: | |
Full name: | |
Published on 2012-09-14