Question

I'll just start out by saying I am not at all experienced with creating Perl modules so I'm sorry if I'm way off here.

Let's say I am creating a few modules:

foo::bar
foo::bar::a
foo::bar::b

Since I don't know what they are called, I am calling the a.pm and b.pm modules "sub modules" since they are related to the bar.pm module, but could still be somewhat independent.

So one of my Perl scripts could use foo::bar::a, another script could use foo::bar::b, and maybe I have another script that needs to use functions from both "a" and "b". Instead of saying this:

use foo::bar;
use foo::bar::a qw(one two);
use foo::bar::b;

I want to do something like this:

use foo::bar qw(:a :b);

In my mind, that would give my script access to everything in bar.pm, a.pm, and b.pm.

I tested something like this, and I was obviously wrong.

Is something like this possible? I suppose I could have bar.pm use a.pm and b.pm, and then have "wrapper" functions that pass the call onto the "sub modules" but it seems like there would be an easier way.

Was it helpful?

Solution

Look at my Test::Data module for an example about doing that. Even though you can make it happen, I've never been terribly fond of the result. You might want to consider a Plugin or Mixin approach instead. There are some modules on CPAN that can help with this.

Here's the custom import that I wrote for Test::Data:

sub import 
    {
    my $self   = shift;
    my $caller = caller;

    foreach my $package ( @_ )
        {
        my $full_package = "Test::Data::$package";
        eval "require $full_package; 1";
        if( $@ )
            {
            carp "Could not require Test::Data::$package: $@";
            }

        $full_package->export($caller);
        }

    }

OTHER TIPS

Yes, you can do that. It will probably involve writing a custom 'sub import' in foo::bar that interprets incoming arguments the way you want.

Probably you're using Exporter right now, and it's its lack of support for your syntax that's the issue. You'll find that there's nothing particularly special about the module syntax Exporter implements; it's just a common convention. You'll likely want to look at how it does business to get insight into how you'll want to, though.

If you don't know what a module is called, why are you including it? You shouldn't need to include it. Only include a module in the (calling) module that needs it, and nowhere else.

That is: if you are using it, then "use" it. If you don't use it, don't "use" it.

Yes, but you have to rig your own import sub:

use strict;
use warnings;

package ab;
use base qw<Exporter>;
our @EXPORT_OK;
our %EXPORT_TAGS;
BEGIN { 
    @EXPORT_OK   = qw<>;
    %EXPORT_TAGS = ( a => 1, b => 1, all => \@EXPORT_OK );
}

sub setup_part { 
    #use Smart::Comments;
    my $code = shift;
    my $mini_path = "foo/bar/$code.pm";
    return if exists $INC{$mini_path};
    require $mini_path; 
    my $arr_ref 
        = do { no strict 'refs';
            \@{Symbol::qualify( 'EXPORT_OK', $code )};
        };
    $code->import( @$arr_ref );
    push @EXPORT_OK, @$arr_ref;
    $EXPORT_TAGS{$code} = [ @$arr_ref ];
    return;
}

sub import { 
    my ( $package_name, @imports ) = @_;
    my %import_hash = map { $_ => 1 } @imports;
    if ( exists $import_hash{':all'} ) { 
        @import_hash{qw<:a :b>} = ( 1, 1 );
    }
    foreach my $import ( grep { exists $import_hash{$_} } qw<:a :b> ) { 
        setup_part( substr( $import, 1 ));
    }
    goto &{Exporter->can( 'import' )};
}

1;

Also try looking at Class::MixinFactory

I have looked for the solution similar to the recent one. I know -- too old thread but I'd like to comment the answer (Feb 12 '09 at 17:55) by brian d foy but sadly I don't have enough reputation to accomplish this. That's why I add my comment as new response.

His answer has helped me to solve the issue similar to the recent one. But it requires some modification if is used with use lib.

I have a bunch of modules that look like A::B::*. Those should be loaded to scripts by the general module A::B. All those modules are within their files under the same directory as the loading script. Using the mechanism suggested by brian d foy we can get many subroutine redefined errors. To avoid all of them, I believe, I found better solution, better than no warnings 'redefine'. Now we are free to use use lib, no warnings 'redefine' or shift @INC, ... in the main script.

    sub import {
        @TAGS = ( @_ );
        my $me = shift @TAGS;

        ( my $pm = $me ) =~ s|::|/|g;
        $pm .= ".pm";

        ( $dir = $INC{$pm} ) =~ s/\.pm$//;
        foreach ( glob "$dir/*.pm" ) {
            /(\w+)\.pm$/;
            my $module = "${me}::$1";

            eval "use $module qw(:all)"; # You are free to use any items in the exporting list
            die "$me: Error while loading $module from $_: $@\n" if $@;
        }

        # Fill in @EXPORT_OK and %EXPORT_TAGS manually from each A::B::*::EXPORT_OK
        # ...

        goto &{ Exporter->can( "import" ) };
    }

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top