Re: module location
by broquaint (Abbot) on Nov 07, 2003 at 15:27 UTC
|
Just do a require instead as use is a compile-time construct (as opposed to require which is done run-time)
require( shift @ARGV );
But as liz notes, that requires munging the module name for any module with a '::' seperator. Better yet, don't load the module at all and just make use of Module::Locate
use Module::Locate 'locate';
my $path = locate $ARGV[0];
| [reply] [d/l] [select] |
|
|
Tried installing Module::Locate using CPAN, but got these errors:
Module-Locate-1/lib/
Module-Locate-1/lib/Module/
Module-Locate-1/lib/Module/Locate.pm
Package seems to come without Makefile.PL.
(The test -f "/root/.cpan/build/Module-Locate-1/Makefile.PL" returne
+d false.)
Writing one on our own (setting NAME to ModuleLocate)
CPAN.pm: Going to build B/BR/BROQ/Module-Locate-1.tar.gz
Checking if your kit is complete...
Looks good
Writing Makefile for ModuleLocate
/usr/bin/perl "-Iblib/arch" "-Iblib/lib" Build.PL Build
Can't locate Module/Build.pm in @INC (@INC contains: blib/arch blib/li
+b /usr/lib/perl5/5.8.0/i386-linux-thread-multi /usr/lib/perl5/5.8.0 /
+usr/lib/perl5/site_perl/5.8.0/i386-linux-thread-multi /usr/lib/perl5/
+site_perl/5.8.0 /usr/lib/perl5/site_perl /usr/lib/perl5/vendor_perl/5
+.8.0/i386-linux-thread-multi /usr/lib/perl5/vendor_perl/5.8.0 /usr/li
+b/perl5/vendor_perl /usr/lib/perl5/5.8.0/i386-linux-thread-multi /usr
+/lib/perl5/5.8.0 .) at Build.PL line 1.
BEGIN failed--compilation aborted at Build.PL line 1.
make: *** [Build] Error 2
make: *** Waiting for unfinished jobs....
make: *** Waiting for unfinished jobs....
make: *** Waiting for unfinished jobs....
cp lib/Module/Locate.pm blib/lib/Module/Locate.pm
/usr/bin/make -j3 -- NOT OK
Running make test
Can't test without successful make
Running make install
make had returned bad status, install seems impossible
I was just going to try it, so it's not a big deal, but I thought I would let you know. | [reply] [d/l] |
|
|
Thanks for the heads-up, I've hopefully fixed that bug with the latest version (in anticipation of someone trying to install it ;). It also comes with a few other changes which should be useful to the folks who want to do module probing such as is_mod_loaded() and is_pkg_loaded().
| [reply] |
Re: module location
by liz (Monsignor) on Nov 07, 2003 at 15:29 UTC
|
That's because the assigment of $perl_module doesn't happen until runtime, while the use happens at compile time.
You basically have two options:
- Move assignement to compile time
my $perl_module;
BEGIN {$perl_module = shift};
eval "use $perl_module";
- Move loading of module to runtime
(my $filename = "$perl_module.pm") =~ s#::#/#g;
require $filename;
$perl_module->import;
The first has the disadvantage that you need to eval a string. If you can't trust the parameter input, that may be a security issue.
The latter has the disadvantage that you must convert the module name to a filename. But you need the original module name to be able to do the import().
Hope this helps.
Liz | [reply] [d/l] [select] |
|
|
This is driving me nuts - I don't understand why this doesn't work:
#!/usr/bin/perl -w
use strict;
my $perl_module;
BEGIN {
my $ct_args = @ARGV;
if ($ct_args != 1) {
print "\nUsage: pwhich_short <perl module name>\n\n";
print "Example: pwhich_short DBI\n\n";
exit;
}
$perl_module = shift;
};
eval "use $perl_module" or die "Can't find $perl_module: $!\n";
This code gets this error:
Can't find DBI:
That's it. Does this work for you? Any ideas?
Thanks. | [reply] [d/l] [select] |
|
|
I think you want to replace:
eval "use $perl_module" or die "Can't find $perl_module: $!\n";
by:
eval "use $perl_module";
die "Can't find $perl_module: $@\n" if $@;
Eval just returns whatever was returned by use, which to my knowledge is undefined (please someone correct me if I'm wrong).
You need to check whether $@ is non-empty after the eval().
Liz | [reply] [d/l] [select] |
|
|
Re: module location
by ferrency (Deacon) on Nov 07, 2003 at 15:24 UTC
|
"use" happens at compile time, but the $perl_module variable isn't initialized until run time, after the "use" statement has already executed. Actually you can't use a variable package name, but you can require it. Try this:
#!/usr/bin/perl -w
use strict;
my $perl_module = shift;
eval {require $perl_module} or die "Can't find $perl_module!";
Alan | [reply] [d/l] [select] |
|
|
I thought you had it, but not I get this error:
Can't find DBI! at ./test.pl line 4.
Here is the absolute path to the DBI.pm file:
/usr/lib/perl5/vendor_perl/5.8.0/i386-linux-thread-multi/DBI.pm
and the @INC path shows this in 'perl -V':
@INC:
/usr/lib/perl5/5.8.0/i386-linux-thread-multi
/usr/lib/perl5/5.8.0
/usr/lib/perl5/site_perl/5.8.0/i386-linux-thread-multi
/usr/lib/perl5/site_perl/5.8.0
/usr/lib/perl5/site_perl
/usr/lib/perl5/vendor_perl/5.8.0/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.8.0
/usr/lib/perl5/vendor_perl
/usr/lib/perl5/5.8.0/i386-linux-thread-multi
/usr/lib/perl5/5.8.0
What am I missing? Thanks for your help! | [reply] [d/l] [select] |
|
|
./test.pl DBI.pm
If you don't like that, you can change the eval to a string eval, which will interpolate the package name into a bareword before require sees it:
#!/usr/bin/perl -w
use strict;
my $perl_module = shift;
eval "require $perl_module" or die "Can't find $perl_module!";
This would be the more flexible solution, since it would handle things like ./test.pl DBD::PgSQL (assuming that makes sense... basically, any module with ::'s in it).
Alan | [reply] [d/l] [select] |
Re: module location
by BrowserUk (Patriarch) on Nov 07, 2003 at 16:22 UTC
|
perl -mDBI test.pl
would meet your needs?
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
Hooray!
Wanted!
| [reply] [d/l] |
|
|
It would, but how in test.pl can I tell that 'DBI' was specified on the command line? test.pl needs to know that.
I have to say I like your signature quote - "efficiency is intelligent laziness". I'm going to remember that one ;)
| [reply] |
|
|
The answer to that would depend on why the script needs to know that. Ie. What will the script do different?
I guess I'm having trouble trying to conceive of why you would make the module a command line argument rather than having it inside the script. I originally thought that you might have two or modules that offer the same interface, but different implementation. This would mean that the rest of the script wouldn't care which of the alternative modules was loaded, it would just use the exported entrypoints from whichever one was loaded.
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
Hooray!
Wanted!
| [reply] |
|
|
It would, but how in test.pl can I tell that 'DBI' was specified on the command line? test.pl needs to know that.
Yes, and this is Perl ;)
perl -MDBI -le'print for keys %INC'
Exporter.pm
Carp.pm
strict.pm
vars.pm
Config.pm
warnings/register.pm
warnings.pm
DynaLoader.pm
Exporter/Heavy.pm
DBI.pm
AutoLoader.pm
| [reply] [d/l] |
Re: module location
by jZed (Prior) on Nov 07, 2003 at 16:25 UTC
|
May I back up a minute and ask why you are wanting use of DBI to be conditional? Since DBI can work with or without compilation (see docs for DBI::PurePerl), under what circumstance would you want to not use it? I'm not saying there are no such circumstances, I'm just curious. | [reply] |
|
|
DBI was just an example of a module name. The script I'm working on will take in the name of any perl module and will tell you
1. if the module is installed on the system
2. if it is installed, what version ($VERSION) it is, and
3. if it is installed, exactly where on the system it
resides (absolute file name)
It's not rocket science - I'm sure others (like Broquaint above with Module::Locate) have probably already done this, but I'll post the code when I'm done. | [reply] [d/l] |
|
|
Well, for DBI, this tells you all three of those things:
perl -MDBI=9999
But good luck on a more general solution, seems like there have been some good suggestions for you.
| [reply] |
|
|
|
|
|
|
use Module::Locate 'locate';
die "Usage: $0 MODULE\n" unless @ARGV;
my $mod = shift @ARGV;
my $path;
if(eval{ require( $path = locate $mod ) }) {
die "$mod missing version number\n"
unless $mod->VERSION;
print "$mod version ", $mod->VERSION, " installed at $path\n";
} else {
die "$mod not installed\n";
}
| [reply] [d/l] |
Re: module location
by hmerrill (Friar) on Nov 07, 2003 at 17:33 UTC
|
Ok, here's the code - it's not the cleanest code, but it seems to work for the relatively few modules I've tried it with. I call it 'pwhich' which functions sort of like the 'which' command on Linux:
#!/usr/bin/perl -w
use strict;
my $perl_module;
BEGIN {
my $ct_args = @ARGV;
if ($ct_args != 1) {
print "\nUsage: pwhich <perl module name>\n\n";
print "Example: pwhich DBI\n\n";
exit;
}
$perl_module = shift;
};
eval "use $perl_module";
die "Can't find Perl module $perl_module!\n" if $@;
my $inc_key = "$perl_module.pm";
$inc_key =~ s!::!/!g;
print "inc_key = $inc_key\n";
my $abs_filename = $INC{$inc_key};
print "\n";
print "Module: $perl_module\n";
print "Location: $abs_filename\n";
open(IN,"<$abs_filename") || die "Can't open $abs_filename!";
my $version = "";
while (<IN>) {
if (/\s*\$[\w:]*VERSION\s*=[ "']*([0-9_\.]+)/i) {
$version = $1;
last;
}
}
close(IN);
print "Version: $version\n\n";
| [reply] [d/l] |
Re: module location
by jZed (Prior) on Nov 07, 2003 at 16:55 UTC
|
Perhaps this snippet from DBD::CSV's test.pl will help:
my $v;
eval {
require DBI;
$v->{DBI}= $DBI::VERSION;
require SQL::Statement;
$v->{SQL}= $SQL::Statement::VERSION;
require Text::CSV_XS;
$v->{CSV}= $Text::CSV_XS::VERSION;
require DBD::CSV;
$v->{DBD}= $DBD::CSV::VERSION;
};
if ($@) {
print "\n\nYOU ARE MISSING REQUIRED MODULES:\n\n";
print " DBI\n" unless $v->{DBI};
print " SQL::Statement\n" unless $v->{SQL};
print " Text_CSV\n" unless $v->{CSV};
exit;
}
print "USING:\n";
printf " %-20s %s\n",'OS', $^O;
printf " %-20s %s\n",'Perl', $];
printf " %-20s %s\n",'DBD::CSV', $v->{DBD};
printf " %-20s %s\n",'DBI', $v->{DBI};
printf " %-20s %s\n",'SQL::Statement', $v->{SQL};
printf " %-20s %s\n",'Text::CSV_XS', $v->{CSV};
| [reply] [d/l] |