William Barrett
William Barrett

Reputation: 301

Can't use Exporter properly

I've wasted many days on a larger block of code, containing Exporter statements, which used to work about a year ago. Several variations on this have failed, including an install of ./FOO/BAR/Foobar.pm which signaled success.

I am using Windows 10, Perl v5.26.0, built for MSWin32-x64-multi-thread

Caller.pl

   #!/usr/bin/perl

   use lib ".";
   use lib "./FOO/BAR";

   use strict;
   use warnings;

   use FOO::BAR::Foobar;

   print "try FOO::BAR::Foobar::foo()\n";
   FOO::BAR::Foobar::foo();  # perl can't find this

   print "try foo()\n";
   foo();          # errors out - can't find &main::foo

   print "done\n";

./FOO/BAR/Foobar.pl

#!/usr/bin/perl -w

use strict;
use warnings;

package Foobar;

our($VERSION , @ISA , @EXPORT , @EXPORT_OK , %EXPORT_TAGS , $FOO);

BEGIN {
    require Exporter;
    @ISA       = qw(Exporter);
    @EXPORT_OK = qw(foo);
}

sub foo {
    print "Loaded\n";
    $FOO = q{some val};
}

1;

Execution dump

perl Caller.pl
try FOO::BAR::Foobar::foo()
Undefined subroutine &FOO::BAR::Foobar::foo called at Caller.pl line 12.

What's going on? Should I abandon any use of Exporter? But then how to link functions across modules?

Upvotes: 1

Views: 82

Answers (1)

haukex
haukex

Reputation: 3013

There are three things going wrong:

  1. With FOO::BAR::Foobar::foo(): There is no such sub, there is only Foobar::foo().

  2. With foo(): use FOO::BAR::Foobar; is the equivalent of BEGIN { require FOO::BAR::Foobar; FOO::BAR::Foobar->import() }, but there is no method import available in the package FOO::BAR::Foobar, since you're inheriting Exporter into the package Foobar.

  3. With foo(): You're using @EXPORT_OK instead of @EXPORT, which means that you need to explicitly import foo, but you're not doing that in use FOO::BAR::Foobar;.

So two things are needed to fix this:

  1. As already pointed out in the comment by @HåkonHægland, change package Foobar; to package FOO::BAR::Foobar;.

  2. Change use FOO::BAR::Foobar; to use FOO::BAR::Foobar qw/foo/;.

Then the code you've shown will work - there's no need to abandon Exporter. I'd just recommend a different style of using Exporter: Instead of inheriting via @ISA, just import import into your package. Here's how I would have written your file ./FOO/BAR/Foobar.pm:

package FOO::BAR::Foobar;
use strict;
use warnings;

use Exporter 'import';
our @EXPORT_OK = qw(foo);

our $FOO;
sub foo {
    print "Loaded\n";
    $FOO = q{some val};
}

1;

Upvotes: 4

Related Questions