Can perl modules "use" other perl modules? - perl

perl 5.24.0 on linux
Perl module "nesting" (sort of) problem...
I can't seem to get this to work and was wondering if someone could tell me what's wrong. The simple example below will articulate my problem better than my verbage...
First, ping.pl...
#!/usr/bin/env perl
# This is ping.pl
use ping_mod;
ping_dbh();
exit;
Next up is the perl module, ping_mod.pm...
#!/usr/bin/env perl
use Exporter;
use ping_common;
package ping_mod;
#ISA = qw(Exporter);
#EXPORT = qw(ping_dbh);
sub ping_dbh {
set_dbh();
print "dbh = $dbh\n";
}
1;
Finally is ping_common.pm which ping_mod uses...
#!/usr/bin/env perl
use Exporter;
our $dbh;
package ping_common;
#ISA = qw(Exporter);
#EXPORT = qw($dbh set_dbh);
sub set_dbh {
$dbh = 99;
}
1;
When I run ping.pl, I get...
Undefined subroutine &ping_mod::set_dbh called at ping_mod.pm line 11.
But if I change ping_mod.pm to be...
#!/usr/bin/env perl
use Exporter;
use ping_common;
package ping_mod;
#ISA = qw(Exporter);
#EXPORT = qw(ping_dbh);
sub ping_dbh {
# set_dbh();
# print "dbh = $dbh\n";
print "hi there\n";
}
1;
... it runs fine. So, I'm thinking it must be exporting OK. But "useing" ping_common messes it up somehow.
Even if I "use ping_common" in ping.pl, it still can't find it.

As #toolic said, use ping_common has to be after the package statement. Here's why.
Packages in Perl isolate global variables and functions. The full name for ping_dbh is really ping_mod::ping_dbh. You can call ping_dbh in the ping_mod package. If you want to call it elsewhere you must use its full name, ping_mod::ping_dbh.
use Module is really require Module to load it and Module->import to import its functions and variables into the current package. It doesn't matter where the module is loaded, so long as it is loaded. But it is very important where it is imported.
With this in mind, look at this.
use ping_common;
package ping_mod;
That will load ping_common and import its functions, not into ping_mod, but into the default package main. They will not be available to ping_mod.
package ping_mod;
use ping_common;
This also loads ping_common, but it imports its functions into ping_mod.
But why does Exporter still work, even outside the package?
use Exporter;
use ping_common;
package ping_mod;
#ISA = qw(Exporter);
#EXPORT = qw(ping_dbh);
Ironically, Exporter does not work by exporting. It works by inheritance. #ISA = qw(Exporter); makes ping_mod inherit the import method from Exporter. That #ISA, because it is in the ping_mod package, is the global variable #ping_mod::ISA.
.pm files should generally start with a package statement. They should not start with a #!; though it doesn't hurt anything. #! tells the operating system what to use to run the file as an executable program. Perl modules are generally not executables.
You can read more about packages in perlmod.

Related

Wrong way of exporting perl functions from a module

