package Exporter; =head1 Comments If the first entry in an import list begins with !, : or / then the list is treated as a series of specifications which either add to or delete from the list of names to import. They are processed left to right. Specifications are in the form: [!]name This name only [!]:DEFAULT All names in @EXPORT [!]:tag All names in $EXPORT_TAGS{tag} anonymous list [!]/pattern/ All names in @EXPORT and @EXPORT_OK which match A leading ! indicates that matching names should be deleted from the list of names to import. If the first specification is a deletion it is treated as though preceded by :DEFAULT. If you just want to import extra names in addition to the default set you will still need to include :DEFAULT explicitly. e.g., Module.pm defines: @EXPORT = qw(A1 A2 A3 A4 A5); @EXPORT_OK = qw(B1 B2 B3 B4 B5); %EXPORT_TAGS = (T1 => [qw(A1 A2 B1 B2)], T2 => [qw(A1 A2 B3 B4)]); Note that you cannot use tags in @EXPORT or @EXPORT_OK. Names in EXPORT_TAGS must also appear in @EXPORT or @EXPORT_OK. Application says: use Module qw(:DEFAULT :T2 !B3 A3); use Socket qw(!/^[AP]F_/ !SOMAXCONN !SOL_SOCKET); use POSIX qw(/^S_/ acos asin atan /^E/ !/^EXIT/); You can set C<$Exporter::Verbose=1;> to see how the specifications are being processed and what is actually being imported into modules. =head2 Module Version Checking The Exporter module will convert an attempt to import a number from a module into a call to $module_name->require_version($value). This can be used to validate that the version of the module being used is greater than or equal to the required version. The Exporter module supplies a default require_version method which checks the value of $VERSION in the exporting module. =cut require 5.001; $ExportLevel = 0; $Verbose = 0; require Carp; sub export { # First make import warnings look like they're coming from the "use". local $SIG{__WARN__} = sub { my $text = shift; $text =~ s/ at \S*Exporter.pm line \d+.\n//; local $Carp::CarpLevel = 1; # ignore package calling us too. Carp::carp($text); }; local $SIG{__DIE__} = sub { Carp::croak("$_[0]Illegal null symbol in \@${1}::EXPORT") if $_[0] =~ /^Unable to create sub named "(.*?)::"/; }; my $pkg = shift; my $callpkg = shift; my @imports = @_; my($type, $sym); *exports = \@{"${pkg}::EXPORT"}; if (@imports) { my $oops; *exports = \%{"${pkg}::EXPORT"}; if (!%exports) { grep(s/^&//, @exports); @exports{@exports} = (1) x @exports; foreach $extra (@{"${pkg}::EXPORT_OK"}) { $exports{$extra} = 1; } } if ($imports[0] =~ m#^[/!:]#){ my(@allexports) = keys %exports; my $tagsref = \%{"${pkg}::EXPORT_TAGS"}; my $tagdata; my %imports; # negated first item implies starting with default set: unshift(@imports, ':DEFAULT') if $imports[0] =~ m/^!/; foreach (@imports){ my(@names); my($mode,$spec) = m/^(!)?(.*)/; $mode = '+' unless defined $mode; @names = ($spec); # default, maybe overridden below if ($spec =~ m:^/(.*)/$:){ my $patn = $1; @names = grep(/$patn/, @allexports); # XXX anchor by default? } elsif ($spec =~ m#^:(.*)# and $tagsref){ if ($1 eq 'DEFAULT'){ @names = @exports; } elsif ($tagsref and $tagdata = $tagsref->{$1}) { @names = @$tagdata; } } warn "Import Mode $mode, Spec $spec, Names @names\n" if $Verbose; if ($mode eq '!') { map {delete $imports{$_}} @names; # delete @imports{@names} would be handy :-) } else { @imports{@names} = (1) x @names; } } @imports = keys %imports; } foreach $sym (@imports) { if (!$exports{$sym}) { if ($sym =~ m/^\d/) { $pkg->require_version($sym); # If the version number was the only thing specified # then we should act as if nothing was specified: if (@imports == 1) { @imports = @exports; last; } } elsif ($sym !~ s/^&// || !$exports{$sym}) { warn qq["$sym" is not exported by the $pkg module ], "at $callfile line $callline\n"; $oops++; next; } } } Carp::croak("Can't continue with import errors.\n") if $oops; } else { @imports = @exports; } warn "Importing from $pkg into $callpkg: ", join(", ",@imports),"\n" if ($Verbose && @imports); foreach $sym (@imports) { $type = '&'; $type = $1 if $sym =~ s/^(\W)//; *{"${callpkg}::$sym"} = $type eq '&' ? \&{"${pkg}::$sym"} : $type eq '$' ? \${"${pkg}::$sym"} : $type eq '@' ? \@{"${pkg}::$sym"} : $type eq '%' ? \%{"${pkg}::$sym"} : $type eq '*' ? *{"${pkg}::$sym"} : warn "Can't export symbol: $type$sym\n"; } }; sub import { local ($callpkg, $callfile, $callline) = caller($ExportLevel); my $pkg = shift; export $pkg, $callpkg, @_; } sub export_tags { my ($pkg) = caller; *tags = \%{"${pkg}::EXPORT_TAGS"}; push(@{"${pkg}::EXPORT"}, map {$tags{$_} ? @{$tags{$_}} : $_} @_ ? @_ : keys %tags); } sub require_version { my($self, $wanted) = @_; my $pkg = ref $self || $self; my $version = ${"${pkg}::VERSION"} || "(undef)"; Carp::croak("$pkg $wanted required--this is only version $version") if $version < $wanted; $version; } 1;