Hello Axel,
thanks for your work.
on 10/30/01 08:21 AM, Axel Rose at [EMAIL PROTECTED] wrote:
> The task looked not that difficult but as you can see from the code
> below it got larger and larger.
Your code seems to be involved, so I cleaned it up.
Save attached file as Droplet, then try it.
If you don't like my version, please ignore this message.
Best regards,
---
Keitarou Miyazaki
Nagoya, Japan
#!perl -w
use strict;
package ModuleFinder;
my $DIRSEP = $^O =~ /^Mac/
? ':' # mac
: $^O =~ /^win/i
?
'\\' # win
: '/'; # default: unix, linux, *bsd...
=item $obj = CLASS->new($source_file);
=cut
sub new {
my $pkg = shift;
my
$sourcefile = shift or die "No input file.";
my $self = bless {'FILE' =>
$sourcefile, # source file
'INC' => {}, #
required modules
'FILE_VISITED' => {} # processed modules
}, $pkg;
local %INC = (); # preserve original %INC
#
Change directory to souce file's directory.
#
my $pwd = `pwd`; chop $pwd;
my $sep = quotemeta($DIRSEP);
$sourcefile =~ m/^(.*$DIRSEP)[^$DIRSEP]+$/;
my
$sourcedir = $1 || $pwd;
$sourcedir .= $DIRSEP unless $sourcedir =~ /$DIRSEP$/;
chdir( $sourcedir ) or die $!;
# Fetch required modules.
#
$self->_process_file($sourcefile);
foreach my $module (keys %INC) {
if
($module eq $INC{$module}) {
# This module is located in source file's
directory.
# Fix the file name to absolute path name.
$INC{$module} = $sourcedir . $INC{$module};
}
}
%{$self->{'INC'}} =
%INC;
# Back to original directory.
#
chdir($pwd);
$self
}
=item
$obj->show_modules;
=cut
sub show_modules {
my $self = shift;
foreach my
$module (sort keys %{$self->{'INC'}}) {
my $fixed = $module;
$fixed =~
s|/|$DIRSEP|g;
print "'$fixed' => $self->{INC}->{$module}\n";
}
}
=item
%module_list = $obj->modules;
=cut
sub modules {
my $self = shift;
my %ret =
();
foreach my $module (keys %{$self->{'INC'}}) {
my $fixed = $module;
$fixed =~ s|/|$DIRSEP|g;
$ret{$fixed} = $self->{'INC'}->{$module};
}
%ret
}
sub _process_file {
my $self = shift;
my $file = shift;
=for debug
print "FILE: $file\n";
=cut
local *FILE;
open FILE, $file or die "cannot
open file '$file'";
my $skip_pod_section = 0;
while ( <FILE> ) {
last
if /^__END__/;
if ( ! $skip_pod_section and /^=/ ) {
$skip_pod_section = 1; next;
}
if ( $skip_pod_section and /^=cut/ )
{
$skip_pod_section = 0; next;
}
next if
$skip_pod_section;
if (/\brequire\b.+;/) {
$self->_eval_require_line($_);
} elsif (/^\s*use.+;/o) {
$self->_eval_use_line($_);
}
}
close FILE;
$self->{'FILE_VISITED'}->{$file}++;
# process required modules
foreach my
$module (keys %INC) {
$file = $INC{$module};
$self->_process_file($file) unless exists $self->{'FILE_VISITED'}->{$file};
}
}
sub _eval_require_line {
my $self = shift;
local $_ = shift;
if
($self->_not_understandable($_)) {
warn "Skipping: $_";
return;
}
local $^W = 0; # suppress warnings about redefining subroutines
eval $_;
}
sub _eval_use_line {
my $self = shift;
local $_ = shift;
next if
/^\s*use\s+constant/o; # avoid annoying messages on some module...
# fill %INC
local $^W = 0; # suppress warnings about redefining subroutines
eval( $_ );
#
warn "$@ in line '$_'" if $@;
# TODO: what, if "use" statement spans multiple
lines ...
}
sub _not_understandable {
my $self = shift;
local $_ = shift;
return 1 if /require\s+\d/; # skip "require <perl-version>"
return 1 if /
#\s*require/; # skip comments
return 1 if /require\s+'*"*(\$|.+\/\$)'*"*/; #
we cannot know the content of a file name variable ...
return 1 if
/eval.+require/; # ignore modules if exception handling is already included
return
1 if /\$require/; # keep regexp understandable
# some particular difficult sample
lines:
# require IO::Socket::UNIX if ($^O ne 'epoc');
# { local $@;
require Carp::Heavy; } # XXX fix require to not clear $@?
# do { require Carp;
Carp::croak("Can't export symbol: $type$sym") };
# Carp::croak("$pkg $wanted
required--this is only version $version$file")
#
($pack,$file,$line,$sub,$hargs,undef,$eval,$require) = @a;
# eval { local
$SIG{__DIE__}; require $filename };
# require '$optionRequire{$option}'
#
eval "require Term::Rendezvous;" or die;
# require "File/Spec/$module.pm";
return 0;
}
package main;
my $m = new ModuleFinder $ARGV[0];
$m->show_modules;
# or you can do
# use Data::Dumper;
# my %modules =
ModuleFinder->new($ARGV[0])->modules;
# print Dumper \%modules;
__END__