Perl - Package/Module Issues - perl

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( )

Related

Can perl modules "use" other perl modules?

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.

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 problem 'require' the same file

I have a shared module in perl. The main program needs two files, first, a shared file (let's call it 'X'), and, second, a 'package' file. File 'X' is also included in the 'package' file using 'require'. When I compile this program it gives me the following error:
Undefined subroutine &main::trim called at testing.pl line 8.
My understanding is that perl couldn't find the trim() module. If I don't include the package file, then this will run without any problem.
Can anyone shed light on this problem?
These are my codes:
Main program: testing.pl
#!/usr/bin/perl -w
use strict;
use postgres;
require "shared.pl";
trim("als");
Package File: postgres.pm
#!/usr/bin/perl
package postgres;
use strict;
use DBI;
require "shared.pl";
1;
shared file: shared.pl
#!/usr/bin/perl
# =============
# shared module
# =============
use strict;
sub trim($)
{
}
1;
If the module doesn't use package, you want do instead of require. See What is the difference between library files and modules?.
do "shared.pl" or die $#;
You really should create a proper module, one with a package statement.
package Shared;
use strict;
use warnings;
our #EXPORT = qw( trim );
use Exporter qw( import );
sub trim { ... }
1;
Name the file Shared.pm and load it using use Shared;.
By default, require will only load a file one time. In this case, that one time is from the file postgres.pm, in the postgres package. So the trim subroutine gets defined in the postgres namespace as &postgres::trim.
One workaround would be to use the fully qualified subroutine name in the testing.pl file:
postgres::trim("als"); # not trim("als")
Another workaround is to hack the %INC table (the variable that keeps track of what modules/files have already been use'd and require'd) so you can reload shared.pl into the main package:
use postgres;
delete $INC{"shared.pl"};
require "shared.pl";
A third workaround would be to export the trim function from the postgres package to the main package. The docs for the Exporter module are a good introduction to why and how this is done.
# in postgres.pm
*main::trim = *trim;
# or in testing.pl
*trim = *postgres::trim;
trim("als");

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.