sub MAIN
Documentation for sub MAIN
assembled from the following types:
language documentation Command line interface
(Command line interface) sub MAIN
The sub with the special name MAIN
will be executed after all relevant entry phasers (BEGIN
, CHECK
, INIT
, PRE
, ENTER
) have been run and the mainline of the script has been executed. No error will occur if there is no MAIN
sub: your script will then just have to do the work, such as argument parsing, in the mainline of the script.
Any normal exit from the MAIN
sub will result in an exit code of 0
, indicating success. Any return value of the MAIN
sub will be ignored. If an exception is thrown that is not handled inside the MAIN
sub, then the exit code will be 1
. If the dispatch to MAIN
failed, a usage message will be displayed on STDERR and the exit code will be 2
.
The command line parameters are present in the @*ARGS
dynamic variable and may be altered in the mainline of the script before the MAIN
unit is called.
The signature of (the candidates of the multi) sub MAIN
determines which candidate will actually be called using the standard multi dispatch semantics.
A simple example:
# inside file 'hello.raku' sub MAIN($name) { say "Hello $name, how are you?" }
If you call that script without any parameters, you get the following usage message:
$ raku hello.raku Usage: hello.raku <name>
However, if you give a default value for the parameter, running the script either with or without specifying a name will always work:
# inside file 'hello.raku' sub MAIN($name = 'bashful') { say "Hello $name, how are you?" }
$ raku hello.raku Hello bashful, how are you?
$ raku hello.raku Liz Hello Liz, how are you?
Another way to do this is to make sub MAIN
a multi sub
:
# inside file 'hello.raku' multi sub MAIN() { say "Hello bashful, how are you?" } multi sub MAIN($name) { say "Hello $name, how are you?" }
Which would give the same output as the examples above. Whether you should use either method to achieve the desired goal is entirely up to you.
A more complicated example using a single positional and multiple named parameters, and also showing that where
clauses can also be applied to MAIN
arguments:
# inside "frobnicate.raku" sub MAIN( Str $file where *.IO.f = 'file.dat', Int :$length = 24, Bool :$verbose ) { say $length if $length.defined; say $file if $file.defined; say 'Verbosity ', ($verbose ?? 'on' !! 'off'); }
With file.dat
present, this will work this way:
$ raku frobnicate.raku 24 file.dat Verbosity off
Or this way with --verbose
:
$ raku frobnicate.raku --verbose 24 file.dat Verbosity on
If the file file.dat
is not present, or you've specified another filename that doesn't exist, you would get the standard usage message created from introspection of the MAIN
sub:
$ raku frobnicate.raku doesnotexist.dat Usage: frobnicate.raku [--length=<Int>] [--verbose] [<file>]
Although you don't have to do anything in your code to do this, it may still be regarded as a bit terse. But there's an easy way to make that usage message better by providing hints using pod features:
# inside "frobnicate.raku" sub MAIN( Str $file where *.IO.f = 'file.dat', #= an existing file to frobnicate Int :$length = 24, #= length needed for frobnication Bool :$verbose, #= required verbosity ) { say $length if $length.defined; say $file if $file.defined; say 'Verbosity ', ($verbose ?? 'on' !! 'off'); }
Which would improve the usage message like this:
$ raku frobnicate.raku doesnotexist.dat Usage: frobnicate.raku [--length=<Int>] [--verbose] [<file>] [<file>] an existing file to frobnicate --length=<Int> length needed for frobnication --verbose required verbosity
As any other subroutine, MAIN
can define aliases for its named parameters.
sub MAIN( Str $file where *.IO.f = 'file.dat', #= an existing file to frobnicate Int :size(:$length) = 24, #= length/size needed for frobnication Bool :$verbose, #= required verbosity ) { say $length if $length.defined; say $file if $file.defined; say 'Verbosity ', ($verbose ?? 'on' !! 'off'); }
In which case, these aliases will also be listed as alternatives with --help
:
Usage: frobnicate.raku [--size|--length=<Int>] [--verbose] [<file>] [<file>] an existing file to frobnicate --size|--length=<Int> length needed for frobnication --verbose required verbosity
Enumeration
s can be used in signatures with arguments converted automatically to its corresponding enum
symbol:
enum Flag ( FLAG_FOO => 0b001, FLAG_BAR => 0b010, FLAG_BAZ => 0b100, ); sub MAIN(Flag $flag = FLAG_FOO) { say "Flagging $flag"; }
This will work correctly with
raku MAIN-enum.raku FLAG_BAR
but will die if called with something that is not a Flag
.
%*SUB-MAIN-OPTS
It's possible to alter how arguments are processed before they're passed to sub MAIN {}
by setting options in the %*SUB-MAIN-OPTS
hash. Due to the nature of dynamic variables, it is required to set up the %*SUB-MAIN-OPTS
hash and fill it with the appropriate settings. For instance:
my %*SUB-MAIN-OPTS = :named-anywhere, # allow named variables at any location # other possible future options / custom options ; sub MAIN ($a, $b, :$c, :$d) { say "Accepted!" }
Available options are:
named-anywhere
By default, named arguments passed to the program (i.e., MAIN
) cannot appear after any positional argument. However, if %*SUB-MAIN-OPTS<named-anywhere>
is set to a true value, named arguments can be specified anywhere, even after positional parameter. For example, the above program can be called with:
$ raku example.raku 1 --c=2 3 --d=4
is hidden-from-USAGE
Sometimes you want to exclude a MAIN
candidate from being shown in any automatically generated usage message. This can be achieved by adding a hidden-from-USAGE
trait to the specification of the MAIN
candidate you do not want to show. Expanding on an earlier example:
# inside file 'hello.raku' multi sub MAIN() is hidden-from-USAGE { say "Hello bashful, how are you?" } multi sub MAIN($name) { #= the name by which you would like to be called say "Hello $name, how are you?" }
So, if you would call this script with just a named variable, you would get the following usage:
$ raku hello.raku --verbose Usage: hello.raku <name> -- the name by which you would like to be called
Without the hidden-from-USAGE
trait on the first candidate, it would have looked like this:
$ raku hello.raku --verbose Usage: hello.raku hello.raku <name> -- the name by which you would like to be called
Which, although technically correct, doesn't read as well.
language documentation Functions
From Functions
(Functions) sub MAIN
Declaring a sub MAIN
is not compulsory in Raku scripts, but you can provide one to create a command line interface for your script.