stevieb has asked for the wisdom of the Perl Monks concerning the following question:

Hey all, I hope you've all had/are having a wonderful holiday!

I'm having a Rubber Duck Debugging moment here... I am using @EXPORT_OK to export my public functions within a module, and all are available through an :all tag, but for my test suite, I want to have an extra tag that exports a few of my private functions as well, but can't seem to be able to import them. Here's what I've got:

Module:

package MyPackage; use strict; use warnings; use Exporter qw(import); our @ISA = qw(Exporter); our @EXPORT_OK = qw( func_one func_two ); our @EXPORT_PRIVATE = qw( _private_one _private_two ); our %EXPORT_TAGS = ( all => \@EXPORT_OK, private => \@EXPORT_PRIVATE, )

Test script:

use warnings; use strict; use MyPackage qw(:all :private); ...

When I run the script, I get:

"_private_one" is not exported by the MyModule module "_private_two" is not exported by the MyModule module Can't continue after import errors at ... line .... BEGIN failed--compilation aborted at ... line ...

I *thought* I'd done this before, but it turns out although I have other modules that have multiple tags, I've only ever tried to import one at a time, not multiple at once.

I'm sure I'm just having a brain fart moment here. Could someone please point out what I'm missing, or is this importing of multiple tags something that isn't available and I'm just finding out now?

Cheers,

-stevieb

Update: I just thought of something... I suppose I could insert the @EXPORT_OK array into the @EXPORT_PRIVATE one and then simply import the :private tag by itself, but now I'm curious as to whether that's the only way forward or not.

Replies are listed 'Best First'.
Re: Importing multiple %EXPORT_TAGS
by choroba (Cardinal) on Dec 28, 2020 at 00:30 UTC
    From Exporter:

    > Names in EXPORT_TAGS must also appear in @EXPORT or @EXPORT_OK.

    So the problem isn't you're trying to import two tags, the problem is you're trying to export something that's not exportable (as the error message tries to tell you, but without the knowledge of the quoted sentence, it's a bit enigmatic).

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

      Perfect, thanks choroba!

      That makes sense, and I completely overlooked that in the docs. Thankfully the couple of private functions I want to share are quasi-public anyway, so I'll just put them into @EXPORT_OK and make sure my documentation is clear on it.

      I made me a loophole:

      our @EXPORT_OK qw( func_one func_two ); our @EXPORT_PRIVATE = qw( _private_one _private_two ); our %EXPORT_TAGS = ( all => \@EXPORT_OK, private => _add_private(), ); sub _add_private { push @EXPORT_OK, @EXPORT_PRIVATE; return \@EXPORT_OK;

      Then in the script, use MyModule qw(:private);.

        If I read that correctly, you might want to check your namespace after importing :all...

        The _add_private sub will be called while initializing %EXPORT_TAGS, and it modifies @EXPORT_OK, which is also used to define (by reference) the :all tag. Data::Dumper should illustrate this if asked to dump the %EXPORT_TAGS hash.

        If you still want this, I suggest: (untested)

        # ... our %EXPORT_TAGS = ( all => [@EXPORT_OK], ); $EXPORT_TAGS{private} = _add_private(); # ...

        The %EXPORT_TAGS initialization is split into two statements to ensure a sequence point and avoid a possible undefined evaluation order. This ensures that the initial @EXPORT_OK is copied into a new array before _add_private modifies its contents.

Re: Importing multiple %EXPORT_TAGS
by Anonymous Monk on Dec 28, 2020 at 02:26 UTC
    Dont inherit from exporter

      What Anonymous Monk is saying is that the first line is already enough:

      use Exporter qw(import); our @ISA = qw(Exporter); # don't add this line!

        Thank you for this. Almost all of my distributions are Object Oriented, so I rarely ever use Exporter functionality.