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

Hey all,

I've looked all over but can't quite figure out how to do the following without what seems to be onerous code:

I have a module, "Foo/Core.pm" that has a few functions, variables, and tags (:DEFAULT, etc) to export.

I have another module, "Foo/Core/Specialized.pm" that I'd like to be able to have export all of Foo::Core's stuff, plus some other stuff -- including the ability to specify some parameters in the use line.

Here's a code example of what syntax I want:

... use Foo::Core::Specialized qw(Mixed func_a, func_b, :TAG_A); ...

I've got a custom Foo::Core::Specialized::import() sub that does this:

### From Foo::Core::Specialized use Foo::Core; sub import { my $this_pkg = shift; my @imports = @_; ### Catch the word "Mixed" in the import list and react to it, ### removing it before continuting. foreach (my $i = 0; $i < scalar(@imports); $i++) { if ($imports[$i] eq 'Mixed') { do_something(); splice(@imports, $i--, 1); } } ### The goal here is to switch to the calling package, do the ### import from the Foo::Core package into that calling package, ### then switch back to this package. The problem is, it ### doesn't work... there's no error, but the symbols aren't ### exported (anywhere I can find them =) either. my $caller = caller(); eval "package $caller;"; Foo::Core->import(@imports); eval "package $this_pkg;"; }

This kind of "parasitic" export would simply piggy-pack off the other module's export routine, adding some functionality of its own in some way or another.

When I use the Foo::Core package directly the symbols are exported properly (but obviously I don't get the specialized behavior). I could do:

... use Foo::Core qw(func_a, func_b, :DEFAULT); use Foo::Core::Specialized 'Mixed'; ...

but it seems like I shouldn't have to. If I *have* to loop through the @Foo::Core::EXPORT, @Foo::Core::EXPORT_OK, and %FOO::Core::EXPORT_TAGS lists and map the symbols manually, I can do that, but again ... it seems like I shouldn't have to.

I'm not sure if it matters, but the caller will be 'main' the vast majority of the time.

Thanks!

Updated: I forgot to mention that Foo::Core::Specialized uses Foo::Core

Replies are listed 'Best First'.
Re: Creating "parasitic" exports
by BrowserUk (Patriarch) on Nov 17, 2009 at 22:11 UTC
    I forgot to mention that Foo::Core::Specialized uses Foo::Core

    If you have F::C::S import everything from F::C, then F::C::S can the re-export anything its caller requests.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      Thanks for the suggestion =)

      That's what I tried first, but then I realized that every time the export list changes in Foo::Core, it has to be updated in Foo::Core::Specialized. That's a less elegant solution than re-implementing Exporter's import within my own, so I opted against it.

        every time the export list changes in Foo::Core, it has to be updated in Foo::Core::Specialized.

        Why? Why not just initialise F::C::S's EXPORT* vars from F::C's?

        package Foo::Core::Specialised; use Foo::Core ':all'; our @EXPORT = @Foo::Core:@EXPORT; our @EXPORT_OK = @Foo::Core::EXPORT_OK; our %EXPORT_TAGS = %Foo::Core::EXPORT_TAGS; ## Add, subtract or overwrite as required.

        That way F::C::S can export everything F::C can unless you explicitly remove it--self maintaining--plus anything you add or overwrite.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Creating "parasitic" exports
by almut (Canon) on Nov 18, 2009 at 18:40 UTC
    eval "package $caller;"; Foo::Core->import(@imports);

    I suppose this doesn't work because the package needs to be known at compile time...

    Try this

    eval "package $caller; Foo::Core->import(\@imports)";

    Update: something like this works for me:

    package Foo::Core; use Exporter qw(import); our @EXPORT_OK = qw(func_a); sub func_a { print "in func_a(): @_\n"; } 1; ----- package Foo::Core::Specialized; use Foo::Core; sub import { my $this_pkg = shift; my @imports = @_; foreach (my $i = 0; $i < scalar(@imports); $i++) { if ($imports[$i] eq 'Mixed') { print "doing something with 'Mixed'...\n"; splice(@imports, $i--, 1); } } my $caller = caller(); eval "package $caller; Foo::Core->import(\@imports)"; } 1; ----- #!/usr/bin/perl use Foo::Core::Specialized qw(Mixed func_a); func_a(42, 'foo'); __END__ $ ./807805.pl doing something with 'Mixed'... in func_a(): 42 foo