In Perl, why do I need Exporter? - perl

I have a module called hsfSubs.pm in my perl\lib folder. I have nothing in the module but subroutines and 1; at the end.
One subroutine, for example, is named pause. I have implemented no import or export routines.
In my main programs, I simply say use hsfSubs;, and I am subsequently able to call pause with no problem. Ditto if I say use hsfSubs qw(pause);.
Why would I need to use Exporter, #EXPORT and #EXPORT_OK, etc. or any other complications?
The multiple answers on Stack Overflow to questions about Exporter tell how to use it, but I fail to see why to use it.

The short version is that you wanted a module, but you ended up with what this calls a library. These aren't good because they pollute their caller's namespace (which can cause plenty of problems). But more crucially here, loading them using require or use (as oppose to do) is buggy.
If it had been properly written as a module, your example would not work. Exporter is the solution to that problem.
Let's dive into the details.
Like I said, there's a problem with your module. As you've noticed, it sometimes works despite the bug.
$ cat Buggy.pm
sub test { "ok!" }
1;
$ perl -e'use Buggy; CORE::say(test());'
ok!
But that's just because your example is too simple. Let's add a properly-written[1] module to the mix.
$ cat Buggy.pm
sub test { "ok!" }
1;
$ cat Other.pm
package Other;
use Buggy;
1;
$ perl -e'use Other; use Buggy; CORE::say(test());'
Undefined subroutine &main::test called at -e line 1.
The bug in your module is that it doesn't have a package directive. Modules loaded using use and require must always use a package directive. But as soon as you add that, your module stops working.
$ cat NotBuggy.pm
package NotBuggy;
sub test { "ok!" }
1;
$ perl -e'use NotBuggy; CORE::say(test());'
Undefined subroutine &main::test called at -e line 1.
Exporter is used to solve that problem.
$ cat Final.pm
package Final;
use Exporter qw( import );
our #EXPORT = qw( test );
sub test { "ok!" }
1;
$ perl -e'use Final; CORE::say(test());'
ok!
Well, not really. If it was properly written, it would include use use strict; use warnings 'all';. Always include that! It was omitted here to keep things visually simple.

Related

failed to install my own perl module(pm file)

I have made my own perl modules(pm files),named test.pm
package test;
use Exporter;
use strict;
use File::Basename qw(basename dirname);
use Cwd qw(abs_path);
use File::Path qw(make_path);
use FindBin qw($Bin $Script);
BEGIN {
our #ISA = qw(Exporter);
our #EXPORT = qw(mkdirOrDie);
our $VERSION = 1.0;
}
sub mkdirOrDie
{
my ($dir) = #_ ;
if(!-d $dir){
make_path($dir);
$dir=abs_path($dir);
# timeLog("Directory Created: $dir");
}
}
and I tried to install this module as follows,
h2xs -AX -n test
perl Makefile.PL
make
make install
there is no error,and I copy the test.pm to /usr/lib64/perl5/5.10.0/,but when i call sub function using test, an error has occurred,
Undefined subroutine &main::mkdirOrDie called at /to/my/path/main.pl line 92
is there something i ignored?
It's unclear at which point things started to go wrong for you.
Firstly, test.pm is a bad name for a Perl module. Perl modules should have names that begin with upper case letters (and Test.pm is already taken).
You should run h2xs before writing your code - as it generates a module skeleton for you fill in. I hope it hasn't overwritten your code with an almost empty file! It's also worth noting that most people stopped using h2xs many years ago. These days we have tools like Module::Starter.
Then, running, make install (which you need to do with root permissions - so usually with sudo) is what installs your module into the system libraries. There should be no need to run that cp command afterwards.
As for why your code doesn't find the module, there are many possible reasons. Are you using Perl 5.10 or do you have other Perl versions installed? What does the code look like that you are trying to use? Does test.pm still include the code you think it does?
Need more information to be much help here.

Check and report Perl module missing

