You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
5.7 KiB
225 lines
5.7 KiB
package Exporter;
|
|
|
|
=head1 NAME
|
|
|
|
Exporter::Heavy - Exporter guts
|
|
|
|
=head1 SYNOPIS
|
|
|
|
(internal use only)
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
No user-serviceable parts inside.
|
|
|
|
=cut
|
|
#
|
|
# We go to a lot of trouble not to 'require Carp' at file scope,
|
|
# because Carp requires Exporter, and something has to give.
|
|
#
|
|
|
|
sub heavy_export {
|
|
|
|
# First make import warnings look like they're coming from the "use".
|
|
local $SIG{__WARN__} = sub {
|
|
my $text = shift;
|
|
if ($text =~ s/ at \S*Exporter\S*.pm line \d+.*\n//) {
|
|
require Carp;
|
|
local $Carp::CarpLevel = 1; # ignore package calling us too.
|
|
Carp::carp($text);
|
|
}
|
|
else {
|
|
warn $text;
|
|
}
|
|
};
|
|
local $SIG{__DIE__} = sub {
|
|
require Carp;
|
|
local $Carp::CarpLevel = 1; # ignore package calling us too.
|
|
Carp::croak("$_[0]Illegal null symbol in \@${1}::EXPORT")
|
|
if $_[0] =~ /^Unable to create sub named "(.*?)::"/;
|
|
};
|
|
|
|
my($pkg, $callpkg, @imports) = @_;
|
|
my($type, $sym, $oops);
|
|
*exports = *{"${pkg}::EXPORT"};
|
|
|
|
if (@imports) {
|
|
if (!%exports) {
|
|
grep(s/^&//, @exports);
|
|
@exports{@exports} = (1) x @exports;
|
|
my $ok = \@{"${pkg}::EXPORT_OK"};
|
|
if (@$ok) {
|
|
grep(s/^&//, @$ok);
|
|
@exports{@$ok} = (1) x @$ok;
|
|
}
|
|
}
|
|
|
|
if ($imports[0] =~ m#^[/!:]#){
|
|
my $tagsref = \%{"${pkg}::EXPORT_TAGS"};
|
|
my $tagdata;
|
|
my %imports;
|
|
my($remove, $spec, @names, @allexports);
|
|
# negated first item implies starting with default set:
|
|
unshift @imports, ':DEFAULT' if $imports[0] =~ m/^!/;
|
|
foreach $spec (@imports){
|
|
$remove = $spec =~ s/^!//;
|
|
|
|
if ($spec =~ s/^://){
|
|
if ($spec eq 'DEFAULT'){
|
|
@names = @exports;
|
|
}
|
|
elsif ($tagdata = $tagsref->{$spec}) {
|
|
@names = @$tagdata;
|
|
}
|
|
else {
|
|
warn qq["$spec" is not defined in %${pkg}::EXPORT_TAGS];
|
|
++$oops;
|
|
next;
|
|
}
|
|
}
|
|
elsif ($spec =~ m:^/(.*)/$:){
|
|
my $patn = $1;
|
|
@allexports = keys %exports unless @allexports; # only do keys once
|
|
@names = grep(/$patn/, @allexports); # not anchored by default
|
|
}
|
|
else {
|
|
@names = ($spec); # is a normal symbol name
|
|
}
|
|
|
|
warn "Import ".($remove ? "del":"add").": @names "
|
|
if $Verbose;
|
|
|
|
if ($remove) {
|
|
foreach $sym (@names) { delete $imports{$sym} }
|
|
}
|
|
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;
|
|
}
|
|
# We need a way to emulate 'use Foo ()' but still
|
|
# allow an easy version check: "use Foo 1.23, ''";
|
|
if (@imports == 2 and !$imports[1]) {
|
|
@imports = ();
|
|
last;
|
|
}
|
|
} elsif ($sym !~ s/^&// || !$exports{$sym}) {
|
|
require Carp;
|
|
Carp::carp(qq["$sym" is not exported by the $pkg module]);
|
|
$oops++;
|
|
}
|
|
}
|
|
}
|
|
if ($oops) {
|
|
require Carp;
|
|
Carp::croak("Can't continue after import errors");
|
|
}
|
|
}
|
|
else {
|
|
@imports = @exports;
|
|
}
|
|
|
|
*fail = *{"${pkg}::EXPORT_FAIL"};
|
|
if (@fail) {
|
|
if (!%fail) {
|
|
# Build cache of symbols. Optimise the lookup by adding
|
|
# barewords twice... both with and without a leading &.
|
|
# (Technique could be applied to %exports cache at cost of memory)
|
|
my @expanded = map { /^\w/ ? ($_, '&'.$_) : $_ } @fail;
|
|
warn "${pkg}::EXPORT_FAIL cached: @expanded" if $Verbose;
|
|
@fail{@expanded} = (1) x @expanded;
|
|
}
|
|
my @failed;
|
|
foreach $sym (@imports) { push(@failed, $sym) if $fail{$sym} }
|
|
if (@failed) {
|
|
@failed = $pkg->export_fail(@failed);
|
|
foreach $sym (@failed) {
|
|
require Carp;
|
|
Carp::carp(qq["$sym" is not implemented by the $pkg module ],
|
|
"on this architecture");
|
|
}
|
|
if (@failed) {
|
|
require Carp;
|
|
Carp::croak("Can't continue after import errors");
|
|
}
|
|
}
|
|
}
|
|
|
|
warn "Importing into $callpkg from $pkg: ",
|
|
join(", ",sort @imports) if $Verbose;
|
|
|
|
foreach $sym (@imports) {
|
|
# shortcut for the common case of no type character
|
|
(*{"${callpkg}::$sym"} = \&{"${pkg}::$sym"}, next)
|
|
unless $sym =~ s/^(\W)//;
|
|
$type = $1;
|
|
*{"${callpkg}::$sym"} =
|
|
$type eq '&' ? \&{"${pkg}::$sym"} :
|
|
$type eq '$' ? \${"${pkg}::$sym"} :
|
|
$type eq '@' ? \@{"${pkg}::$sym"} :
|
|
$type eq '%' ? \%{"${pkg}::$sym"} :
|
|
$type eq '*' ? *{"${pkg}::$sym"} :
|
|
do { require Carp; Carp::croak("Can't export symbol: $type$sym") };
|
|
}
|
|
}
|
|
|
|
sub heavy_export_to_level
|
|
{
|
|
my $pkg = shift;
|
|
my $level = shift;
|
|
(undef) = shift; # XXX redundant arg
|
|
my $callpkg = caller($level);
|
|
$pkg->export($callpkg, @_);
|
|
}
|
|
|
|
# Utility functions
|
|
|
|
sub _push_tags {
|
|
my($pkg, $var, $syms) = @_;
|
|
my $nontag;
|
|
*export_tags = \%{"${pkg}::EXPORT_TAGS"};
|
|
push(@{"${pkg}::$var"},
|
|
map { $export_tags{$_} ? @{$export_tags{$_}} : scalar(++$nontag,$_) }
|
|
(@$syms) ? @$syms : keys %export_tags);
|
|
if ($nontag and $^W) {
|
|
# This may change to a die one day
|
|
require Carp;
|
|
Carp::carp("Some names are not tags");
|
|
}
|
|
}
|
|
|
|
# Default methods
|
|
|
|
sub export_fail {
|
|
my $self = shift;
|
|
@_;
|
|
}
|
|
|
|
sub require_version {
|
|
my($self, $wanted) = @_;
|
|
my $pkg = ref $self || $self;
|
|
my $version = ${"${pkg}::VERSION"};
|
|
if (!$version or $version < $wanted) {
|
|
$version ||= "(undef)";
|
|
# %INC contains slashes, but $pkg contains double-colons.
|
|
my $file = (map {s,::,/,g; $INC{$_}} "$pkg.pm")[0];
|
|
$file &&= " ($file)";
|
|
require Carp;
|
|
Carp::croak("$pkg $wanted required--this is only version $version$file")
|
|
}
|
|
$version;
|
|
}
|
|
|
|
1;
|