Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl, How do I create a map/grep like subroutine?

Tags:

arguments

perl

I want to create a subroutine like grep {} @ or map {} @ that can handle code and/or boolean input. Somehow the internet doesn't have much info on this.

I tried to create the sub below, but it can't even handle the first test. I get the error Can't locate object method "BoolTest" via package "input" (perhaps you forgot to load "input"?) at C:\path\to\file.pl line 16..

How does this think it's an object? Am I not creating BoolTest correctly?

# Example senarios
BoolTest { 'input' =~ /test[ ]string/xi };
BoolTest { $_ =~ /test[ ]string/xi } @array;
BoolTest(TRUE);

# Example subroutine
sub BoolTest
{
   if ( ref($_[0]) == 'CODE') {
       my $code = \&{shift @_}; # ensure we have something like CODE
       if ($code->()) { say 'TRUE'; } else { say 'FALSE'; }
   } else {
       if ($_[0]) { say 'TRUE'; } else { say 'FALSE'; }
   }
}
like image 953
Eric Fossum Avatar asked Jan 29 '15 19:01

Eric Fossum


1 Answers

To pass a code reference, you can use the following:

sub BoolTest { ... }

BoolTest sub { 'input' =~ /test[ ]string/xi };
BoolTest sub { $_ =~ /test[ ]string/xi }, @array;
BoolTest(TRUE);

You could have the sub have a similar syntax to map BLOCK LIST, by using the &@ prototype.

sub BoolTest(&@) { ... }

BoolTest { 'input' =~ /test[ ]string/xi };
BoolTest { $_ =~ /test[ ]string/xi } @array;

This creates the same anonymous subs are earlier, so return, last, etc will behave the same as in the first snippet.

Note that the prototyped version won't accept

BoolTest(TRUE);

unless you override the prototype

&BoolTest(TRUE);

But you shouldn't expect your caller to do that. Based on your example, you could have them use the following, but a second sub might be better.

BoolTest { TRUE };
like image 166
ikegami Avatar answered Nov 15 '22 05:11

ikegami