Search code examples
perlperl-module

perl: "unincluding" modules


so, i have a program like this:

#!/usr/bin/perl -w  
use strict;  
foreach (@data) {  
    if($_ eq "foo") {  
        use Foo;
        process();
    }  
    if($_ eq "bar") {  
        use Bar;
        process();
    }  
...  
}

Each included module is somewhat similar, the only difference being what the process()-sub does.

#!/usr/bin/perl -w  
use strict;  
sub process {  
...  
}

My issue: the input for the main script is a (possibly long) list of things, while processing that list i get continuous "Subroutine redefined" errors (obviously). Is there any way to "un-use" a module?
Due to the fact that the library of possible "actions" to include may grow in the future, i thought this way of including modules dynamically would be the best approach. Many thanks for your help :)


Solution

  • As @pilcrow said, you can solve this issue quickly by using require instead of use, but, I think this is a good example where Polymorphism is to be used.

    You can create a base class like:

    package Processors::Base;
    
    sub new{
      my $class = shift;
      return bless {}, $class;
    }
    
    sub process{
      die "You can only use a subclass of me";
    }
    
    1;
    

    And then, create your processors as packages that inherit from this base package.

    package Processors::Foo;
    
    sub process{
      ... do stuff ...
    }
    
    1;
    

    Then your code could look like:

    #!/usr/bin/perl -w  
    use strict;  
    for my $pkg (@data) { 
        (my $path = $pkg) =~ s{::}{/}g;
        require "$path.pm";
        $pkg->process; 
        ...  
    }
    

    Of course, the modifications assume that $_ is in the form of Processors::Foo for example. Even if you can not modify the content of your @data, I think you can generate the name of the processor so that you are able to invoke its process() method.

    If you want to be a show-off, you could create a Factory object that will return instances of your processors based on the value of $_:

    package Processors::Factory;
    
    sub get_instance{
      my ($self, $processor_name) = @_;
    
      my $full_processor_name = sprintf('Processors::%s', ucfirst($processor_name) );
    
      (my $full_processor_path = $full_processor_pkg) =~ s{::}{/}g;
      require "$full_processor_path.pm";
    
      my $processor = $full_processor_name->new();
    
      return $processor;
    }
    
    1;
    

    Then, your code would look like:

    #!/usr/bin/perl -w  
    use strict;
    use Processors::Factory;
    
    foreach (@data) { 
        Processors::Factory->get_instance( $_ )->process();
        ...  
    }