I have come across the interesting problem of reloading a module.

There is Symbol::delete_package(), but if called to delete 'Foo::Bar', it will
delete $Foo::{Bar::} stash, effectively wiping along every Foo::Bar::* package.

I need to be able to 'unload' package Foo::Bar, so I can reload it with the
equivalent of eval "use Foo::Bar";

Here is the solution I came up with and I wanted to get some feedback on it.

Basically, instead of just wiping the child stash from the parent stash, I
iterate over stash entries for that package, wiping everything that's not a
substash (i.e. ending in '::').

I also unload the module with DynaLoader if it was an XS module so it will be
reloaded on the second 'use'.

Am I doing something terribly wrong ? Is there any harm in doing something like
this ?

I realize that, for instance, if some other package took a ref to a subroutine
in package Foo::Bar, after reloading Foo::Bar would still hold a ref to the _old_
instance of that subroutine. And that's a good thing, AFAIK

sub package2filename {
    my $package = shift;
    $package =~ s[::][/]g;
    $package .= '.pm';
    return $package;
}

sub unload_package {
    my $package = shift;
    my ($stash, $dynamic);

    {
        no strict 'refs';
        $stash = \%{$package . '::'};
    }

    # Figure out if this module was dynamically loaded
    for (my $i = 0 ; $i < @DynaLoader::dl_modules ; $i++) {
        if ($DynaLoader::dl_modules[$i] eq $package) {
            $dynamic = splice(@DynaLoader::dl_librefs, $i);
            splice(@DynaLoader::dl_modules, $i);
        }
    }

    # wipe every entry in the stash except the sub-stashes
    while (my ($name, $glob) = each %$stash) {
        if ($name !~ /::$/) {
            delete $stash->{$name};
        }
    }

    # Unload the .so
    if ($dynamic) {
        DynaLoader::dl_unload_file($dynamic);
    }

    # Clear package from %INC
    delete $INC{package2filename($package)};
}


-- -------------------------------------------------------------------------------- Philippe M. Chiasson m/gozer\@(apache|cpan|ectoplasm)\.org/ GPG KeyID : 88C3A5A5 http://gozer.ectoplasm.org/ F9BF E0C2 480E 7680 1AE5 3631 CB32 A107 88C3A5A5

Attachment: signature.asc
Description: OpenPGP digital signature



Reply via email to