0

This should be rather trivial, but I cannot figure it out on my own. Having the code below, are there any ways to get rid of many invocations of dirname(rel2abs($0))?

package Foo;

use File::Basename;
use File::Spec::Functions qw/rel2abs/;
use Carp qw/croak/;
use 5.010;

use constant BAR_NAMES => {
    WATER => dirname(rel2abs($0)) . '/../data/water.png',
    FIRE => dirname(rel2abs($0)) .'/../data/fire.png',
    GRASS => dirname(rel2abs($0)) .'/../data/grass.png'#,
    #and so on
};

sub get {
    my ($self, $name) = (shift, shift);
    if (exists BAR_NAMES->{$name}) {
        #return some calculated data based on $name value
    } else {
        croak("Constant `$name` is not declared.");
    }
};

1;

Thank you.

4

4 回答 4

6

You could roll it in a map:

use constant BAR_NAMES =>
{
   map { uc( $_ ) => dirname(rel2abs($0)) . "/../data/$_.png" }
     qw< water fire grass >
};

If I am not mistaken, the dirname should not be necessary:

use constant BAR_NAMES =>
{
   map { uc( $_ ) => rel2abs("$0/../data/$_.png") }
     qw< water fire grass >
};
于 2013-09-11T14:59:56.903 回答
5

On top of the great existing answers, there's also

use constant PROJ_ROOT => dirname(rel2abs($0)) . '/..';

use constant BAR_NAMES => {
    WATER => PROJ_ROOT.'/data/water.png',
    FIRE  => PROJ_ROOT.'/data/fire.png',
    GRASS => PROJ_ROOT.'/data/grass.png',
};

and

use FindBin qw( $RealBin );

use constant BAR_NAMES => {
    WATER => "$RealBin/../data/water.png",
    FIRE  => "$RealBin/../data/fire.png",
    GRASS => "$RealBin/../data/grass.png",
};
于 2013-09-11T15:18:07.957 回答
3
my $dirname;
BEGIN { $dirname = dirname(rel2abs($0)); }

use constant BAR_NAMES => {
    WATER => $dirname . '/../data/water.png',
    FIRE => $dirname .'/../data/fire.png',
    GRASS => $dirname .'/../data/grass.png'#,
    #and so on
};

You need a BEGIN block because any expression in a use statement is evaluated at compile time.

于 2013-09-11T14:58:44.710 回答
3
use constant BAR_NAMES => do {
    my $dirname = dirname(rel2abs($0));
    {
        WATER => $dirname . '/../data/water.png',
        FIRE => $dirname .'/../data/fire.png',
        GRASS => $dirname .'/../data/grass.png'#,
        #and so on
    }
};
于 2013-09-11T15:02:46.113 回答