Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: Trouble with Exporter

Tags:

perl

exporter

Module: ./FOO/BAR/Foobar.pm

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;

Program: ./Caller.pl

#!/usr/bin/perl

   use strict;
   use warnings;

   use FOO::BAR::Foobar qw/foo/;

   Foobar::foo();  # works
   foo();          # errors out - can't find &main::foo

I'd list all the things I've tried, but there are a lot - as you can see I have more global Foobar globals than that listed. I've removed the BEGIN and done some other things as suggested in [older] posts on PerlMonks.

I think I read somewhere once that if the package name is the same name as the module name, Exporter works a certain way by default. I don't know if putting the module in a sub-directory could have changed that behavior(?). However, I'm eager to see how I've screwed up.

like image 238
vol7ron Avatar asked Jan 16 '23 08:01

vol7ron


2 Answers

If the module is located in FOO/BAR/Foobar.pm, then the package name should be FOO::BAR::Foobar.

I would also remove the & sign from the @EXPORT_OK array.

like image 146
choroba Avatar answered Jan 24 '23 23:01

choroba


In addition to choroba's answer I found this post by Sherm Pendley, which I think is the same post I read years ago:

In a non-OO module that exports functions, they have to be the same for Exporter to do its thing. When you use() a module - let's call it "Foo", the following steps are basically what happens:

BEGIN {
   require Foo;
   import Foo qw(args);
}

The second step is optional - if there's no import() function in module Foo, the use() will still succeed.

Now, let's suppose that package Bar is in Foo.pm. Foo.pm is compiled by the require() with no problems. Because its code is in package Bar, the import() function, explicitly declared or inherited from Exporter, is compiled into that package too.

But the use() still tries to call an import() function in package Foo. Worse, because import() is optional it will silently fail. The only clue the user will get that something has gone wrong, is that none of the functions declared in package Bar will be usable without a fully- specified package name, i.e. Bar::baz(), because the import() failed to create aliases for them in the current package.

Other things can depend on the filename = package convention too. Take perldoc, for example. If a user of your module runs "perldoc Foo" to get your module's docs, it will read the docs found in Foo.pm. The user's going to be confused if those docs describe a package named "Bar."

Even if your module is "pure" OO and doesn't export anything, following the established convention helps avoid confusion - imagine a maintenance programmer looking at your script a year from now, and seeing this:

use Foo;
my $bar = Bar->new();

It's not very intuitive to see a class Bar defined in Foo.pm.

So no, it's not required in theory. But the convention of naming them the same is followed so widely, that in practice it's really more or less required.


So, it seems if you have multiple packages per module, only the one that share the same name as the file can export its variables/functions. I suspect you could get it to work if you were to create your own import function for the other packages (?).

Anyhow, in my example, if I didn't want to call the package the whole hierarchy tree, I could set the lib:

use lib './FOO/BAR';
use Foobar qw/foo/;   # instead of "use FOO::BAR::Foobar"

This would mean I could still have Foobar.pm and inside it package Foobar instead of package FOO::BAR::Foobar

like image 28
vol7ron Avatar answered Jan 24 '23 23:01

vol7ron