Is there any way to report the missing modules used in the Perl file beforehand instead of getting as an error.
I have something like use Digest::MD5, use File::DosGlob modules in my Perl program. Whenever the users run the script they are getting an error if there is no specific module installed in their system. They could not understand the default error message given by #INC. So I would like to clearly tell them that these modules need to be installed to run the script.
You could build your own verification by using a BEGIN block. Those are run at compile time, just like use is. Keep in mind that use Foo is essentially nothing else as this:
BEGIN {
require Foo;
Foo->import;
}
The following code will replace all use statements with a single BEGIN and place them inside an eval. That's essentially like a try/catch mechanism.
We need the string eval (which is considered evil around here) because require only converts from package names with colons :: to paths if the argument is a bareword. But because we have the name in $module, it's a string, so we need to place it into an eval according to require's docs.
If that string eval fails, we die. That's caught by the outer eval block and $# is set. We can then check if it contains our module name, in which case we naively assume the failure was because that module is not installed. This check could be a bit more elaborate.
We keep track of any failures in $fails, and if there were any, we stop.
#!/usr/bin/perl
use strict;
use warnings;
# all our use statements go here
BEGIN {
my $fails;
foreach my $module ( qw/Digest::MD5 File::DosGlob ASDF/ ) {
eval {
eval "require $module" or die; # because $module is not a bareword
$module->import;
};
if ($# && $# =~ /$module/) {
warn "You need to install the $module module";
$fails++;
}
}
exit if $fails;
}
# ...
Above I included ASDF, which I don't have, so when run it will say
You need to install the ASDF module at /home/code/scratch.pl line 1335.
You might want to make that message a bit more verbose. If your users are not able to understand the default error message that Perl gives when it cannot find a module, it might be wise to include a guide on how to install stuff right there.
Note that both modules you listed have been included with Perl for a while (read: since March 2002). So why would you want to do this for those modules?
$ corelist Digest::MD5
Data for 2014-09-14
Digest::MD5 was first released with perl v5.7.3
$ corelist File::DosGlob
Data for 2014-09-14
File::DosGlob was first released with perl 5.00405
A better way would be ship your program as a distribution that can be installed, and include a Makefile or a cpanfile or something similar that lists dependencies. There is a guide in perlnewmod on how to start a new module. You'd not want to upload to CPAN obviously, but the basics are the same.
With this, your users would get all dependencies installed automatically.
You could use Devel::Modlist, it will list all the required module for your program.
perl -d:Modlist test.pl
There's another module Module::ScanDeps which comes with a utility scandeps.pl which you can use on your script as:
scandeps.pl test.pl
Note that sanity checking your Perl code using perl -c is dangerous, so use it carefully.
Your question isn't really clear about what "beforehand" means. To check if a Perl program's syntax is correct and directly included modules are resolvable, use
perl -c <perl-program.pl>
This checks the syntax of your file and ensures that any modules used by your code exist. However, it does not transitively check the entire dependency tree, only those mentioned in perl-program.pl.

Eclipse: Perl EPIC debug & release mode execution mismatch

