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

Hello all,

Imagine this - I was extremely bored at work one day and I wrote an IRC bot that did a few things (i.e. auto-op'ing certain users in the channel, checking bittorrent rss feeds etc). What I want to do is to make changes to how the bot handles things - without having to restart it.

Easy! I thought - if I can just get the script to load the module upon demand (simple), and unload it when finished (a tad trickier), so that the module is forced to load next time, picking up any changes I made in the module since the last usage.

I've looked through a bunch of webpages and books to no avail. Looking in the wrong places? maybe, dunno ... if I knew I wouldn't be asking here :)

So - does anybody know how I could accomplish the above? Or could somebody at least point me in the direction of where I should be looking (wherefore pointing out what I missed finding already)?

Any help much appreciated.

Replies are listed 'Best First'.
Re: Loading/Unloading Modules?
by adamk (Chaplain) on Apr 16, 2005 at 09:55 UTC
    "Reloading" of modules is pretty much a 4 step process.

    1. Run anything custom you need to do (like disconnecting from database handles or unloading plugins)
    2. Delete all your symbol table $stuff
    3. Delete your %INC entry
    4. require My::Module

    The tricky bit is 1. and 2.

    You can't do 1. for _any_ arbitrary class, it needs intimate knowledge of the module itself... what if it's a Singleton that has handles to itself still outstanding?

    When doing 2. you have to ensure that you both delete everything needed (including various child classes) and DON'T delete things you shouldn't (like separate modules that occupy lower namespaces that should stay intact).

    Otherwise, it should be relatively easy. But very case-specific.
Re: Loading/Unloading Modules?
by gam3 (Curate) on Apr 16, 2005 at 03:43 UTC
Re: Loading/Unloading Modules?
by brian_d_foy (Abbot) on Apr 16, 2005 at 16:36 UTC

    You can look at Apache::StatINC and Apache::Reload for examples.

    You might be able to simply have the Perl program exec() itself.

    --
    brian d foy <brian@stonehenge.com>
Re: Loading/Unloading Modules?
by betterworld (Curate) on Apr 16, 2005 at 12:38 UTC
    Consider this litte program:
    #!/usr/bin/perl use strict; use warnings; our $foo; sub do_something { $foo++; print "$foo\n"; } our $running; if (!$running) { $foo = 0; $running = 1; $SIG{INT} = sub {do $0}; for (;;) { sleep (1); do_something(); } }
    This will output increasing numbers.
    Now change its source code while it is running, for instance change "$foo++" to "$foo+=5". Then send the program a SIGINT by pressing ^C (don't know if this works on Windows). You will get a warning about a redefined subroutine, but then the program continues running with its old variables and a new do_something subroutine.
    I experienced that this is particularly useful for programs like IRC bots to change the code without having to stop the programs.
    If you put the subroutine into a module, you will probably be able to leave out the $running stuff and make everything simpler.
      Thanks for the reply - however the problem with this is that I deally I don't want to have to send a signal or anything each time I change code. Ideally the change over would be seemless - i.e. I copy the new module into place and it is automatically picked up next time that module is actually needed.

      This is different to the bot's config file which it reloads whenever I tell it too in the channel (what a good little bot).

      Playing around with a few things after everyone's answers I combined replies and came up with a veriant on davidrw's test script that uses Symbol::delete_package as well as deletes the module from %INC. Seems to work so far :)

      Now the big test is to get it going within my bot and it's framework.

      Thanks for everybodies help.
Re: Loading/Unloading Modules?
by davidrw (Prior) on Apr 16, 2005 at 02:41 UTC
    I don't know much about the inner workings of modules & loading/unloading, but this appears to work:
    This is X1.pm:
    package X; sub new { my $self = shift; printf "new() v1\n"; return bless {}, $self; } sub blah { printf "blah v1\n"; } 1;
    This is X2.pm:
    package X; sub new { my $self = shift; printf "new() v2\n"; return bless {}, $self; } sub blah { printf "blah v2\n"; } 1;
    This is the test script, x.pl:
    #!/usr/bin/perl use lib '.'; use X; my $x1 = X->new(); $x1->blah; printf "Copying in X2.pm\n"; system("cp X2.pm X.pm"); printf "Trying X.pm\n"; eval `cat X.pm`; $x1->blah; my $x2 = X->new();
    And this is the execution and output:
    [me@host tmp]$ cp X1.pm X.pm [me@host tmp]$ ./x.pl new() v1 blah v1 Copying in X2.pm Trying X.pm blah v2 new() v2
    While it didn't work for we to just 'use' or 'require' the modules again (i didn't really except it to, especially 'use' since that's done early on), it appears to work to eval in the new module. Is this a good or a horrible implementation/usage? I really can't say--hopefully someone wiser will comment...

      You have to delete the filename and filepath from %INC for use or require to work:

      use X2; print "Reusing X2\n"; delete $INC{'X2.pm'}; require X2;