This question already has answers here:
How can I require an optional Perl module if installed?
(8 answers)
Closed 9 years ago.
I'm writing a small Perl script that depends on some modules that might be available, so during the installation I would have to check if everythings there. I could just write use some::module and see if an error comes up, but a short message like "You need to install some::module" would be more helpful for endusers.
I also could just search every directory in #INC, but as it's Perl, there has to be an easier way.
perl -MSome::Module -e ';'
Whoops, misread the question. I thought you wanted to know in a one-off instance, not discovering it in a recoverable manner. I always use something like this:
sub try_load {
my $mod = shift;
eval("use $mod");
if ($#) {
#print "\$# = $#\n";
return(0);
} else {
return(1);
}
}
Which you use like this:
$module = 'Some::Module';
if (try_load($module)) {
print "loaded\n";
} else {
print "not loaded\n";
}
How about:
die "Some::Module missing!" unless(eval{require Some::Module});
I have a little script that lists all the Perl modules on my system;
#!/usr/bin/perl
use ExtUtils::Installed;
my $instmod = ExtUtils::Installed->new();
foreach my $module ($instmod->modules()) {
my $version = $instmod->version($module) || "???";
print "$module -- $version\n";
}
Inside that foreach loop you might want to do some thing like;
my $match;
if ($module =~ /$match/) {
print "Found $match: $module\n";
}
I use something like this:
BEGIN {
my $module_name = shift; # #ARGV
our $module_exp = $module_name;
eval "use $module_name;";
}
$module_exp =~ s{::}{/}g;
foreach my $key ( grep { m/^$module_exp\./ } keys %INC ) {
print "$key => $INC{$key}\n";
}
But I use this more in the form of a korn shell function:
function wherperl
{
perl -M$1 <<EX_DOC
my \$module = '$1';
\$module =~ s/::/\\//g;
for ( keys %INC ) {
next unless m/^\$module\./;
print \$_ . ' => ' . \$INC{\$_} . "\n";
}
EX_DOC
}
I like to use the cpan utility:
% cpan -D YAML
YAML
-------------------------------------------------------------------------
YAML Ain't Markup Language (tm)
A/AD/ADAMK/YAML-0.70.tar.gz
/usr/local/perls/perl-5.10.0/lib/site_perl/5.10.0/YAML.pm
Installed: 0.68
CPAN: 0.70 Not up to date
Ingy dot Net (INGY)
ingy#cpan.org
This can be a little slow since it has to connect to a CPAN mirror to fetch some of the data, but I also have a local CPAN mirror. :)
Related
I have found this:
my $rc = eval
{
require Term::ReadKey;
Term::ReadKey->import();
1;
};
if($rc)
{
# Term::ReadKey loaded and imported successfully
...
}
But that does not work for packages defined inside other modules like:
{
package Hi::Test;
}
my $rc = eval{ require Hi::Test };
$rc is false here.
How can I check that 'Hi::Test' is available?
I'm assuming there is actually something happening in that package, and not just an empty block.
The following code checks if there are any entries in the symbol table for that package. It's dirty, but it works as long as there are subs or package variables registered.
{
package Hi::Test;
sub foo;
}
my $rc = eval{ require Hi::Test };
if (! $rc) {
$rc = do {
no strict;
*stash = *{"Hi::Test::"};
scalar keys %stash;
}
}
print $rc;
It will print 1.
You want something like defined(*Hi::Test::), except that simply mentioning *Hi::Test:: creates the package.
$ perl -E'
say defined(*Hi::Test::) ? "exists" : "doesn'\''t exist";
'
exists
By using symbolic references, you avoid that problem.
$ perl -E'
{ package Hi::Test }
say defined(*{"Hi::Test::"}) ? "exists" : "doesn'\''t exist";
say defined(*{"Hi::TEST::"}) ? "exists" : "doesn'\''t exist";
'
exists
doesn't exist
Putting that code in a sub to makes things cleaner.
$ perl -E'
use strict;
use warnings;
sub test_for_package {
my ($pkg_name) = #_;
$pkg_name .= "::";
return defined(*$pkg_name);
}
{ package Hi::Test }
say test_for_package("Hi::Test") ? "exists" : "doesn'\''t exist";
say test_for_package("Hi::TEST") ? "exists" : "doesn'\''t exist";
'
exists
doesn't exist
Note that creating the package Foo::Bar::Baz also creates the packages Foo and Foo::Bar.
I'm a little rusty on this, but I think your require will be failing regardless - this errors:
#!/usr/bin/perl
{
package Hi::Test;
sub foo {
print "bar\n";
}
}
{
package main;
require Hi::Test;
}
This errors - it can't find it #INC (because it isn't in #INC). Both use and require specifically tell perl to "go out and find a module file"
But you can still call 'foo' with:
Hi::Test::foo();
So you can't test the loading of the module with eval nor can you check %INC .
But what you can do is check %Hi:::
use Data::Dumper;
print Dumper \%Hi::;
print Dumper \%Hi::Test::;
Which gives us:
$VAR1 = {
'Test::' => *{'Hi::Test::'}
};
$VAR1 = {
'foo' => *Hi::Test::foo
};
So we can:
print "Is loaded" if defined $Hi::{'Test::'}
UPDATED
I have found this clue:
my $module = *main::;
my #sub_name = split '::', $full_name;
while( each #sub_name ) {
$module = $$module{ $sub_name[$_].'::' };
}
print "Module is available" if $module;
In compare to this answer it does not create additional variable in global stash
If I have Perl code which usees a lot of modules, is there a fast and easy way to find out if some of this modules are not pure Perl modules?
#DynaLoader::dl_modules contains the list of XS modules loaded.
perl -MSome::Module1 -MSome::Module2 -M... \
-MDynaLoader -E'say for sort #DynaLoader::dl_modules;'
Or if you wanted to write it as a script:
# Usage: script Some::Module1 Some::Module2 ...
use 5.010;
use DynaLoader qw( );
while (defined($_ = shift(#ARGV))) {
s{::}{/}g;
$_ .= ".pm";
require $_;
}
say for sort #DynaLoader::dl_modules;
Of course, nothing's stopping you from putting it in an existing script either.
use 5.010;
use DynaLoader qw( );
END { say for sort #DynaLoader::dl_modules; }
This looks like a job for what I call a "blowup sensor". You could just boobytrap the hooks, by putting this at the top of the first module:
BEGIN {
require Carp; #Does the stack stuff
# Fool Perl into thinking that these are already loaded.
#INC{ 'XSLoader.pm', 'DynaLoader.pm' } = ( 1, 1 );
# overload boobytrapped stubs
sub XSLoader::load { Carp::confess( 'NOT Pure Perl!' ); }
sub DynaLoader::bootstrap { Carp::confess( 'NOT Pure Perl!' ); }
}
If you have to try which modules in your Perl prog is not installed yet on your machine. You can do it like this:
use ExtUtils::Installed;
my $installed = ExtUtils::Installed->new();
my #miss;
foreach $module ($installed->modules()){
#miss = $installed->validate($module);
}
print join("\n", #miss);
Actually i m using one perl script to prepare Readme txt for my builds. in that script i used
foreach $line (<LOG>)
{
if(length(trim($line))>0)
{
$line=trim($line);
$line=~ s/[\r]//gs;
if(rindex($line,'#')!=-1)
{
$icut=substr($line,0,index($line,']'));
$icut2=substr($icut,index($icut,'#')+1,length($icut));
}
push(#issue,$icut2);
it's fetching correct issue no but when the situation comes like
[I#1303350], [I#1270918],[I#1312521] Updated Physical Confirmation Template based on CO
then it's fetching only one issue no not all issue i that same line. so i modified my code like
foreach $revno(<REV>)
{
if(length(trim($revno))>0)
{
$revno=trim($revno);
$revno=~ s/[\r]//gs;
if(rindex($revno,'#')!=-1)
{
$revcut=substr($revno,0,rindex($revno,']'));
print "$revcut\n";
$revcut1=substr($revcut,index($revcut,'#')+1,length($revcut));
}
}
push(#issue,$revcut1);
now it's fetch it all revision no but output is like 1312588,1303350], [I#1270918],[I#1312521 but i want to remove the # [ ] I only but not , so pls tell me how can i parse this through regex.
This can be done without regular expressions: Transliterate: tr///
use warnings;
use strict;
my $s = '1312588,1303350], [I#1270918],[I#1312521';
$s =~ tr/ ][#I//d;
print "$s\n";
__END__
1312588,1303350,1270918,1312521
You can do it like this:
echo "[I#1303350], [I#1270918],[I#1312521]" | perl -lnwe "print for m/#(\d+)/g"
This works for me:
my #issues = $line_of_data =~ m/#(\d+)/g;
And if you want commas, it's far easier to do this:
my $with_commas = join( ', ', #issues );
And you still have the individual issues numbers as "atoms" of data.
I'm sorry if this had been asked, but I found it hard to search for.
I use Perl 5.12 locally but some of our machines use Perl 5.8.8 and they won't be updated for the time being.
For auditing I use 'say' on platform 5.12.
I've written a simple function to implement say on 5.8.8 but I don't want to use it on 5.12.
Is there a way to only use my say function on the older version of Perl and use the 'builtin' version of say on 5.12?
You can use the $^V special variable to determine the version of the Perl interpreter:
BEGIN {
if ($^V ge v5.10.1) { # "say" first appeared in 5.10
require feature;
feature->import('say');
}
else {
*say = sub { print #_, "\n" }
}
}
This should work:
BEGIN{
no warnings 'once';
unless( eval{
require feature;
feature->import('say');
1
} ){
*say = sub{
print #_, "\n";
}
}
}
Before posting my question to the ActiveState forum, I'd like to try luck here :)
I'm trying to convert a simple script of mine to .exe file using Perlapp (version 8.1). The Perl script works fine and it seems Perlapp also did its job successfully.
But the converted .exe file has some weird behavior, which, I believe, must be related to utf-8 encoding. For example, the Perl script would yield the result like:
hàn huáng zhòng sè sī qīng guó
But running the executable file would give me only this:
h hu zh s s q gu
I've already configured Perlapp so that utf8.pm is explicitly added but the problem just refuses to go away. I've tried something else. For example,
binmode DATA, ":utf8";
and
">:encoding(utf8)"
but without any luck;
Can anyone kindly give me some hint as to what might be the reason? Thanks like always :)
I can post the whole code here but it seems unnecessary so I just paste some snippets of the code that I think is relevant to the problem:
use utf8;
%zidian = map {chomp;split/\s+/,$_,2} <DATA>;
open my $in,'<:utf8',"./original.txt";
open my $out,'>:utf8',"./modified.txt";
if ( $code~~%zidian) {
$value = lc$zidian{$code};
}
__DATA__
3400 Qiū
3401 TIǎN
3404 KUà
3405 Wǔ
And one more thing, I'm running ActivePerl 5.10.0.on Windows XP (Chinese Version) and the script is saved as utf-8 encoding without BOM. PerlApp cannot handle a script that has BOM.
Edit
If I were to give a workable snippet, then I suppose it's like giving the whole code because I'm using three inter-connected sub-routines, which I take with some modifications from Lingua::han::Pinyin module and Lingua::han::Utils module.
#! perl
# to make good vertical alignment,
# set font family to SonTi and font size to Four(12pts)
use utf8;
sub Unihan {
my $hanzi = shift;
my #unihan = map { uc sprintf("%x",$_) } unpack ("U*", $hanzi);
}
sub csplit {
my $hanzi = shift;
my #return_hanzi;
my #code = Unihan($hanzi);
foreach my $code (#code) {
my $value = pack("U*", hex $code);
push #return_hanzi, $value if ($value);
}
return wantarray ? #return_hanzi : join( '', #return_hanzi );
}
%zidian = map {chomp;split/\s+/,$_,2} <DATA>;
sub han2pinyin {
my $hanzi = shift;
my #pinyin;
my #code = Unihan($hanzi);
foreach $code (#code) {
if ( $code~~%zidian) {
$value = lc$zidian{$code};
}
else {
$value = " ";
}
push #pinyin, $value;
}
return wantarray ? #pinyin : join( '', #pinyin );
}
open $in,'<:utf8',"./original.txt";
seek $in, 3,0;
open $out,'>:utf8',"./modified.txt";
while(<$in>){
s/(.{18})/$1\n/g;
push #tmp, $_;
}
foreach (#tmp){
my #hanzi;
my #pinyin;
#hanzi = csplit($_);
my $hang = join "", #hanzi;
#pinyin = han2pinyin($hang);
for ( my $i = 0; $i < #hanzi && $i < #pinyin; ++$i ) {
if ( $hanzi[$i] =~ /[\xEFBC8C]|[\xE38082]|[\xEFBC81]|[\xEFBC9F]|[\xE2809C]|[\xE2809D]|[\xEFBC9A]/ ) {
splice(#pinyin, $i, 0," ");
}
}
printf $out "%-7s" x #pinyin, #pinyin;
print $out "\n";
printf $out "%-6s" x #hanzi, #hanzi;
print $out "\n";
}
__DATA__
3400 Qiū
3401 TIǎN
3404 KUà
3405 Wǔ
ActiveState hasn't given me any help yet. Whatever. Now I've figured out a workaround for my problem and this workaround looks very weird.
First I added some otherwise useless utf-8 encoded characters to my DATA section, like the following:
__DATA__
aardvark 'ɑ:dvɑ:k
aardwolf 'ɑ:dwulf
aasvogel 'ɑ:sfәugәl
3400 Qiū
3401 TIǎN
3404 KUà
3405 Wǔ
And then I removed the use utf8; pragma from my script;
and then I removed the utf8 flag from the following line of code:
open $out,'>:utf8',"./modified.txt";
Now it becomes
open $out,'>',"./modified.txt";
But I had to let the following line of code unchanged:
open $in,'<:utf8',"./original.txt";
Then everything was okay except that I'd receive "wide characters in print" warnings. But I added another line of code:
no warnings;
And then I Perlapped my script and everything worked fine :)
This is really strange. I'm suspecting this problem is somehow OS specific. It's also quite likely that there's something wrong with my Windows system. And I also tried Perl2exe and the compiled executable gave me some "memory 0010c4 cannot be read" error. Whatever. My problem is somehow fixed by myself :)