in reply to Importing multiple %EXPORT_TAGS

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]

Replies are listed 'Best First'.
Re^2: Importing multiple %EXPORT_TAGS
by stevieb (Canon) on Dec 28, 2020 at 00:34 UTC

    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.

Re^2: Importing multiple %EXPORT_TAGS
by stevieb (Canon) on Dec 28, 2020 at 00:39 UTC

    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.

        Great catch!

        However, the separation isn't needed. As soon as I saw you put the EXPORT_OK into an anonymous array, changed from the taking of the reference as I had it, I realized that's all that was needed. So all now instead of being a reference to the array, it's a reference to a copy of it:

        our %EXPORT_TAGS = ( all => [ @EXPORT_OK ], private => _export_private(), ); sub _export_private { push @EXPORT_OK, @EXPORT_PRIVATE; return \@EXPORT_OK; }

        Output:

        $VAR1 = { 'private' => [ 'add_bugtracker', 'add_repository', 'changes', 'changes_bump', 'changes_date', 'ci_badges', 'ci_github', 'git_ignore', 'init', 'make_test', 'manifest_skip', 'move_distribution_files', 'remove_unwanted_files', 'version_bump', 'version_info', '_git_commit', '_git_push', '_validate_git' ], 'all' => [ 'add_bugtracker', 'add_repository', 'changes', 'changes_bump', 'changes_date', 'ci_badges', 'ci_github', 'git_ignore', 'init', 'make_test', 'manifest_skip', 'move_distribution_files', 'remove_unwanted_files', 'version_bump' 'version_info', ] };