Search code examples
functionclassperlsubclasscode-duplication

How can I run the same code throughout my Perl scripts with as little code duplication as possible?


I have a subroutine, csay, that's defined in a Perl class (package). There are several subclasses of it that run that subroutine often and throughout themselves. Its behaviour depends on a few variables (most of which must be given as arguments), one of which is constant within any lexical scope ($debug_level). I'm trying to avoid duplicating code as much as possible, including having to pass the "constant" variable as an argument every single time or prefixing every usage with $self->.

I'm not against using compile-time substitution (if such a thing exists in Perl), but I'd like to avoid using instances (blessing hashes, etc) if possible. See below for an example of what I'm trying to do. Any ideas?

package SystemManager::Action::Generic;

sub csay($self, $cur_debug_level, $min_debug_level, $message) {
    if ($cur_debug_level >= $min_debug_level) { print("$message\n"); }
}

sub prepare_system($self)...

package SystemManager::Action::Backup;
use parent "SystemManager::Action::Generic";

sub backup_system($self,$debug_level,@files) {
    $self->csay($debug_level, 1, "Starting backup");
    $self->prepare_system();
    $self->csay($debug_level, 1, "Iterating through files");
    for my $file in (@files) {
        $self->csay($debug_level, 2, "Processing $file");
        ...
    }
    ...
}

csay doesn't need to be part of the same class; the most important part is to not have to specify $debug_level as an argument every single time.


Solution

  • As an alternative to the answer by Håkon Hægland, you could use an exportable our variable:

    package SystemManager::Action::Generic;
    our $cur_debug_level = 0;
    our @EXPORT = qw($cur_debug_level); # or @EXPORT_OK to export explicitly only
    
    sub csay($self, $min_debug_level, $message) {
        if ($cur_debug_level >= $min_debug_level) { print("$message\n"); }
    }
        
    package SystemManager::Action::Backup;
    use parent "SystemManager::Action::Generic";
    
    sub backup_system($self,@files) {
        $self->csay(1, "Starting backup");
        $self->prepare_system();
        $self->csay(1, "Iterating through files");
        for my $file in (@files) {
            $self->csay(2, "Processing $file");
            ...
        }
        ...
    }
    
    package main;
    use SystemManager::Action::Backup;
    $cur_debug_level = 2;
    my $backup = Backup->new();
    $backup->backup_system(<*.txt>);