Search code examples
perloopperl-module

Using modules with Perl


I am trying to make a library of functions for my oscilloscope, but I can't seem to get other module files to play nice.

What I have is here, except the Oscope.pm file. If it's needed I can upload it too.

test.pl

# Includes
use 5.012;
use Oscope;
use Oscope::Acquire;
use warnings;

# From Oscope.pm
my $scope = Oscope->new('port', 'COM3');

# From Oscope::Acquire.pm
$scope->QueryAcquire();

Oscope/Acquire.pm

package Oscope::Acquire;

use Oscope;
use parent 'Oscope';

sub QueryAcquire
{
   my ($self) = @_;
   # Oscope.pm
   my $message = $self->Send('ACQUIRE?');
   return();
}

1;

Output

Can't locate object method "QueryAcquire" via package "Oscope" at C:\Documents and Settings\ericfoss\My Documents\Slick\Perl\tests\Test.pl line 11.


Solution

  • I'm not going to say this is a good idea. You apparently want Oscope::Aquire to monkey patch Oscope. That is possible, but I would recommend having Oscope::Acquire export a function that takes an Oscope parameter (more information on exporting):

    Oscope/Acquire.pm

    package Oscope::Acquire;
    require Exporter 'import';
    @EXPORT_OK = qw{QueryAcquire};
    
    use Oscope;
    
    sub QueryAcquire
    {
        my ($oscope) = @_;
        my $message = $oscope->Send('ACQUIRE?');
        return $message;
    }
    
    1;
    

    Which you would use:

    use Oscope;
    use Oscope::Acquire 'QueryAcquire';
    
    my $oscope = Oscope->new();
    print QueryAquire($oscope);
    

    However, if you really want the $oscope->QueryAcquire() syntax, and you don't want to put it in Oscope itself, you can monkey patch the module. Perl documentation refers to this as modifying the module's symbol table through a typeglob and it's apparently deprecated ("The results of creating new symbol table entries directly ... are undefined and subject to change between releases of perl"):

    Oscope/Acquire.pm

    package Oscope::Acquire;
    
    use Oscope;
    
    *Oscope::QueryAcquire = sub {
        my ($self) = @_;
        my $message = $self->Send('ACQUIRE?');
        return $message;
    }
    
    1;
    

    I should have read my own link more closely. It appears that the approved way of doing this is to simply add methods to the Oscope package inside the Oscope/Acquire.pm file ("You can define a subroutine outside its package by explicitly qualifying the name of the subroutine"):

    package Oscope::Acquire;
    use Oscope;
    
    ...
    
    sub Oscope::QueryAcquire {
        my ($self) = @_;
        my $message = $self->Send('ACQUIRE?');
        return $message;
    }
    
    1;
    

    That is, there's no need to the typeglob.