Skip Menu |

This queue is for tickets about the Keyword-Declare CPAN distribution.

Report information
The Basics
Id: 131483
Status: resolved
Priority: 0/
Queue: Keyword-Declare

People
Owner: Nobody in particular
Requestors: perl [...] toby.ink
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: (no value)
Fixed in: (no value)



Subject: separators for arrays
The documentation includes the following example: keyword tryall (Block @blocks) {...} Which would accept the following syntax: tryall { ... } { ... } { ... }; But what about this syntax: tryall { ... }, { ... }, { ... }; Or even this? tryall 1 { ... }, 2 { ... }, 3 { ... }; The last two examples are pretty hard to implement with Keyword::Declare.
Subject: Re: [rt.cpan.org #131483] separators for arrays
Date: Thu, 16 Jan 2020 06:14:27 +0000
To: bug-Keyword-Declare [...] rt.cpan.org
From: Damian Conway <damian [...] conway.org>
Hi Toby, Thank-you for pointing out the current infelicities of implementing these entirely reasonable cases. Though I'm not entirely convinced that "pretty hard" is a entirely fair descriptor. ;-) For example, here's a reasonably straightforward implementation for that final "comma-separated list of numbered blocks" example: use Keyword::Declare; keyword tryall (Num|Block|Comma @args) { # Check that the args are in num/block/comma sequence... for (my $i=0; $i < @args; $i+=3) { return "BEGIN{ die 'Syntax error in tryall' }" if $args[$i] !~ /\d/ || $args[$i+1] !~ /^\{/ || $i+2 < @args && $args[$i+2] !~ /,/ } # Build the replacement code... my @num = grep /\d/, @args; my @blk = grep /\{/, @args; return join '//', map { "eval { say 'Trying $num[$_]'; $blk[$_] } " } 0..$#num; } # Now test... tryall 1 { say 'one'; die }, 2 { say 'two'; die }, 3 { say 'three'; die }, 4 { die }, 5 { say 'five' }, 6 { say 'six' } Admittedly, though that's not exactly "hard" to implement, it's also not nearly as easy and declarative as I'd like it to be. Obviously, the first step is to add a :sep attribute on keyword parameters, so that syntaxes like your simple list of comma-separated (un-numbered) blocks could be specified as: keyword tryall (Block @blocks :sep(',')) { return join '//', map { "eval $_ " } @blocks; } I will certainly look at doing that. But for a comma-separated list of numbers-then-blocks, we're rapidly moving into a realm where a keyword's parameter list has to be as powerful as a full grammar...which I'm frankly nervous about tackling. Thinking about it further, I realized that the key to simplifying this particular case (and, I suspect, most others too) lies in providing the ability to specify parameter types that match compound elements (such as a number followed by a block) and which then allow us to extract those individual elements, preferably by name. To that end, I'm going to look at possibly supporting regexes (including keytyped named regexes) that include named captures. When a keyword detects an argument using a regex (or keytype), it will return that argument as an object, rather than as a simple string. That object will have a stringification overloading that simply returns the entire match (as currently), but will also have a hash-lookup operator that returns the various named captures the regex made (and, I suppose, an array-lookup operator to return numbered captures as well). So then we could simply write: keytype NumThenBlock is / (?<num> (?&PerlNumber) ) (?&PerlOWS) (?<block> (?&PerlBlock) ) /x; keyword tryall (NumThenBlock @blocks :sep(',')) { return join '//', map { "eval { say 'Trying $_->{num}'; $_->{block} } " } @blocks; } Please have a think about this proposed solution yourself and let me know if you feel it would adequately meet your future keyword-declaring needs. :-) If so, I will look at releasing a new version of the module as soon as I can implement these extra features. Damian
Show quoted text
> keyword tryall (Num|Block|Comma @args) {
Now, that's smart. I don't know why I didn't think of that. But yes, ":sep" seems like a good solution.
Subject: Re: [rt.cpan.org #131483] separators for arrays
Date: Mon, 20 Jan 2020 05:18:11 +0000
To: bug-Keyword-Declare [...] rt.cpan.org
From: Damian Conway <damian [...] conway.org>
Show quoted text
> Now, that's smart. I don't know why I didn't think of that.
Probably because you're Lawful Good, as opposed to Chaotic Neutral. ;-) Show quoted text
> But yes, ":sep" seems like a good solution.
The latest release (0.001015), which I just now uploaded, supports both the :sep attribute and also named captures within type regexes. Moreover, specifying a :sep attribute causes each repetition to also remember its trailing separator as an extra named capture. So my example solution can now be even cleverer: keytype NumThenBlock is / (?<num> (?&PerlNumber) ) (?&PerlOWS) (?<block> (?&PerlBlock) ) /x; keyword tryall ( NumThenBlock @blocks :sep(',') ) { return join '//', map { "eval { say 'Trying $_->{num} up to $_->{':sep'}'; do $_->{block} } " } @blocks; } Thanks again for the inspiration to add these two useful features. Damian