I have a very small module and I am having trouble with exporting the functions from it.
Take the function GetVar() if I call it using TestMod::GetVar() It will work fine, however when I call GetVar() from the script in which the module is imported I get an error (listed below). I am 99% sure that I have not exported the function GetVar() correctly, however I can not find my mistake.
Module source:
#!/usr/bin/perl
use strict;
package TestMod;
our (#ISA, #EXPORT, $VERSION);
use Exporter;
#ISA = qw(Exporter);
#EXPORT = qw(&GetVar);
$VERSION = 0.01;
sub GetVar()
{
return "something";
}
1;
Script source:
#!/usr/bin/perl
use strict;
use lib "/home/user1221/projects/";
use module;
print "Version: $TestMod::VERSION";
my $a = GetVar(); #should work but doesn't
print "$a\n";
Error:
Undefined subroutine &main::GetVar called at /home/user1221/projects/module_use.pl line 8.
use module; in your script is exact equivalent of
BEGIN { require module; module->import(); }
but since you don't have module package nothing is imported.
What you need is
BEGIN { require module; TestMod->import(); }
or make sure your module file names follow package names.

Perl: Exporting functions from a package which is in a subdirectory?

I've simplified my problem down to a small example. There is something happening that I don't understand with the way importing / exporting functions from packages works.
This code works and I can call greet() from use-myPack.pl.
# myPack.pm
package myPack;
require Exporter;
#ISA = qw(Exporter);
#EXPORT_OK = ('greet');
sub greet {
printf("Hello!\n");
}
1;
# use-myPack.pl
use myPack qw(greet);
greet();
# Output
PS C:\Users\adam> perl .\use-myPack.pl
Hello!
However, when I call use-myPack.pl from the parent directory and use the :: operator to ensure it can still use myPack, it can't find the function called greet().
# myPack.pm
package myPack;
require Exporter;
#ISA = qw(Exporter);
#EXPORT_OK = ('greet');
sub greet {
printf("Hello!\n");
}
1;
# use-myPack.pl
use adam::myPack qw(greet);
greet();
# Output
PS C:\Users> perl .\adam\use-myPack.pl
Undefined subroutine &main::greet called at .\adam\use-myPack.pl line 2.
Can anyone help explain why I can call greet() in the first case, but not the second?
The package name used in the use directive must match the package named used in the module's package directive (because you end up doing PACKAGE_NAME->import(IMPORT_LIST)).
use Foo::Bar; with package Foo::Bar; = ok
use Bar; with package Foo::Bar; = not ok
use Foo::Bar; with package Bar; = not ok
The simplest option is to change the module to use
package adam::myPack;
to allow you to keep using
use adam::myPack qw( greet );
Otherwise, you need to switch to
use myPack qw( greet );
and make Perl find the module by changing the library search path (#INC) by using
use lib 'adam';
or
use FindBin qw( $RealBin );
use lib "$RealBin/adam";
The former works if the cwd is different than the scripts directory, while the latter doesn't.
Alternatives to use lib
If you called the directory lib instead of adam, you could use
use mylib; # Short for something similar to:
# use FindBin qw( $RealBin );
# use lib "$RealBin/lib", "$RealBin/../lib";
Or if you have a directory to which you install module for all your scripts (e.g. ~/perl5/lib), set the environment variable PERL5LIB to it in your login script.
export PERL5LIB=~/perl5/lib # sh & bash syntax
Here is a mini-tutorial about the differences between packages and modules.
use My::Package 1.0 (qw'some options');
# ↑ no comma
is effectively the same as:
BEGIN{
# load the <module> if it isn't loaded already
require My::Package;
# or
require 'My/Package.pm';
# check the version of the <package>
'My::Package'->VERSION(1.0); # compare against $My::Package::VERSION
# do extra processing in the <package>
'My::Package'->import(qw'some options');
}
Notice that only require dealt with the module, the rest of the statements all dealt with the package of the same name.
My/Package.pm:
package My::Package;
use strict;
use warnings;
our $VERSION = 1.0; # checked by UNIVERSAL::VERSION
# you can actually override VERSION. ( don't though )
# bad example of an import method
sub import{ # called by C<use>
my( $package, $filename, $line ) = caller;
print 'you called ', __PACKAGE__, " from $filename at line $line with options #_\n";
# the following is similar to how Exporter::import works
no strict 'refs';
*{ $package.'::exported_sub' } = \&My::Package::Subs::exported_sub;
}
package My::Package::Subs; # <== look another package in the same module
sub exported_sub{...}
If you call use with an empty list then import is not called.
use My::Package ();
BEGIN{
require 'My/Package.pm';
}
The main reason you would do this is to make sure that the module is loaded at compile time without it doing anything extra on behalf of the calling package.
When you do this:
require Exporter; # loads module named Exporter
#ISA = qw(Exporter); # inherit C<import> from Exporter.
Any method calls to import on the package will be handled by import in Exporter. This includes any use statements.
Provided of course that you don't override it by defining your own import or AUTOLOAD methods.
modules contain 0 or more package statements.
Without a package statement, it will be in the same package where it was first loaded from.
A module usually contains a package of the same name.
As an aside
:: is not an operator (otherwise it would be in perlop).
Instead :: and ' are called package separators.
If :: were an operator, you would be able to do A :: B :: C and A::(B::C), which are (currently) syntax errors.

Perl subroutine naming conflicts

How does Perl resolve subroutine naming conflicts when parsing modules in the #INC path?
I'm writing a Perl module and I don't want my subroutine names to conflict with anything that already exists.
This should shed some light here.
Test script
#!/usr/bin/perl
use warnings;
use strict;
# import 'print_stuff' from TestPackage
# so you can call this sub without package name
use TestPackage qw(print_stuff);
my $string = "whatever";
TestPackage::print_stuff($string);
print_stuff($string);
sub print_stuff {
my $str = shift;
print "test.pl: $str\n";
}
Test package
package TestPackage;
# Export subs, which will enable you to call these
# subs without package name(TestPackage)
require Exporter;
#ISA = qw(Exporter);
#EXPORT_OK = qw(print_stuff);
sub print_stuff {
my $str = shift;
print "TestPackage: $str\n";
}
1;
Output:
$ test.pl
TestPackage: whatever
test.pl: whatever
Use package to build separate namespaces in modules, so you can avoid this kind of problems. The package statement declares the compilation unit as being in the given namespace. This link may helps you.

Perl explicitly using module UNIVERSAL causes a module to not export any symbols

I have two perl modules where one is the "object base" and the other imports functions from this "object base" module. When I compile the second module (perl -c Foo/Bar/NewObject.pm) it compiles without any warnings.
The issue is if I include the UNIVERSAL module in compiling the second module (perl -MUNIVERSAL -Mstrict -wc Foo/Bar/NewObject.pm) it throws warnings like:
"set" is not exported by the Foo::Bar::Object module
So my question is why does including UNIVERSAL cause the Exporter function to fail exporting symbols from the 'object base' model?
An example of what the modules look like are below.
object base:
#!/usr/bin/perl -w
use strict;
package Foo::Bar::Object;
use Exporter;
our #ISA = qw(Exporter);
our #EXPORT = qw( new set get update create );
...
1;
second module:
#!/usr/bin/perl -w
use strict;
package Foo::Bar::NewObject;
use Foo::Bar::Object qw( new set get );
...
1;
I ended up resolving this by follow what #ikegami linked in the comments. I had to wrap the #EXPORT in a BEGIN {} block and that seemed to work.
There must have been a module trying to use the methods before they were exported.

Perl - Package/Module Issues

From everything I've read on using Perl modules, the basic usage is:
Module file with .pm extension, which includes the statement package <name>, where <name> is the filename of the module without the extension.
Code file that uses module contains the statement use <name>;.
The application I'm coding has one main code script which uses about 5 modules. I had forgotten to include the package <name> statement in the modules, but my code still ran just fine with the use <name> statement. I started receiving Undefined subroutine errors with one of the modules, so I added the package statement to each of the modules. Now the rest of those modules stopped working. What gives?
Example:
mainapp.pl
#!/usr/bin/perl
use UtyDate;
my $rowDate = CurrentDate("YYYYMMDD");
UtyDate.pm
#!/usr/bin/perl
package UtyDate;
sub CurrentDate
{
#logic
}
return 1;
When I run the above code, I get the error Undefined subroutine &main::CurrentDate called at.... However, if I remove the package UtyDate; line from UtyDate.pm, I get no error. This situation exists for several but not all of my modules.
There's obviously a lot more code I'm not showing, but I'm confused how any of the code I'm not showing could affect the package/use constructs I've shown here.
When you use a module, the code in the module is run at compile time. Then import is called on the package name for the module. So, use Foo; is the same as BEGIN { require Foo; Foo->import; }
Your code worked without the package declarations because all the code was executed under the package main, which is used by the main application code.
When you added the package declarations it stopped working, because the subroutines you defined are no longer being defined in main, but in UtyDate.
You can either access the subroutines by using a fully qualified name UtyDate::CurrentDate(); or by importing the subroutines into the current name space when you use the module.
UtyDate.pm
package UtyDate;
use strict;
use warnings;
use Exporter 'import';
# Export these symbols by default. Should be empty!
our #EXPORT = ();
# List of symbols to export. Put whatever you want available here.
our #EXPORT_OK = qw( CurrentDate AnotherSub ThisOneToo );
sub CurrentDate {
return 'blah';
}
sub AnotherSub { return 'foo'; }
Main program:
#!/usr/bin/perl
use strict;
use warnings;
use UtyDate 'CurrentDate';
# CurrentDate is imported and usable.
print CurrentDate(), " CurrentDate worked\n";
# AnotherSub is not
eval { AnotherSub() } or print "AnotherSub didn't work: $#\n";
# But you can still access it by its fully qualified name
print UtyDate::AnotherSub(), " UtyDate::AnotherSub works though\n";
See Exporter docs for more info.
You are missing the exporter perl header code. You will need to add something like the following to the top of your pm file below the package statement:
package UtyDate;
BEGIN {
use Exporter ();
use vars qw($VERSION #ISA #EXPORT);
$VERSION = "1.0.0";
#ISA = qw(Exporter);
#EXPORT = qw( &CurrentDate );
}
See this link: http://perldoc.perl.org/Exporter.html#DESCRIPTION
Alternatively to Gray's suggestion, you can do this:
use UtyDate;
UtyDate::CurrentDate(...);
Besides using the exporter, as Gray points out, you could (UGLY, but works) also call the functions with the module name ..
You functiond/procedures don't work since they are now in a differen namespace (defined by the module name)
use UtyDate;
UtyDate::CurrentDate( )