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

Hello gurus,

I am new to the site! It looks like a great source of information!

I am moving our linear Perl test environment to a more OO structured environment and am having a few problems. First off, there is a Perl/Tk window that "calls" our individual tests (testname.pex) in which each of these tests has a main() subroutine.

I am trying to create objects of the individual tests, however I am trying to share several subroutines in both my Object Methods and other locations external to the object.

Example code, outside the object:

use UARTchan; require 'TdWrapper.pl'; Test_Run( 'Full UART Bit Test - $Change: 2944 $' ); sub main { my( $why ); # establish the testing context and assert needed connections unless( initialize( ) ) { $why = IpdrTest_LastFailure( ); IpdrTest_EndLog( ); # assumes the logging got started return 'Failed to initialize: ' . $why; } print "UART Full Test \n"; IpdrTest_Identify( 'UART Full Test ' ); if( IpdrTest_Failure( ) ) { $why = IpdrTest_LastFailure( ); IpdrTest_EndLog( ); return 'Failed to identify: ' . $why; } # conduct the many test steps print "Test begun\n" ; IpdrTest_PrintLog( "Test begin\n\n" ); fillupUART(); print "Test done\n"; # conclusion of test. really only a wrapup of logging. IpdrTest_EndLog( ); if( IpdrTest_Failure( ) ) { return IpdrTest_LastFailure( ); } return 'Ok'; } ... ... ... sub fillupUART{ # Generate global data variable our( $data ); # Generate the UART Channel Object our( $testChan ) = new UARTchan(); # Prompt User for the STE Uart channel, loop until 'Exit' selected TOPLOOP: while(1){ printMenu(); # Print the menu } $testChan->DESTROY; UARTchan->END; # Destroy ALL Objects of the UARTchan + class } ... ... ...
The subroutines Test_Run(), IpdrTest_Failure(), and IpdrTest_LastFailure() (to name a few) are contained IN TdWrapper.pl.

Now to see some of the class/object code:

package UARTchan; require 'TdWrapper.pl'; ########################################### #### Class Data #### ########################################### my $UARTobjs = 0; my $stepNumber = 0; # Used during testing, all objects linke +d my $subStepNum = 0; ########################################### #### Object Constructor #### ########################################### sub new { my $proto = shift; my $class = ref($proto) || $proto; my $this = {}; # Data Members $this->{IPDRUART} = undef; $this->{IPDRDATA} = undef; # The IPDR UART Data buffer, re +ad and written to $this->{IPDRCONF} = undef; # Data member is used in both t +he config and block commands $this->{STEUART} = undef; $this->{STEBAUD} = undef; $this->{STEDATA} = undef; # The STE UART Data buffer, rea +d and written to $this->{COMPBIT} = undef; # Tells the calculation method +which way to compare the data members # Class Data $this->{"_UARTobjs"} = \$UARTobjs; # Storing a reference to this g +lobal in "_UARTobjs" bless($this, $class); ++ ${ $this->{ "_UARTobjs" } }; # Increment the reference printf( "Info> There are currently $UARTobjs UART Objects.\n" ); return($this); } ... ... ... sub steuartopen { my $this = shift; # Increase global count ++$stepNumber; $subStepNum = 0; # Reset Substep count to 0 IpdrTest_StepBegin( "$stepNumber.$subStepNum" ); printf( "Info> Configuring the IP521 UART.\n" ); IpdrTest_PrintLog( "Info> Configuring the IP521 UART.\n" ); # Set the STE IP521 UART as Open STE_Config_UART( $this->{STEUART}, 'Open' ); if( IpdrTest_Failure( ) ) { IpdrTest_Failed( IpdrTest_LastFailure( ) ); printf( "Warning> $stepNumber.$subStepNum failed : Unable to 'Op +en' device.\n" ); IpdrTest_PrintLog( "Warning> $stepNumber.$subStepNum failed : Un +able to 'Open' device.\n" ); IpdrTest_StepFailed(); die "Step $stepNumber.$subStepNum failed"; } # Set the STE IP521 UART BAUD rate STE_Config_UART( $this->{STEUART}, $this->{STEBAUD} ); if( IpdrTest_Failure( ) ) { IpdrTest_Failed( IpdrTest_LastFailure( ) ); printf( "Warning> $stepNumber.$subStepNum failed : Unable to set + device baud rate.\n" ); IpdrTest_PrintLog( "Warning> $stepNumber.$subStepNum failed : Un +able to set device baud rate.\n" ); IpdrTest_StepFailed(); IpdrTest_StepEnd(); die "Step $stepNumber.$subStepNum failed"; } printf( "Step $stepNumber.$subStepNum passed\n" ); IpdrTest_PrintLog( "Step $stepNumber.$subStepNum passed\n" ); IpdrTest_StepPassed(); IpdrTest_StepEnd(); }

Note that the object ALSO needs to reference several of the external subroutines in TdWrapper.pl. However, depending on WHERE I place the require 'TdWrapper.pl';line in my class/object file (.pm), the Perl Interpreter (as far as I can tell) will "lock" those subroutines into different namespace, thus making those subroutines either accessible inside the object OR everywhere else, but not both.

Is there a workaround where I can use these subroutines in BOTH the object/class and everywhere else?

Thanks!

Replies are listed 'Best First'.
Re: Using External Subroutines in a Perl Object file (Package Module)
by jethro (Monsignor) on Aug 25, 2010 at 19:58 UTC

    Without having read much of your code, the line 'require xxx.pl' already tells me that you are doing it the really old-fashioned way (lets call it the perl4 approach). To add utility subroutines there are a few more modern ways:

    1. The perl5 approach
    Using a module called Exporter you create a module that you load with a 'use mymodule(a,b,c);' statement. Subsequently the subroutines a b and c will be part of your name space (and also any subroutines that are included by default). Just do 'perldoc Exporter', it is a core module since the beginning of perl5

    2. The perl5 object oriented approach
    You've got objects already. Nothing simpler than to make them inherit subroutines from a common ancestor. Create a class and change the subroutines to methods in that class, then add 'use base myutilityclass;' and adapt your new subroutine and the subroutines are methods of your class. Check out 'perldoc perlobj' and 'perldoc base'. If you have a recent perl version, use 'parent' instead of 'base'

    3. The Perl6 approach
    Don't fear, you don't need perl6 for this. There is a module called moose that offers a modern interface to objects similar to the object system built into Perl6 and somewhat similar to other languages like Java. Moose has Roles. Roles are (basically) additional methods, variables and/or requirements you can simply add to objects like lego blocks to your lego house. 'perldoc moose' gets you filled in on the details (after you installed it from CPAN). Or read about it on the internet or on perlmonks.

      You rock, let me restructure and test it out. This code base is about 3 years old, so not surprised that you are saying it looks old :)