hperange has asked for the wisdom of the Perl Monks concerning the following question:

Hello, Perl novice here; I have a data structure like that
my @rules = ( { name => 'name1', re => qr/regex1/, color => 'yellow', }, { name => 'name2', re => qr/regex2/, color => 'green', }, { name => 'default', re => qr/.*/, color => '', }, );
And I am trying to color the output of a system command. My code is working, but I wonder whether the below last 2 lines can be joined into a single statement:
#!/usr/bin/perl use strict; use warnings; use Term::ANSIColor; use List::Util qw(max sum first); ... $class = '...'; $color = first { $class =~ /$_->{'re'}/ } @rules; $color = $color->{'color'};
I am asking because I am not sure whether it's good practice that in the first line $color holds a reference to a hash, and in the next line $color holds a string. Thanks for your time.

Replies are listed 'Best First'.
Re: Data structure / hash reference question
by roboticus (Chancellor) on Apr 21, 2012 at 14:22 UTC

    hperange:

    I generally avoid that practice, as it's easy to get confused. Sometimes I want a shorthand variable for a member, like color, but also want to use the hashref, too. In that case, I normally have two variables $rColor and $color, where $rColor is the reference. This keeps them visually distinct, but related (to me, anyway). If I wasn't using the reference, I'd avoid the issue altogether by making a subroutine that simply returned the color:

    $class = '...'; $color = color_of($class); sub color_of { $class = shift; my $t = first { $class =~ /$_->{'re'}/ } @rules; return $color->{'color'}; }

    Having said all that, it really depends on usage. I occasionally find it more convenient to reuse the variable. In limited scope, it can often be clear and obvious enough to not warrant the extra effort:

    for my $foo (...) { my $color = first { $class =~ /$_->{'re'}/ } @rules; $color = $color->{'color'}; ... }

    With this bit, I'm setting up the variable at the top of the loop, so it's clear (to me) that the first line is simply an interim step. If the for body were longer, and I switched between the hash version and scalar version, it would be confusing. In this case, it would be nice if there were a simple way to do it in one go, like:

    my $color = ${first { $class =~ /$_->{'re'}/ } @rules}->{'color'};

    But if it exists, then I haven't found it.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      You were close :)

      my $class = 'regex1'; my $color = ( first { $class =~ /$_->{'re'}/ } @rules )->{ color }; + print "$color\n";

        stevieb:

        You'd think that as long as I've been toying around with perl, I'd've figured it out or stumbled across it by now.

        I tried several "obvious" things, none of which worked:

        $color = ${ ... }->{color}; $color = $${ ... }->{color}; $color = ${%{ ... }}{color};

        The parenthesis are a surprise to me, but I'm glad it's possible to avoid the two-step!

        ...roboticus

        When your only tool is a hammer, all problems look like your thumb.

        Thanks, this works :)