wanna_code_perl has asked for the wisdom of the Perl Monks concerning the following question:
I'm working on a non-OO module that has a number of subs that are dynamically created and added to the symbol table. Their names are known at compile time, so I could certainly hard-code them in, but I'm a fan of DRY and would rather just specify them once.
When the module is loaded I have several subs that are string-eval'd into existence. In reality the body of the subs is more complex than a simple tr//, but this demonstrates the problem well enough. Everything works fine, but I'm stuck on the simple task of convincing Exporter::Easy to export the subs. I can make it work with Exporter just fine:
package Foo; use strict; use warnings; use Carp; my %subs = ( subA => _gen_tr('abc' => 'xyz'), subB => _gen_tr('ijk' => 'qrs'), ); $subs{reverse($_)} = $subs{$_} for keys %subs; # Stand-in example for +aliases no strict 'refs'; *$_ = $subs{$_} for keys %subs; require Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = keys %subs; sub _gen_tr { /^\w+$/ or confess "Non-word characters in argument: <$_>" for @_; eval "sub { shift =~ tr/$_[0]/$_[1]/r }" } 1;
The above works fine; all subs and their aliases are exported as expected (passes test code at the end of this post).
But when I replace the require Exporter; our @ISA ...; our @EXPORT_OK ...; lines with a similar Exporter::Easy incantation:
use Exporter::Easy ( OK => [ keys %subs ], TAGS => [ all => [ keys %subs ], ], );
Code using Foo sees "subA" is not exported by the Foo module, whether I use Foo ':all' or specify subA directly. I've even tried wrapping the exports and actual %subs initialization in a BEGIN block, but that did not make a difference. Hardcoding the sub names directly in the OK => [ ... ] or all => [ ... ] lines does of course work, but that's exactly what I'm trying to avoid doing.
Why Exporter::Easy? One reason is, I like it. The "real" reason is, my full code has more tags and more complex exports. I can do what I want with Exporter, but it's ugly. I'm willing to consider other Exporter::* modules if Exporter::Easy can't handle it. Or, I suppose, to suck it up and use Exporter if there's no other way.
So how would you do it? $cake->have->eat;
Test code:
use strict; use warnings; use Test::More; # Pick one: #use Foo qw/subA subB Abus Bbus/; use Foo ':all'; is subA('abra-cadabra'), 'xyrx-zxdxyrx'; is subB('i like stuff'), 'q lqse stuff'; is Abus('abra-cadabra'), 'xyrx-zxdxyrx'; is Bbus('i like stuff'), 'q lqse stuff'; done_testing;
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Dynamic exports with Exporter::Easy
by Athanasius (Archbishop) on Oct 22, 2019 at 03:22 UTC | |
by wanna_code_perl (Friar) on Oct 22, 2019 at 05:53 UTC | |
|
Re: Dynamic exports with Exporter::Easy
by Anonymous Monk on Oct 22, 2019 at 10:18 UTC |