12

First of all: raku (perl6) is amazing. And so is Cro. It only took a week-end to fall in love. However now I stumble over something that must be extremely simple.

If I use a slurpy parameter in a multiple dispatch MAIN this is recognized and works perfectly:

multi MAIN( 'config', 'add', *@hostnames ) {

However if I make this a non-slurpy array, this is either not recognized or I don't know how to provide it from the command line:

multi MAIN( 'config', 'add', @hostnames ) {

I would expect one of these invocations to work:

$ cli.raku config add www.example.com example.com
$ cli.raku config add www.example.com,example.com
$ cli.raku config add www.example.com, example.com

A similar construct is used in the Cro CLI however without example of how to call one of the commands with an array in the docs.

I also tried this with an array as named parameter:

my %*SUB-MAIN-OPTS = :named-anywhere;
multi MAIN( 'config', 'add', :@hostnames) {

Given the example in the raku docs I would expect this to work:

$ cli.raku config add --hostnames=www.example.com example.com

But it does not, nor variants with comma or space comma separation. In all cases I get the usage information.

acw
  • 447
  • 2
  • 9
  • For the named argument I think you give the option multiple times: —host=a —host=b – LuVa Jun 04 '20 at 23:50
  • 2
    The main problem here is that there's a MAIN with an array as an argument would expect to be handled an array by its invocant and it's impossible that the shell does that kind of thing (see [here](https://stackoverflow.com/questions/17232526/how-to-pass-an-array-argument-to-the-bash-script), so you're left with the slurpy. Commas do not make a difference. Maybe we should clarify that in the documentation, but at any rate, it's a shell limitation, not Raku's – jjmerelo Jun 05 '20 at 15:30

1 Answers1

10

The arg parsing that is built into Raku corresponds to standard shell features/conventions. As JJ notes, there is no shell feature/convention for individual arrays. I presume this is why plain @foo (and %bar) is not defined to match anything as part of the built in CLI parsing features.


Your example would be covered by a slurpy, and you haven't said why you don't want to use a slurpy.

One guess is that it's because a slurpy would allow zero arguments. Here's an idiomatic way to fix that:

multi MAIN( 'config', 'add', *@hostnames where +*) {

You can read the +* as "one or more".

What's actually going on there is that I've written a where clause. This is a constraint that's imposed on a variable or parameter in addition to any other constraint such as a type. A where clause is an arbitrary condition that evaluates as True or False. The value that is about to be bound to the variable/parameter (if it passes the constraint condition) is implicitly "it" for the condition.

Whenever an expression contains one or more operator(s) combined with one or more *s as operand(s), Raku converts the expression into a function, where the *(s) are parameters of that function.

So +* is a tiny little one parameter function that just applies a prefix + to its one argument aka "it".

When you apply prefix + to an array, it returns the Int count of elements in that array. The value returned from the condition expression is evaluated as a Bool -- True or False. If it's 0 (i.e. no arguments were passed), the constraint condition returns False so the MAIN signature fails to bind and the usage message gets displayed.


If that's not it, perhaps it's because you can use only one array slurpy per command line, at the end.

Or just curiosity.


A named array works like this:

sub MAIN ( :@n ) {}

my shell prompt> cli-prog.raku -n=www.example.com -n=example.com

A search of SO for "[raku] getopt"


You can take over control of CLI parsing to get whatever result you want:

raiph
  • 31,607
  • 3
  • 62
  • 111
  • 1
    That there is no shell convention for individual arrays as @jjmerelo mentioned clarified a lot. – acw Jun 06 '20 at 00:12
  • 1
    In the SuperMain source, you pointed me to, I found this: PROCESS::<%SUB-MAIN-OPTS> = True; That allows me to put the subcommands in front of the named array. (And perhaps could be added to https://docs.raku.org/language/create-cli#index-entry-$PERCENT_SIGN*SUB-MAIN-OPTS) – acw Jun 06 '20 at 00:14
  • And thanks also for the video and presentation of Brian Duggan, very informative! – acw Jun 06 '20 at 00:22
  • "perhaps `PROCESS::<%SUB-MAIN-OPTS> = True;` could be added to docs" Doc currently suggests `my %*SUB-MAIN-OPTS = :named-anywhere;`. That sets the same variable. (But only for same process code called from scope containing the `my` (and any code that that code calls etc.).) Sounds like you're saying that that's not global enough for the way you've written your code? I've searched doc issues and don't see a report about that. Please consider [opening a doc issue](https://github.com/Raku/doc/issues/new) and explaining there. Thanks. Welcome to Raku. :) – raiph Jun 06 '20 at 01:03
  • No, just tested, using a slurpy array both work fine in the same scope as MAIN. There is a difference though. If I use a named array-reference `:h( :$hostnames ) where {$_.all ~~ URI::Host}` instead of a slurpy array, then ( `PROCESS::<%SUB-MAIN-OPTS> = True;` works and `my %*SUB-MAIN-OPTS = :named-anywhere;` doesn't. Don't know why yet. And thanks! – acw Jun 06 '20 at 16:32
  • Hi @acw. Thanks for following up. Are you putting the `my` *inside* the `MAIN`, or outside, before, it? And is it in the file executed by raku or in a module? – raiph Jun 06 '20 at 18:32
  • In both cases outside of MAIN, just before it. So in the same scope as MAIN. It's in a module. Inspired by the Cro CLI, I have a script file in bin that has nothing but:`#!/usr/bin/env raku use MyApp::Tools::CLI;` Within this CLI.pm6 there's my MAIN. – acw Jun 06 '20 at 22:37
  • @acw. It would be really helpful if you wrote that up as a separate SO, including a [MRE]. On its face it must be something to do with the distinction between a somewhat global global and a `PROCESS` global (as global as it gets). – raiph Jun 06 '20 at 22:45
  • 1
    No problem @raiph. Posted this question: [Alter how arguments are processed before they're passed to sub MAIN](https://stackoverflow.com/questions/62239232/alter-how-arguments-are-processed-before-theyre-passed-to-sub-main) – acw Jun 06 '20 at 23:37
  • 1
    Note that the Raku convention of repeating the named parameter works well in conjunction with the brace-expansion feature present in bash, zsh, etc. For the example at the end of the answer, this would work from those shells with the feature enabled: `cli-prog.raku --n={www.example.com,example.com,other.url,even-more.org}` – Mark Reed Dec 04 '20 at 19:43