package r; use strict; tie @ARGV, 'r::Tie::RecursiveARGVArray', @ARGV; sub import { } package r::Tie::RecursiveARGVArray; use Tie::Array; use base 'Tie::Array'; use File::Spec; sub TIEARRAY { my ($classname,@init) = @_; bless [@init], $classname; } sub FETCH { my ($self, $index) = @_; $self->_ReplaceDirs($index,$index); $self->[$index]; } sub FETCHSIZE { my ($self) = @_; scalar @$self; } sub STORE { my ($self, $index, $value) = @_; $self->[$index] = $value; } sub STORESIZE { my ($self, $count) = @_; $#$self = $count - 1; } sub SPLICE { my ($self,$offset,$length,@list) = @_; $self->_ReplaceDirs($offset,$offset+$length-1); splice(@$self,$offset,$length,@list); } sub POP { my ($self,$item) = @_; $self->_ReplaceDirs(-1,-1); pop(@$self); } sub _ReplaceDirs { my ($self, $fromindex, $toindex) = @_; # as long as the index range contains directories, substitute the directory contents my $recursionguard = 0; while (my @indices = grep { -d $self->[$_] } ($fromindex..$toindex) and $recursionguard++ < 10000) { my $index = $indices[0]; opendir DIR, $self->[$index] or do { warn "Cannot traverse directory $self->[$index]: $!\n"; splice(@$self, $index, 1, ()); # remove the bad-apple next; }; my @contents = readdir DIR or do { warn "Cannot read directory $self->[$index]: $!\n"; splice(@$self, $index, 1, ()); # remove the bad-apple closedir DIR or warn "Cannot close directory $self->[$index] (weird): $!\n"; next; }; closedir DIR or warn "Cannot close directory $self->[$index] (weird): $!\n"; # if there is any portable way to do this... I'd like to hear it! @contents = grep !/^\.{1,2}$/, @contents; # convert directory contents to paths by prepending the directory. # even be super nice about using catfile or catdir, appropriately @contents = map { my $asfile = File::Spec->catfile( $self->[$index], $_ ); -f $asfile ? $asfile : File::Spec->catdir( $self->[$index], $_ ); } @contents; # replace directory with its contents splice(@$self, $index, 1, @contents); } } 1;