File-FindLib
view release on metacpan or search on metacpan
package File::FindLib;
use strict;
use File::Basename qw< dirname >;
use File::Spec::Functions qw< rel2abs catdir splitdir >;
use vars qw< $VERSION >;
my $Pkg= __PACKAGE__; # Our class name (convenient to use in messages)
BEGIN {
$VERSION= 0.001_004;
}
return 1; # No run-time code below; just 'sub's and maybe BEGIN blocks
sub import {
my( $class, @args )= @_;
if( 1 == @args ) {
my( $find )= @args;
return LookUp(
-from => ( caller )[1],
-upto => $find,
-add => $find,
);
} else {
die "Too many arguments to 'use $Pkg'. Not yet supported.\n";
}
}
sub LookUp {
my %args= @_;
my $from= rel2abs( $args{-from} );
my $upto= $args{-upto};
my $add= $args{-add};
warn "$Pkg finds no $from; perhaps chdir()ed before 'use $Pkg'?\n"
if ! -e $from && $^W;
if( -l $from ) {
$from= rel2abs( readlink($from), dirname($from) );
}
my $dir= $from;
$dir= dirname( $dir )
if ! -d _;
while( 1 ) {
my $find= catdir( $dir, $upto );
if( -e $find ) {
my $path= catdir( $dir, $add );
if( -d $path ) {
require lib;
lib->import( $path );
return $path;
}
my $ret= require $path;
UpdateInc( $path );
return $ret;
}
my $up= dirname( $dir );
die "$Pkg can't find $find in ancestor directory of $from.\n"
if $up eq $dir;
$dir= $up;
}
}
# Set $INC{'My/Mod.pm'} after loading 'lib/My/Mod.pm';
# so "use File::FindLib 'lib/Mod.pm'; use Mod;" doesn't load it twice.
sub UpdateInc {
my( $path )= @_; # Path to module file.
my $base= $path; # Path minus ".pm"; parts that go into package name.
return 0 # If no .pm on end, "use Bareword" wouldn't find it.
if $base !~ s/[.]pm$//;
my @parts= grep length $_, splitdir( $base ); # Potential pkg name parts.
my @names; # Above minus leading parts that aren't barewords.
unshift @names, pop @parts # Include last part until find...
while @parts && $parts[-1] =~ /^\w+$/; # ...a non-bareword.
EDGE:
for my $o ( 0 .. $#names ) { # Strip shortest prefix that leaves a pkg.
next # "use Foo::123" works but "use 123::Foo" wouldn't.
if $names[$o] =~ /^[0-9]/;
my $stab= \%main::;
my @pkg= @names[ $o..$#names ];
for my $name ( @pkg ) { # Defined package? No autovivification.
$stab= $stab->{$name.'::'};
next EDGE
if ! $stab || 'GLOB' ne ref \$stab;
}
my $mod= join '/', @pkg; # @INC always uses '/'; no catdir()
$INC{"$mod.pm"} ||= $INC{$path};
return 1;
}
return 0;
}
__END__
=head1 NAME
File::FindLib - Find and use a file/dir from a directory above your script file
=head1 SYNOPSIS
use File::FindLib 'lib';
Or
use File::FindLib 'lib/MyCorp/Setup.pm';
=head1 DESCRIPTION
File::FindLib starts in the directory where your script (or library) is
located and looks for the file or directory whose name you pass in. If it
( run in 0.591 second using v1.01-cache-2.11-cpan-e1769b4cff6 )