Skip to content

Commit ec14ecd

Browse files
authored
Some work on create-cli.rakudoc (#4688)
* make example more elementary * improve some explanations * make alias example about single-letter variants for long-form args This should be the most interesting use case for parameter aliases in the CLI context. * add missing comma * add references to Q syntax * linkfix & whitespace * reorder section on intercepting USAGE and MAIN The subsection `sub RUN-MAIN` clearly doesn't belong under the section on usage message interception. It fits slightly better under the section on intercepting CLI argument parsing, where I've put it now. It would probably fit best under the last section "Intercepting MAIN calling", but for that edit one would have to make sure to get the history right. The new order of sections also has the advantage that everything on usage messages is contiguous, and everything on custom CLI handling & MAIN calling.
1 parent 79411a9 commit ec14ecd

File tree

1 file changed

+62
-50
lines changed

1 file changed

+62
-50
lines changed

doc/Language/create-cli.rakudoc

Lines changed: 62 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ If you want to pass an indeterminate number of parameters to be dealt with in
104104
C<sub MAIN>, you can use L<slurpy parameters|/language/signatures#Slurpy_parameters>:
105105

106106
# inside file 'hello-all.raku'
107-
sub MAIN(*@all) { @all.map: -> $name { say "Hello, " ~ $name } }
107+
sub MAIN(*@all) { for @all -> $name { say "Hello, " ~ $name } }
108108

109109
=begin code :lang<shell>
110110
$ raku hello-all.raku peter paul mary
@@ -131,7 +131,10 @@ sub MAIN(
131131
say 'Verbosity ', ($verbose ?? 'on' !! 'off');
132132
}
133133

134-
With C<file.dat> present, this will work this way:
134+
The clause C<where *.IO.f> checks that the string C<$file> corresponds to the name of a file that actually exists.
135+
The part C<= 'file.dat'> specifies a default value for C<$file> in case no argument for it is given.
136+
137+
If a file C<file.dat> is present, a call with no arguments will work this way:
135138
=begin code :lang<shell>
136139
$ raku frobnicate.raku
137140
24
@@ -158,12 +161,12 @@ Usage:
158161
frobnicate.raku [--length=<Int>] [--verbose] [<file>]
159162
=end code
160163

161-
Although you don't have to do anything in your code to do this, it may still
162-
be regarded as a bit terse.
164+
Such usage messages are generated completely automatically for you.
165+
If they seem too terse, you can easily add more information to them.
163166

164167
=head2 Improve usage messages with rakudoc comments
165168

166-
But there's an easy way to make that usage
169+
There's an easy way to make the autogenerated usage
167170
message better by providing hints using pod features:
168171

169172
=for code :method<False>
@@ -265,12 +268,13 @@ And here's the signature that produces each type of argument:
265268

266269
As any other subroutine, C<MAIN> can define
267270
L<aliases|/language/signatures#Argument_aliases> for its named parameters.
271+
In particular, this can be used to define single-letter alternative names.
268272

269273
=for code :method<False>
270274
sub MAIN(
271275
Str $file where *.IO.f = 'file.dat', #= an existing file to frobnicate
272-
Int :size(:$length) = 24, #= length/size needed for frobnication
273-
Bool :$verbose, #= required verbosity
276+
Int :l(:$length) = 24, #= length needed for frobnication
277+
Bool :v(:$verbose), #= required verbosity
274278
) {
275279
say $length if $length.defined;
276280
say $file if $file.defined;
@@ -284,8 +288,8 @@ Usage:
284288
frobnicate.raku [--size|--length=<Int>] [--verbose] [<file>]
285289

286290
[<file>] an existing file to frobnicate
287-
--size|--length=<Int> length needed for frobnication
288-
--verbose required verbosity
291+
-l|--length=<Int> length needed for frobnication
292+
-v|--verbose required verbosity
289293
=end code
290294

291295
=head2 Named arrays
@@ -327,14 +331,15 @@ enum Flag (
327331
);
328332

329333
sub MAIN(Flag $flag = FLAG_FOO) {
330-
say "Flagging $flag";
334+
say "Flagging $flag with value $flag.value()";
331335
}
332336
=end code
333337

334338
This will work correctly with
335339

336340
=for code :lang<text>
337-
raku MAIN-enum.raku FLAG_BAR
341+
raku MAIN-enum.raku FLAG_BAZ
342+
# OUTPUT: «Flagging FLAG_BAZ with value 4␤»
338343

339344
but will die if called with something that is not a C<Flag>.
340345

@@ -495,6 +500,11 @@ If no multi candidate of C<MAIN> is found for the given command line
495500
parameters, the sub C<USAGE> is called. If no such method is found,
496501
the compiler will output a default usage message.
497502

503+
In the following example, we print a custom usage message via
504+
a L<Q string|/language/quoting>
505+
(with the C<:c|/language/quoting#Interpolating_closures> flag enabling interpolation of curly braces,
506+
and the C<:to|/language/quoting#Heredocs:_:to> flag for stating it all as a heredoc):
507+
498508
#|(is it the answer)
499509
multi MAIN(Int $i) { say $i == 42 ?? 'answer' !! 'dunno' }
500510
#|(divide two numbers)
@@ -514,6 +524,46 @@ candidates and their parameters. As shown before, you can specify an
514524
additional extended description for each candidate using a
515525
C<#|(...)> Pod block to set L«C<WHY>|/routine/WHY».
516526

527+
528+
=head1 Intercepting usage message generation (2018.10, v6.d and later)
529+
530+
You can replace or augment the default way of usage message generation
531+
(after a failed dispatch to MAIN) by supplying a C<GENERATE-USAGE> subroutine
532+
yourself, or by importing one from any of the
533+
L<Getopt|https://raku.land/?q=getopt> modules available in the
534+
ecosystem.
535+
536+
=head2 X<sub GENERATE-USAGE|Subroutines,GENERATE-USAGE>
537+
538+
The C<GENERATE-USAGE> subroutine should accept a L<C<Callable>|/type/Callable> representing the
539+
C<MAIN> subroutine that didn't get executed because the dispatch failed.
540+
This can be used for introspection. All the other parameters are the
541+
parameters that were set up to be sent to C<MAIN>. It should return the
542+
string of the usage information you want to be shown to the user. An example
543+
that will just recreate the L<C<Capture>|/type/Capture> that was created from processing the
544+
arguments:
545+
546+
sub GENERATE-USAGE(&main, |capture) {
547+
capture<foo>:exists
548+
?? "You're not allowed to specify a --foo"
549+
!! &*GENERATE-USAGE(&main, |capture)
550+
}
551+
552+
You can also use multi subroutines to create the same effect:
553+
554+
multi GENERATE-USAGE(&main, :$foo!) {
555+
"You're not allowed to specify a --foo"
556+
}
557+
multi GENERATE-USAGE(&main, |capture) {
558+
&*GENERATE-USAGE(&main, |capture)
559+
}
560+
561+
Note that the dynamic variable
562+
L<C<&*GENERATE-USAGE>|/language/variables#&*GENERATE-USAGE> is available to
563+
perform the default usage message generation so you don't have to reinvent the
564+
whole wheel if you don't want to.
565+
566+
517567
=head1 Intercepting CLI argument parsing (2018.10, v6.d and later)
518568

519569
You can replace or augment the default way of argument parsing by supplying an
@@ -545,21 +595,13 @@ L<C<&*ARGS-TO-CAPTURE>|/language/variables#&*ARGS-TO-CAPTURE> is available to
545595
perform the default command line arguments to L<C<Capture>|/type/Capture> processing so you don't
546596
have to reinvent the whole wheel if you don't want to.
547597

548-
=head1 Intercepting usage message generation (2018.10, v6.d and later)
549-
550-
You can replace or augment the default way of usage message generation
551-
(after a failed dispatch to MAIN) by supplying a C<GENERATE-USAGE> subroutine
552-
yourself, or by importing one from any of the
553-
L<Getopt|https://raku.land/?q=getopt> modules available in the
554-
ecosystem.
555-
556598
=head2 X<sub RUN-MAIN|Subroutines,RUN-MAIN>
557599

558600
sub RUN-MAIN(&main, $mainline, :$in-as-argsfiles)
559601

560602
This routine allows complete control over the handling of C<MAIN>. It gets a
561603
L<C<Callable>|/type/Callable> that is the C<MAIN> that should be executed, the return value of the
562-
mainline execution and additional named variables: C<:in-as-argsfiles> which
604+
mainline execution and an additional named variable: C<:in-as-argsfiles> which
563605
will be C<True> if STDIN should be treated as C<$*ARGFILES>.
564606

565607
If C<RUN-MAIN> is not provided, a default one will be run that looks for
@@ -586,36 +628,6 @@ RUN-MAIN( &new-main, Nil );
586628
This will print the name (first argument) of the generated object.
587629

588630

589-
=head2 X<sub GENERATE-USAGE|Subroutines,GENERATE-USAGE>
590-
591-
The C<GENERATE-USAGE> subroutine should accept a L<C<Callable>|/type/Callable> representing the
592-
C<MAIN> subroutine that didn't get executed because the dispatch failed.
593-
This can be used for introspection. All the other parameters are the
594-
parameters that were set up to be sent to C<MAIN>. It should return the
595-
string of the usage information you want to be shown to the user. An example
596-
that will just recreate the L<C<Capture>|/type/Capture> that was created from processing the
597-
arguments:
598-
599-
sub GENERATE-USAGE(&main, |capture) {
600-
capture<foo>:exists
601-
?? "You're not allowed to specify a --foo"
602-
!! &*GENERATE-USAGE(&main, |capture)
603-
}
604-
605-
You can also use multi subroutines to create the same effect:
606-
607-
multi GENERATE-USAGE(&main, :$foo!) {
608-
"You're not allowed to specify a --foo"
609-
}
610-
multi GENERATE-USAGE(&main, |capture) {
611-
&*GENERATE-USAGE(&main, |capture)
612-
}
613-
614-
Note that the dynamic variable
615-
L<C<&*GENERATE-USAGE>|/language/variables#&*GENERATE-USAGE> is available to
616-
perform the default usage message generation so you don't have to reinvent the
617-
whole wheel if you don't want to.
618-
619631
=head1 Intercepting MAIN calling (before 2018.10, v6.e)
620632

621633
An older interface enabled one to intercept the calling to C<MAIN> completely.

0 commit comments

Comments
 (0)