Reputation: 9245
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?
Upvotes: 1
Views: 510
Reputation: 34130
Here is a mini-tutorial about the differences between packages and modules.
use My::Package 1.0 (qw'some options');
# ↑ no comma
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.
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.
package
statements.package
statement, it will be in the same package where it was first loaded from.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.
Upvotes: 1
Reputation: 386676
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.
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
Upvotes: 1