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

Hello all,

I wrote a module that has the single task of exporting all the symbols from one package up to its base package name.

E.g. Foo::Bar::Baz goes to just Baz and you can call Baz::quux().

This all works fine and I'm sure there's a module out there that already can do this but it's only a dozen lines of code or so. Anyway.

I'd like to be able to somehow cache what modules have already been exported so as to eliminate a lot of duplicate exports that happen.

I started with a poor man's memoization using a hash but no values ever get assigned to the hash since it's all executing at compile time (I guess).

I also tried inspecting the symbol table to see if the target package name (Baz) already had some CODE and skip it if so. The problem with that is a situation like this: "Foo::Bar qw(Baz)" and "Omg::Bbq qw(Baz)". Only one gets exported, the other dies when called.

So I call upon the wisdom of you, great monks, how to proceed.

Thanks, bmb

UPDATE: some code to illustrate the problem.

# Package/Exporter.pm package Package::Exporter; use strict; use warnings; use Carp qw[confess]; use Data::Dumper; sub import { my( $class, @exports ) = @_; # turn 'Foo::Bar' into 'Foo/Bar' ( my $class_path = $class ) =~ s{::}{/}g; for my $export( @exports ) { no strict 'refs'; # attempt to require 'Foo/Bar/Baz.pm' eval { require "$class_path/$export.pm"; }; # die if there was an error if( $@ ) { confess __PACKAGE__ . "::import ${class}::import problem w +ith $export - $@"; } # warn __PACKAGE__ . "::import ${class}::$export"; # import, just in case "${class}::$export"->import; # loop through everything in 'Foo::Bar::Baz::' my @all_in_namespace = keys %{"${class}::${export}::"}; # only the methods this time my @methods_in_namespace = grep { *{"${class}::${export}::${_} +"}{CODE} } @all_in_namespace; for my $method( @methods_in_namespace ) { # and assign 'Baz::method' to 'Foo::Bar::Baz::method' # warn sprintf( q["%s::%s" = sub () { "%s::%s::%s"}], $export, $method +, $class, $export, $method ); *{"${export}::${method}"}=\&{"${class}::${export}::${metho +d}"}; } } } 1;
# Foo/Bar.pm package Foo::Bar; use strict; use warnings; use base 'Package::Exporter'; 1;
# foo.pl use Foo::Bar qw(Baz); print Baz::quux(), "\n";
What I'd like to be able to do is somehow cache the fact that Foo::Bar::Baz was exported to Baz so the next time "use Foo::Bar qw(Baz);" is called, it skips the export.

Replies are listed 'Best First'.
Re: Import singleton?
by friedo (Prior) on Aug 10, 2006 at 13:41 UTC
    It would probably help to show some code. I have only a vague idea of what you're trying to do after reading your post twice.
Re: Import singleton?
by Tanktalus (Canon) on Aug 11, 2006 at 03:07 UTC

    One way strikes me: just create a variable that gets set to true once the import is called. For example:

    { my %imported; sub import { my( $class, @exports ) = @_; return if $imported{$class}++; # rest of your import here. } }
    By closing on a lexical like this, it won't show up in your namespace. Not that it probably matters, but it may be a good trick to avoid this module from exporting "globals" from other packages upwards.