Why does this halt my perl application package 'not registered for warnings' - perl

I am working with an in house web gateway frame work in perl. And now I am trying to use Image::Magick::Thumbnail to create a thumbnail image.
But if I have this line
my ($thumb, $x, $y) = Image::Magick::Thumbnail::create($image, 50);
I get the following error.
package 'Image::Magick::Thumbnail' not registered for warnings
I have tracked this down to line 313 of warnings.pm
Croaker("package '$category' not registered for warnings")
But I'm not sure why this halts my program any ideas?

use warnings::register; creates a warnings category with the same name as the current package.
Image::Magick::Thumbnail checks if warnings of category Image::Magick::Thumbnail are enabled, but doesn't actually create such a category using use warnings::register;.
The line is there in the code, but it's commented out?! You could edit the module to uncomment that line to solve the problem. Including the following in your script should also do the trick:
{
package Image::Magick::Thumbnail;
use warnings::register;
}

Related

How to fix Verilog::VCD::Writer error: Can't locate object method addSignal?

I suspect I made an import error in Perl.
There is a Perl module Verilog::VCD::Writer to write a VCD file. However, when I copy its SYNOPSIS code to have a try, it always raises the error:
Can't locate object method "addSignal" via package
"Verilog::VCD::Writer" at tester.pl line 10.
The SYNOPSIS calls addComment and addModule before addSignal so there should be no problems in my installation.
addSignal is a function defined in Verilog/VCD/Writer/Module.pm, and the other two are defined in Verilog/VCD/Writer.pm. Even I add Verilog::VCD::Writer::Module, still the debugger go to package Writer to find the addSignal method.
If I call the addSignal function in this way:
$writer->Verilog::VCD::Writer::Module::addSignal("TX",7,0);
Can't locate object method "signals_push" via package
"Verilog::VCD::Writer" at
/home/cqsun/lib/perl5/lib/site_perl/5.18.2/Verilog/VCD/Writer/Module.pm
line 41.
Module.pm defined signals_push in a hash, and clearly the debugger didn't find it.
I suspect there is something wrong, but I don't know where it is.
The webpage for this package is http://search.cpan.org/~jvs/Verilog-VCD-Writer-0.002/lib/Verilog/VCD/Writer.pm
This is a documentation bug.
The code in the SYNOPSIS section of the POD has a few problems. The error you see is from the line:
my $TX=$writer->addSignal("TX",7,0); #Add Signals to top
The code used the wrong object handle for the addSignal method. $writer is an object of the Verilog::VCD::Writer module, and it does not have an addSignal method. However, addSignal is a method of the Verilog::VCD::Writer::Module module. The code needs to use $top instead of $writer.
The next line has the same problem:
my $RX=$writer->addSignal("RX",7,0);
Finally, the following line has a syntax error because it is missing the comment delimiter (#) after the semicolon:
my $dut=$top->addModule("DUT"); Create SubModule
Here is a fixed version of the code which runs without errors and generates a VCD output file:
use Verilog::VCD::Writer;
my $writer = Verilog::VCD::Writer->new(timescale=>'1 ns',vcdfile=>"test.vcd");
$writer->addComment("Author:Vijayvithal");
my $top = $writer->addModule("top"); # Create toplevel module
my $TX = $top->addSignal("TX",7,0); #Add Signals to top
my $RX = $top->addSignal("RX",7,0);
my $dut = $writer->addModule("DUT"); #Create SubModule
$dut->dupSignal($TX,"TX",7,0); #Duplicate signals from Top in submodule
$dut->dupSignal($RX,"RX",7,0);
$writer->writeHeaders(); # Output the VCD Header.
$writer->setTime(0); # Time 0
$writer->addValue($TX,0); # Record Transition
$writer->addValue($RX,0);
$writer->setTime(5); # Time 1ns
$writer->addValue($TX,1);
$writer->addValue($RX,0);
I uploaded a patch to the bug report you opened:
https://rt.cpan.org/Ticket/Display.html?id=123724
Also, the Create SubModule comment seems misleading. Perhaps the author intended to use the addSubModule method instead of the addModule method.

Perl CPAN module object method not found error

I am trying to use a CPAN module: Math::Vector::Real::Neighbors
I see the following error message:
Can't locate object method "box" via package "Math::Vector::Real" at /usr/local/share/perl/5.14.2/Math/Vector/Real/Neighbors.pm line 12.
So, I go into the package and see this: my ($bottom, $top) = Math::Vector::Real->box(#_);
Next, I go into the Real.pm package at: /usr/local/share/perl/5.14.2/Math/Vector/Real.pm
I see the box sub routine exist in it: sub box {...
Any idea why the error might be cropping up?
You need to add use Math::Vector::Real to the top of your script to get Math::Vector::Real::Neighbors to work. The following code runs as expected:
use strict;
use warnings;
use Math::Vector::Real;
use Math::Vector::Real::Neighbors;
use Math::Vector::Real::Random;
my #v = map Math::Vector::Real->random_normal(2), 0..1000;
my #nearest_ixs = Math::Vector::Real::Neighbors->neighbors(#v);
But note that it did not work without the line use Math::Vector::Real.
I am the author of the Math::Vector::Real family of Perl modules.
Nowadays, in order to find the neighbors for a set of points, the algorithm provided in Math::Vector::Real::kdTree is much better:
my #v = ...;
my $kdtree = Math::Vector::Real::kdTree->new(#v);
my #nearest_ixs = $kdtree->find_nearest_vector_all_internal;

Accessing subs from a require'd perl script

I'm going to import some perl code with the require statement. The code I'd like to import is in mylibA.pl:
#!/usr/bin/perl
package FOO::BAR;
sub routine {
print "A message!\n";
}
and mylibB.pl:
#!/usr/bin/perl
package FOO::BAZ;
sub routine {
print "Another message!\n";
}
Then I'm going to use it like this:
#!/usr/bin/perl
foreach my $lib (qw/ mylibA.pl mylibB.pl /){
require $lib;
print "Make a call to ${lib}'s &routine!\n";
}
Is there a way for my script to figure out the namespace that was pulled in with the require statement?
Wow. I have to say this is the one of the most interesting Perl questions I've seen in a while. On the surface this seems like a very simple request - get an included module's namespace, but there really is no way to do this. You can get it while in the package, but not from outside the package. I tried using EXPORT to send the local package name back to the caller script but that ended up going nowhere given the difference in how "use" and "require" work. A more module type of approach probably would have worked with a "use" statement, but the requirement that the required script be able to run by themselves prevented that approach. The only thing left to do was to directly pollute the caller's namespace and hope for the best (assume that the caller had no package namespace) - something that modules are designed to prevent.
BTW - I can't believe this actually works - in strict mode, no less.
caller.pl
#!/usr/bin/perl
use strict;
#package SomePackageName; #if you enable this then this will fail to work
our $ExportedPackageName;
print "Current package=".__PACKAGE__."\n";
foreach my $lib (qw/ mylibA.pl mylibB.pl /){
require $lib;
print "Make a call to ${lib}'s &routine!\n";
print "Package name exported=".$ExportedPackageName."\n";
$ExportedPackageName->routine;
} #end foreach
print "Normal Exit";
exit;
__END__
mylibA.pl
#!/usr/bin/perl
package FOO::BAR;
use strict;
#better hope the caller does not have a package namespace
$main::ExportedPackageName=__PACKAGE__;
sub routine {
print "A message from ".__PACKAGE__."!\n";
}
1;
mylibB.pl
#!/usr/bin/perl
package FOO::BAZ;
use strict;
#better hope the caller does not have a package namespace
$main::ExportedPackageName=__PACKAGE__;
sub routine {
print "Another message, this time from ".__PACKAGE__."!\n";
}
1;
Result:
c:\Perl>
c:\Perl>perl caller.pl
Current package=main
Make a call to mylibA.pl's &routine!
Package name exported=FOO::BAR
A message from FOO::BAR!
Make a call to mylibB.pl's &routine!
Package name exported=FOO::BAZ
Another message, this time from FOO::BAZ!
Normal Exit
Regarding the mostly academical problem of finding the package(s) in a perl source file:
You can try the CPAN module Module::Extract::Namespaces to get all packages within a perl file. It is using PPI and is thus not 100% perfect, but most of the time good enough:
perl -MModule::Extract::Namespaces -e 'warn join ",", Module::Extract::Namespaces->from_file(shift)' /path/to/foo.pm
But PPI can be slow for large files.
You can try to compare the active packages before and after the require. This is also not perfect, because if your perl library file loads additional modules then you cannot tell which is the package of the prinicipal file and what's loaded later. To get the list of packages you can use for example Devel::Symdump. Here's a sample script:
use Devel::Symdump;
my %before = map { ($_,1) } Devel::Symdump->rnew->packages;
require "/path/to/foo.pm";
my %after = map { ($_,1) } Devel::Symdump->rnew->packages;
delete $after{$_} for keys %before;
print join(",", keys %after), "\n";
You can also just parse the perl file for "package" declarations. Actually, that's what the PAUSE upload daemon is doing, so it's probably "good enough" for most cases. Look at the subroutine packages_per_pmfile in
https://github.com/andk/pause/blob/master/lib/PAUSE/pmfile.pm
There are two problems here:
How do I change the behaviour of a script when executed as a standalone and when used as a module?
How do I discover the package name of a piece of code I just compiled?
The general answer to question 2 is: You don't, as any compilation unit may contain an arbitrary number of packages.
Anyway, here are three possible solutions:
Name your modules so that you already know the name when you load it.
Have each module register itself at a central rendezvous point.
Like #1, but adds autodiscovery of your plugins.
The simplest solution is to put all of the API in an ordinary module, and put the standalone logic in a seperate script:
/the/location/
Module/
A.pm
B.pm
a-standalone.pl
b-standalone.pl
Where each standalone basically looks like
use Module::A;
Module::A->run();
If another script wants to reuse that code, it does
use lib "/the/location";
use Module::A;
...
If the loading happens on runtime, then Module::Runtime helps here:
use Module::Runtime 'use_module';
use lib "/the/location";
my $mod_a = use_module('Module::A');
$mod_a->run();
It isn't strictly necessary to place the contents of a-standalone.pl and Module/A.pm into separate files, although that is clearer. If you want to conditionally run code in a module only if it is used as a script, you can utilize the unless(caller) trick.
Of course all of this is tricksing: Here we determine the file name from the module name, not the other way round – which as I already mentioned we cannot do.
What we can do is have each module register itself at a certain predefined location, e.g. by
Rendezvous::Point->register(__FILE__ => __PACKAGE__);
Of course the standalone version has to shield against the possibility that there is no Rendezvous::Point, therefore:
if (my $register = Rendezvous::Point->can("register")) {
$register->(__FILE__ => __PACKAGE__);
}
Eh, this is silly and violates DRY. So let's create a Rendezvous::Point module that takes care of this:
In /the/location/Rendezvous/Point.pm:
package Rendezvous::Point;
use strict; use warnings;
my %modules_by_filename;
sub get {
my ($class, $name) = #_;
$modules_by_filename{$name};
}
sub register {
my ($file, $package) = #_;
$modules_by_filename{$file} = $package;
}
sub import {
my ($class) = #_;
$class->register(caller());
}
Now, use Rendezvous::Point; registers the calling package, and the module name can be retrived by the absolute path.
The script that wants to use the various modules now does:
use "/the/location";
use Rendezvous::Point (); # avoid registering ourself
my $prefix = "/the/location";
for my $filename (map "$prefix/$_", qw(Module/A.pm Module/B.pm)) {
require $filename;
my $module = Rendezvous::Point->get($filename)
// die "$filename didn't register itself at the Rendezvous::Point";
$module->run();
}
Then there are fully featured plugin systems like Module::Pluggable. This system works by looking at all paths were Perl modules may reside, and loads them if they have a certain prefix. A solution with that would look like:
/the/location/
MyClass.pm
MyClass/
Plugin/
A.pm
B.pm
a-standalone.pl
b-standalone.pl
Everything is just like with the first solution: Standalone scripts look like
use lib "/the/location/";
use MyClass::Plugin::A;
MyClass::Plugin::A->run;
But MyClass.pm looks like:
package MyClass;
use Module::Pluggable require => 1; # we can now query plugins like MyClass->plugins
sub run {
# Woo, magic! Works with inner packages as well!
for my $plugin (MyClass->plugins) {
$plugin->run();
}
}
Of course, this still requires a specific naming scheme, but it auto-discovers possible plugins.
As mentioned before it is not possible to look up the namespace of a 'required' package without extra I/O, guessing or assuming.
Like Rick said before, one have to intrude the namespace of the caller or better 'main'. I prefer to inject specific hooks within a BEGIN block of the 'required' package.
#VENDOR/App/SocketServer/Protocol/NTP.pm
package VENDOR::App::SocketServer::Protocol::NTP;
BEGIN {
no warnings;
*main::HANDLE_REQUEST = \&HANDLE_REQUEST;
}
sub HANDLE_REQUEST {
}
#VENDOR/App/SocketServer.pm
my $userPackage= $ARGV[0];
require $userPackage;
main::HANDLE_REQUEST();
Instead of *main:: you can get more specific with *main::HOOKS::HANDLE_REQUESTS i.e. This enables you to resolve all injected hooks easily within the caller by iterating over the HOOK's namespace portion.
foreach my $hooks( keys %main::HOOKS ) {
}

Perl Win32::Console error

My little Perl script on Windows tried to call a dependency library C:/strawberry/perl/vendor/lib/Term/ReadPassword/Win32.pm which was written by somebody else.
Here is a part of C:/strawberry/perl/vendor/lib/Term/ReadPassword/Win32.pm:
package Term::ReadPassword::Win32;
use strict;
if (IsWin32()) {
eval('use Win32');
eval('use Win32::Console');
eval('use Win32API::File');
} else {
eval('use Term::ReadPassword');
}
...
my $CONIN = new Win32::Console(Win32::Console::STD_INPUT_HANDLE());
my $CONOUT = new Win32::Console(Win32::Console::STD_ERROR_HANDLE());
...
The following error showed up when running my script:
Undefined subroutine &Win32::Console::STD_INPUT_HANDLE called at C:/strawberry/perl/vendor/lib/Term/ReadPassword/Win32.pm line 58, <STDIN> line 2.
Using parens is legit, as discussed How can I optionally use Win32::Console and its constants in a cross platform way? and I've looked up http://metacpan.org/pod/Win32::Console.
Thanks.
eval('use Win32::Console');
doesn't do any error checking. If Win32::Console fails to load for any reason, the code will proceed anyway until it actually calls one of the subroutines that was supposed to have been loaded, but wasn't. At that point, you'll get failures like you describe.
What happens if you add use Win32::Console; to your script? (I'm guessing you'll get some kind of error saying Win32::Console couldn't be loaded.)

Overriding a module that is used by a program I'm testing

I am revising a Perl program and I wanted a test harness that could run the original version of the program (call it launch_rockets.pl) and collect the standard output, but somehow skip the system calls that occur inside launch_rockets.pl. The following code successfully overrides system inside launch_rockets.pl:
use subs qw(system);
my $SYSTEM_SUCCESS = 0;
sub system {
print "***\n";
print "system #_\n";
print "***\n\n";
return $SYSTEM_SUCCESS;
}
local #ARGV = #test_args;
do 'launch_rockets.pl';
So far so good. But launch_rockets.pl also contains
use Proc::Background;
and later
Proc::Background->new('perl', 'launch_missiles.pl');
I could copy launch_rockets.pl into a sandbox where Proc::Background is replaced by a stub, but I was wondering if there was any override strategy that would be effective inside a do FILE call in the file's original environment.
use lib '/my/test/library/path';
lib prepends the directory to #INC, so /my/test/library/path/Proc/Background.pm will be the file that gets loaded. Put whatever code you want in there.
Another alternative would be:
{
package Proc::Background;
... # Put stub code here
} # end of package Proc::Background
$INC{'Proc/Background.pm'} = 1; # Make Perl think Proc::Background is loaded