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");
Related
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.
module.pm
package module;
use 5.012;
use warnings;
sub Parse
{
return 1;
}
1;
script.pl
#!/usr/bin/perl -w
use 5.012;
use warnings;
use lib 'C:/';
use module;
print Parse("value");
Stdout
Undefined subroutine &main::Parse
You need either to write:
print module::Parse("value");
or to change the module package to export the name Parse.
See http://perldoc.perl.org/perlmod.html#Perl-Modules for guidance in exporting symbols from your module.
(By the way, you should really name your module Module rather than module. Lowercase module-names are used for Perl built-in features like use warnings and use strict.)
Several things:
First, use Local as your module prefix. That way, if you just happen to have a module with the same name in your Perl installation, it will use yours. Call it "Local::Module". Then, create a Local directory, and name your module Module.pm.
The other thing you have to understand is that you define your module in another namespace. By default, everything is in the main namespace until you use the package statement. That creates another namespace that your package uses. This way, if your package has a function foo, and you've defined a function foo in your main program, they won't collide.
Thus, you have two choices: One (the preferred now) is to simply call your subroutine with the full package name prepended to it. The second is to export your subroutine names to your main program. This can cause problems with duplicate names, but you don't have to keep typing in the package name every time you call your subroutine.
Without Exporting the name
Local/Module.pm
# /usr/bin/env perl
# Local/Module.pm
package Local::Module;
use strict;
use warnings;
sub Parse {
my $value = shift; #Might as well get it.
print "I got a value of $value\n";
return $value;
}
1; #Need this or the module won't load
program.pl
# /usr/bin/env perl
# program.pl
use strict;
use warnings;
use Local::Module;
Local::Module::Parse("Foo");
With export:
Local/Module.pm
# /usr/bin/env perl
# Local/Module.pm
package Local::Module;
use strict;
use warnings;
use Exporter qw(import);
our #EXPORT_OK(Parse); #Allows you to export this name into your main program
sub Parse {
my $value = shift; #Might as well get it.
print "I got a value of $value\n";
return $value;
}
1; #Need this or the module won't load
program.pl
# /usr/bin/env perl
# program.pl
use strict;
use warnings;
use Local::Module qw(Parse);
Parse("Foo");
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.
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.
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( )