views:

73

answers:

2

I have a function to search an array of objects for a matching value using the eq operator, like so:

sub find {
    my ( $self, %params ) = @_;
    my @entries = @{ $self->{_entries} };

    if ( $params{filename} ) {
        @entries = grep { $_->filename eq $params{filename} } @entries;
    }
    if ( $params{date} ) {
        @entries = grep { $_->date eq $params{date} } @entries;
    }
    if ( $params{title} ) {
        @entries = grep { $_->title eq $params{title} } @entries;
    }
    ....

I wanted to also be able to pass in a qr quoted variable to use in the comparison instead but the only way I can think of separating the comparisons is using an if/else block, like so:

if (lc ref($params{whatever}) eq 'regexp') {
    #use =~
} else {
    #use eq
}

Is there a shorter way of doing it? Because of reasons beyond my control I'm using Perl 5.8.8 so I can't use the smart match operator.

TIA

+4  A: 

This is Perl, so of course there's a CPAN module: Match::Smart. It works very similarly to Perl 5.10's smart match operator, only you type smart_match($a, $b) rather than $a ~~ $b.

You may wish to compare with the perlsyn documentation for 5.10 smartmatching as Match::Smart handles quite a few more situations.

Otherwise, I don't see anything wrong with:

sub smart_match {
    my ($target, $param) = @_;
    if (ref $param eq 'Regexp') {
        return ($target =~ qr/$param/);
    }
    else {
        return ($target eq $param);
    }
}

@entries = grep { smart_match($_->date, $params{date}) } @entries;
rjh
+1 for introducing me to a new module that I may just have to stealth-install at $work.
Ether
And now I know about Match::Smart. Ho-ho-ho.
darch
A: 

I don't know exactly what you want your end result to be, but you can do:

for my $field (qw(filename date title)) {
  my $p = $param($field};
  @entries = (ref($p) eq 'regexp')
    ? grep { $_->$field =~ /$p/ } @entries
    : grep { $_->$field eq $p }   @entries;
}

Alternatively, you can turn even your 'eq' comparisions into regular expressions, e.g.:

my $entry = "string to be equal to";
my $re = qr/^\Q$entry\E/;

and that simplifies the logic in the for loop.

runrig