I am noticing an execution mismatch of Perl in Eclipse EPIC plugin.
Specifications:
Perl version: (v5.12.4) built for MSWin32-x86-multi-thread
Eclipse version: Indigo Service Release 2
EPIC version: 0.6.53
Consider the files & source codes below: (all source files are in same directory)
sample.pl
use package1;
require "package1.pm";
require "package2.pm";
sampleFunction();
require "packagetest.pm";
packagetest::callSampleFunction();
package1.pm
package package1;
use Exporter;
our #ISA = qw(Exporter);
our #EXPORT = qw(
sampleFunction
);
sub sampleFunction {
print "from package1.pm \n";
}
package2.pm
package package1; # declare the same package 'package1'
use Exporter;
our #ISA = qw(Exporter);
our #EXPORT = qw(
sampleFunction
);
sub sampleFunction {
print "from package2.pm \n";
}
packagetest.pm
package packagetest;
use package1;
sub callSampleFunction {
sampleFunction();
}
1;
When I execute the sample.pl file in Eclipse EPIC, I am getting two different console outputs.
Debug mode output:
from package2.pm
from package2.pm
Run mode output:
Subroutine sampleFunction redefined at D:/My.Soft.Dev/Perl_XS/package2.pm line 11.
from package1.pm
from package2.pm
I have the below questions:
1) Why am I getting two different outputs here? Is it not a bug?
2) Which of the outputs shown is a "valid output"?
3) Can someone explain why is the particular output valid?
I tried to derive the reasons from my Perl knowledge. But I couldn't. So, I understood, I have to get to know more about Perl:))
UPDATE: I have created a bug report: https://sourceforge.net/p/e-p-i-c/bugs/669/
Looks like (1) is a bug in Perl debugger of 5.12.4 version
Regarding questions #2 and #3:
Your release mode output is the valid one:
use package1 finds, loads, compiles, and executes package1.pm. This defines package1::sampleFunction, which is exported into the main namespace. Exporting is effectively done by reference, and not by name, so main::sampleFunction points to the same function which package1::sampleFunction currently refers to.
require "package1.pm does nothing because that package has already been executed.
require "package2.pm finds, loads, compiles and executes package2.pm. This redefines package1::sampleFunction, which will warn if and only if you have warnings activated – either lexically through use warnings (do this) or globally with the -w switch (don't do this).
sampleFunction() executes main::SampleFunction, which still points to the original subroutine.
from package1.pm
require "packagetest.pm" finds, loads, compiles and executes packagetest.pm. Here in turn:
use package1 will export package1::sampleFunction (which is currently the redefined subroutine) into the packagetest namespace.
We also define the packagetest::callSampleFunction subroutine.
We call packagetest::callSampleFunction, which in turn
calls packagetest::sampleFunction, which is the redefined subroutine
from package2.pm
A guess regarding #1:
The output could come together if we executed the script normally but kept the interpreter with its global state alive, then recompile and re-execute sample.pl. In this case, package1.pm and package2.pm would not be re-executed because they are already loaded. The use package1 would then import the current package1::sampleFunction which already is the redefined version.
To test this hypothesis, restart your IDE and execute the script two times in debug mode. It should then output
from package1.pm
from package2.pm
during the first run, and
from package2.pm
from package2.pm
for all subsequent runs.
The real problem is
that you are redefining subroutines (don't do this),
that you are using the same package name package1 in different files (don't do this),
that you are using a filename package2.pm that does not correspond to the package name package1 inside (don't do this either), and
that you have a number of other style issues, including:
lowercase package names are reserved for “pragmatic modules”
don't export by default, instead use #EXPORT_OK and let the user of your module explicitly request some symbol
require "filename" is usually not something you want to do.
You did not use strict; use warnings
You are using warnings in production, but not in development? Why? :(
You are using the -w switch which is a bit oudated.

Is there a way to get the Perl interpreter to list all the global variables in a pl file?

I have a huge system that I'm converting from a cgi to a daemon and I need to find all the variables that end up being global (as in not declared with my $...)
They are probably intended to be scoped locally, but in perl if you accidentally forget, it doesn't care, but now I do.
I gotta figure the perl interpreter can tell the difference, so is there a way to get it to tell me? I could go through all the code by hand, looking for declarations, but there thousands and thousands and thousands of lines of code in this system.
perldoc strict will show all variables not declared with my:
$ perl -Mstrict=vars -c -e '$x=5; my $y=7; $z=6;'
Global symbol "$x" requires explicit package name at -e line 1.
Global symbol "$z" requires explicit package name at -e line 1.
-e had compilation errors.
The same thing with a list of files:
$ perl -Mstrict=vars -c *.pl
Here is another way using perldoc B::Xref
$ perl -MO=Xref -e '$x=5; my $y=7; $z=6;'
... lots of verbose output
Subroutine (main)
Package (lexical)
$y i1
Package main
$x 1
$z 1
With the PadWalker Module you can see all variables in a specific scope. You can see variables declared with "my" and "our".
You should still use "use strict" but using "use strict" does not show you global variables that you declare as global.
For example this example still has a global variable and strict does not do anything
#!/usr/bin/env perl
use strict;
use warnings;
our $foo;
With PadWalker you can use something like this.
#!/usr/bin/env perl
use strict;
use warnings;
use DDP;
use PadWalker qw(peek_our);
our $var;
print p peek_our(0);
The output is
\ {
$var \ undef
}
Sure, you only should use PadWalker for Debugging.

How can I split my Perl code across multiple files?

My scripts are getting too long. How do I split my code (procedural subs) into multiple Perl files and tell the interpreter to make sense of them?
Kind of like:
# -> main.pl
#include "foo.pl"
say_hello();
and:
# -> foo.pl
sub say_hello {print "hello!"}
What you want to do is create one or more modules. Start by looking over perlmod, especially the Perl Modules section.
Since you say you're writing procedural code, you'll want to export functions from your modules. The traditional way to do that is to use Exporter (which comes with Perl), although Sub::Exporter is a newer CPAN module that allows for some nice things. (See also its Sub::Exporter::Tutorial for an introduction to exporting functions.)
Modules can be placed in any of the directories listed in the #INC variable. Try perl -V to get a list. You can also use lib to add directories at runtime. One trick is to use the FindBin module to find the location of your script, and then add a directory relative to that:
use FindBin; # Suppose my script is /home/foo/bin/main.pl
use lib "$FindBin::Bin/lib"; # Add /home/foo/bin/lib to search path
Your sample code, converted to a module:
In main.pl:
#! /usr/bin/perl
use strict;
use warnings;
use Foo;
say_hello();
In Foo.pm:
package Foo;
use strict;
use warnings;
use Exporter 'import';
our $VERSION = '1.00';
our #EXPORT = qw(say_hello);
sub say_hello {print "hello!"}
1; # A module must end with a true value or "use" will report an error
I think you may be looking for do? http://perldoc.perl.org/functions/do.html
put it in the same folder as your class and add use ClassName to the top of the calling file.
Also check the Perl OOP tutorial.