tags:

views:

192

answers:

3

Hi Everyone,

I'm trying to get a block of code down to one line. I need a way to get the number of items in a list. My code currently looks like this:

# Include the lib directory several levels up from this directory
my @ary = split('/', $Bin);
my @ary = @ary[0 .. $#ary-4];
my $res = join '/',@ary;
lib->import($res.'/lib');

That's great but I'd like to make that one line, something like this:

lib->import( join('/', ((split('/', $Bin)) [0 .. $#ary-4]))  );

But of course the syntax $#ary is meaningless in the above line.

Is there equivalent way to get the number of elements in an anonymous list?

Thanks!

PS: The reason for consolidating this is that it will be in the header of a bunch of perl scripts that are ancillary to the main application, and I want this little incantation to be more cut & paste proof.

Thanks everyone

There doesn't seem to be a shorthand for the number of elements in an anonymous list. That seems like an oversight. However the suggested alternatives were all good.

I'm going with:

lib->import(join('/', splice( @{[split('/', $Bin)]}, 0, -4)).'/lib');

But Ether suggested the following, which is much more correct and portable:

my $lib = File::Spec->catfile(
                realpath(File::Spec->catfile($FindBin::Bin, ('..') x 4)),
               'lib');
lib->import($lib);
+2  A: 

Check the splice function.

Igor Krivokon
Thank you but it doesn't work. `splice( split('/', $Bin), -4)` gives an error: Type of arg 1 to splice must be array (not split). Splice seems to want an ACTUAL array.
NXT
A hack: you can use @{[split...]}. Effectively, it will create an array, take its reference and then dereference it. Also, note: you need both offset and length in splice: 0, -4.
Igor Krivokon
@IK: Yes, including both the offset and length was my final problem.
NXT
+1  A: 

You can manipulate an array (such as removing the last n elements) with the splice function, but you can also generate a slice of an array using a negative index (where -1 means the last element, -2 means the second to last, etc): e.g. @list = @arr[0 .. -4] is legal.

However, you seem to be going through a lot of backflips manipulating these lists when what you seem to be wanting is the location of a lib directory. Would it not be easier to supply a -I argument to the perl executable, or use $FindBin::Bin and File::Spec->catfile to locate a directory relative to the script's location?

use strict;
use warnings;

use Cwd 'realpath';
use File::Spec;
use FindBin;

# get current bin
# go 4 dirs up,
# canonicalize it,
# add /lib to the end
# and then "use" it

my $lib = File::Spec->catfile(
                realpath(File::Spec->catfile($FindBin::Bin, ('..') x 4)),
               'lib');
lib->import($lib);
Ether
Thank you. See other response on why splice doesn't work. I've tried negative indices on the slice like you show but get no output at all. I'm already using FindBin::Bin to get the script dir, and File::Spec doesn't seem to do anything useful for me (would be nice if updir() took an argument so you could go up more than one directory.
NXT
@NXT: the "usual" way of going up directories in the filesystem is by using Cwd's `realpath` to canonicalize a path using `..`.
Ether
@Ether: thanks, I get it now. I didn't know that. In this case I will take conciseness over correctness. But I'm making a note of this for the future.
NXT
+1  A: 
lib->import(join('/', splice(@{[split('/', $bin)]}, 0, -4)).'/lib');
pdehaan
Edit, sorry for my stupid comment, I read your code wrong. This is the answer.
NXT
This should work as-is, splice with three arguments is splice(array,offset,length) - the 0 specifies the beginning, the -4 means (array length-4).Someone else mentioned that 0 .. -4 is legal. While true, you need to consider what that means to perl: 'count up from 0 to -4' (not very meaningful).
pdehaan