Perl - Modules

From LXF Wiki

Perl tutorial part 4

(Original version written by Marco Fioretti for Linux Format magazine issue 72.)


Perl functions and modules: what they are and how to use them.


Alas, we have come to the end of this Perl series. We'll make good use of this last part, however, by looking at how some of the most powerful features of Perl work. We'll start with functions and then introduce modules, with a final example showing how to use the latter to access a database.

Like in any good programming language, reusable chunks of code can be embedded in functions, which in Perl are called subroutines. This is their basic syntax:

sub print_array
{
my $COUNTER = 0; # auxiliary counter
foreach $ITEM (@_) {
	$COUNTER++;
	print "# $COUNTER: $ITEM\n";
	}
$COUNTER;
}
# Let's use it:
@FRIENDS = ('John', 'Jill', 'Kelly', 'Martin');

$NUMBER = &print_array(@FRIENDS);
print "These are my $NUMBER friends\n";

OK, let's look at the easiest parts first. As you can see, subroutines are defined by enclosing their code, however complex, in curly braces, and preceding it with the “sub” Perl keyword and the subroutine name. When you call them, instead, the & character must be prepended to the name: arguments are passed, inside parentheses, right after that same name.

The two most exotheric bits are that arcane symbol @_ and the fact that I “assigned” the subroutine to $NUMBER. @_ is nothing bad, just the special array into which Perl places all the arguments passed to the subroutine from the main program.

The assignment to $NUMBER relies on the fact that all Perl subroutines return the result of their last instruction. What? $COUNTER is just a variable and not an instruction? Yes, but that's perfectly fine with Perl.

Subroutines can be combined with one of the most powerful Perl structures, that is hashes, in a really cool, although a bit voodoo, way. For all practical purposes, you can use Perl subroutines as hash values, that is you can refer to them by keys. Check this out:

%FUNZ = (
	'L', {'D', 'LIST',	'F', \&MONTHLY_LIST}, # List all calls in this month.
	'P', {'D', 'PLOT_2D',	'F', \&GEN_PLOT },	# Generate a plot of all the calls
	'B', {'D', 'BACKUP',	'F', \&BACKUP_ALL }	# Complete backup
	# many other similar elements, omitted here for brevity
    );
#Let's display all choices to the user
foreach (sort keys %FUNZ) {
    printf "%2.2s  %-20.20s", $_, $FUNZ{$_}{'D'}, "\n";
  }

#...and launch the function he requested
if ($USER_INPUT eq 'B') { # Backup everything
my $rsub = $FUNZ{'B'}{'F'};
&$rsub(('All', 'the', 'arguments', 'for', 'this', 'subroutine'));

Yes, it looks weird but it isn't. This comes from an actual script of mine, which asks to the user which tasks should be performed. %FUNZ is an hash with single letter keys (L, P, B...) and values which are other, unnamed, hashes (being lists inside curly braces). Each of these hashes has two keys, D (Description) and F (Function). The value associated to D is a normal string. The one linked to F is (as far as we are concerned) a pointer to a subroutine: this is what the \& notation means. In other words, $FUNZ{'B'}{'F'} is a pointer to the subroutine BACKUP_ALL. When the script is run on the command line, it prints something like this to the terminal:

L	LIST
P	PLOT_2D
B	BACKUP

The letter that the user types in response is loaded in $USER_INPUT. Whenever 'B' is typed, the last snippet of code loads in $rsub the pointer to BACKUP_ALL, and the last line launches it, with any arguments it might need. &$rsub stands (again, as far as we are concerned), for “execute the code at the address contained in $rsub”. Cool, huh?

The online mother of all modules

Do you need Perl modules for your script? Do you wonder if somebody else on the planet already wrote Perl code to process that arcane data format? Stop worrying and go to THE central online repository for these and many other Perl things. The Comprehensive Perl Archive Network (www.cpan.org) already contains almost 8000 modules covering every conceivable area of computing. Of course, they'll also be happy to add your own modules to the database.