Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reloading modules and redefining subroutines in Perl

I'm currently experimenting with reloading a module. The aim I'm hoping to achieve is to be able to change something in the defined subroutine in the module file, and then reload that module, using the new definitions.

Currently, I am changing the print statement in the test subroutine to print "this is some different text" after waiting for the subroutine to execute the original code, and before the module is reloaded.

However, what I'm currently getting is the message:
Subroutine test redefined at /Test/testmodule.pm line 9.

This is exactly what I want, but the output is as follows.

this is some text
Subroutine test redefined at /Test/testmodule.pm line 9.
this is some text

What I'm hoping is that when the module is reloaded, and it realises that the subroutine has been redefined, is that next time it executes the test subroutine, it will refer to the new definition rather than the old one.

I've searched through previous questions on reloading modules, but the answers given were things like looping dependencies (package A uses B, and B uses A), or namespace collision in packages, but this is not the issue at hand here. I want the subroutine to be redefined, and the new definition used.

source code: main.pl

#!/usr/bin/perl
use strict;
use warnings;
use Module::Reload::Selective;
use Test::testmodule;

while(1) {
    test(); #run module's define subroutine
    sleep(5); #stop terminal from being flooded too quickly

    #Ensure that the module is reloaded
    $Module::Reload::Selective::Options->{SearchProgramDir} = 1;
    $Module::Reload::Selective::Options->{ReloadOnlyIfEnvVarsSet} = 0;
    Module::Reload::Selective->reload(qw(Test::testmodule)); #reload!
}

source code: testmodule.pm (in ./Test/ relative to main.pl)

#!/usr/bin/perl
use strict;
use warnings;

# allow exportation
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(test);

sub test {
    print("this is some text\n"); # this line is edited in the source file to
                                  # 'print("this is some different text\n");'
}
1;

Any pointers or references to tutorials would be brilliant. In fact, if the answer isn't incredibly simple, not telling me the answer directly will allow me to read your suggested material and gain an overall better understanding.

All required CPAN modules have been installed, and I can confirm that the testmodule.pm is being successfully written after changing.

OS: Scientific Linux CERN 6, kernel version 2.6.32-131.4.1.el6.x86_64
Perl: v5.10.1 (*) built for x86_64-linux-thread-multi

Many thanks in advance,
Owen.

like image 285
OwenD Avatar asked Jan 20 '23 04:01

OwenD


1 Answers

I don't know if this is the problem or not yet, but you are missing your package statement in the module. This means test is main::test not Test::testmodule::test.

Yep, it was a combination of cjm's answer and mine. This code works for me:

In Test/testmodule.pm:

package Test::testmodule;

use strict;
use warnings;

# allow exportation
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(test);

sub test {
    print "this is some text, counter 1\n";
}

1;

In main.pl:

#!/usr/bin/perl
use strict;
use warnings;
use Module::Reload::Selective;
use Test::testmodule;

while(1) {
    test(); #run module's define subroutine

    my $module = do {
        open my $fh, "<", "Test/testmodule.pm"
            or die "could not open the module: $!";

        local $/;
        <$fh>;
    };

    $module =~ s/counter ([0-9])/"counter " . ($1 + 1)/e;

    open my $fh, ">", "Test/testmodule.pm"
        or die "could not open the module: $!";

    print $fh $module;

    close $fh;

    #Ensure that the module is reloaded
    $Module::Reload::Selective::Options->{SearchProgramDir} = 1;
    $Module::Reload::Selective::Options->{ReloadOnlyIfEnvVarsSet} = 0;
    Module::Reload::Selective->reload(qw(Test::testmodule));
    Test::testmodule->import;
} continue {
    sleep 1;
}

To clarify, Perl 5 does not create a namespace when you create a .pm file. It creates a namespace when you say package NamespaceName or you reference that namespace like this

sub Test::testmodule::test {
    print "this is some text, counter 1\n";
}

Since the test function in your version was not in a the Test::testmodule namespace, it never got reloaded.

like image 139
Chas. Owens Avatar answered Jan 30 '23 04:01

Chas. Owens