Modules (edited – lorraine)

Beginning Perl, Second Edition

Written by James Lee

Note – fix tables & empty spaces

Published by Apress

Chapter 13



In Chapter 12 we discussed Perl’s object-oriented programming features. In describing Perl’s OO capabilities, we created packages and placed those packages into .pm files, then use d the packages in our programs. These packages are also known as modules.

Very simply, a module is a package within a file—a collection of subroutines (methods) and variables that all work together to perform some set of tasks that we can use to solve our programming problems.

There exists a large collection of prewritten Perl modules—we programmers can use these modules, free of charge, to solve our problems. The modules are available at CPAN, the Comprehensive Perl Archive Network (www.cpan.org and mirrors all over the world). There are modules available at CPAN that are easy-to-use solutions to many different problems—for example, modules to simplify network programming, process XML files, create web programs (CGI and others), connect to SQL databases, and do complex mathematics. This list could go on and on, but we suggest you visit http://search.cpan.org/, which offers both browsing and searching of the CPAN.

In this chapter we will be looking at several of these very useful modules. This discussion is only meant to be a sample of what is available at CPAN; we suggest that you point your browser at CPAN and start installing and using modules—they will almost certainly make your program ming life easier.

We will also show how to create a module. You may be wondering, didn’t we do that in Chapter 12? In that chapter we created OO modules—in this chapter we will create a module that is not OO in nature, but rather is a collection of useful subroutines that can be used within any Perl program that uses the module.

Why Do We Need Them?

Why should you use modules? The simple answer is that it saves time—if you need that program written yesterday, it’s exceptionally handy to be able to download a bunch of modules that you know will do the job, and then simply glue them together.

The second answer is because most of us programmers are lazy—that’s just a fact of life. Programmers are, on the whole, naturally lazy people and don’t like reinventing the wheel. Now, don’t get us wrong—there’s good laziness and there’s bad laziness. Bad laziness says “I should get someone else to do this for me,” whereas good laziness says “Maybe someone’s already done this.” The good kind pays off. Most of the programming you’ll be doing will, at some level, have been done before.

Modules that have been around on CPAN for a while will have been used by thousands of individuals, many of whom will have spent time fixing bugs and returning the results to the maintainer. Most of the borderline cases will have been worked out by now, and you can be pretty confident that the modules will do things right. When it comes to things like parsing HTML or processing CGI form data, we’re perfectly willing to admit that the people who wrote HTML::Parser and the CGI modules have done more work on the subject than we have—so we use their code, instead of trying to work out our own.

In short: don’t reinvent the wheel—use modules.

Package Hierarchies

We’ve already seen how packages can help us break up a namespace: $Fred::name isn’t the same variable as $Barney::name . When modules come into play, packages are used to identify the module. Now our variables have a nice namespace, but our modules have to identify themselves by a single word. With several thousand modules out there, it gets hard to find the one we want. So the librarians at CPAN have come up with a solution: we split up the module package names into hierarchies. Instead of having dozens of modules about sorting, we now have Sort::Fields , Sort::Versions , and so on.


Note  This hierarchy is only a naming scheme. It doesn’t mean that Sort::Fields and Sort::Versions are somehow related to a bigger package called Sort —it’s simply a way of making it easier to categorize modules.


So how do we store these in files? Some operating systems won’t let us have colons inside filenames, so Sort::Versions.pm won’t be legal. However, since these names represent a consistent hierarchy, there’s a natural way we can organize them on the disk: as mentioned in Chapter 12, require and use translate colons into directory separators, so Sort::Versions will actually be stored in a file called Versions.pm in a directory called Sort somewhere off one of the site paths in @INC .

Exporters

Since modules are usually packages stored in a file, a subroutine in the Text::Wrap module, for example, would normally be tucked away in the Text::Wrap package. However, let’s say it would be more convenient for us to have this as a subroutine in the package we’re currently in—usually the main package. To do this, Perl uses a module called Exporter , which provides it with a way of importing subroutines from the module into the caller’s package. Here’s how it works.

When you use a module, as well as reading and executing the code, Perl will try and run a subroutine called import inside the module’s package. If that’s not found, nothing happens, and there’s no error. If it is found, though, it’s called with all the parameters given on the use line. So, for instance:

use Wibble ("wobble", "bounce", "boing");

loads the Wibble module and then runs the following:

Wibble::import("wobble", "bounce", "boing") ;


Note  Theoretically, this import() subroutine could do anything. In fact, a few modules use it to let you pass parameters to set up the module. However, you’ll usually want to use it to import subroutines and
vari ables.


Exporter lets the modules that use it borrow a standard import() subroutine. This subroutine checks a number of variables inside the module as well as the parameters that we give it. If we give an empty list, like this:

use Wibble ();

then nothing will be imported. If there’s a particular subroutine we want to use— wobble() for example—then we could call it as Wibble::wobble() , and we’ll get it imported into our current package. We can only import subroutines that the module is prepared to export, and it’ll detail those in a package variable called @EXPORT_OK . So if, for instance, we wanted to make a Wibble module from which we could import wobble() , bounce() , and boing() , we’d say this:

package Wibble ;

use strict;

use Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(wobble bounce boing);

sub wobble { print "wobblen" }
sub bounce { warn  "bouncen" }
sub boing  { die   "boing!n" }

1;

Recall from Chapter 12 that all files that we use must end with a true value, normally 1; .

If we don’t pass any parameters at all, we get the default subroutines, which are defined in @EXPORT . So if our module looked like this:

package Wibble;

use strict;

use Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(wobble bounce boing);
our @EXPORT  = qw(bounce);

sub wobble { print "wobblen" }
sub bounce { warn  "bouncen" }
sub boing  { die   "boing!n" }
 

1;

and we ran use Wibble; in our main program, we’d be able to call bounce() from the main program, but not wobble() or boing() —we would have to call these as Wibble::wobble() and Wibble::boing() .

We can also define tags with the %EXPORT_TAGS hash. This allows us to group together a bunch of subroutines or variables under a group name. For instance, the CGI module (which we’ll be using in Chapter 14) allows us to say

use CGI qw(:standard);

which will import all its most useful subroutines.

Online Documentation

The perldoc program is a simple way to view the online documentation for a module. Simply provide the module name as its argument:

$ perldoc Data::Dumper

You can also check out www.perldoc.com and www.cpan.org for module documentation.

Creating a Non-OO Module

Creating a module is a good thing. It allows you to reuse useful functions across multiple programs by simply using them. Now we will look at creating a module in a different way than we did in Chapter 12—we will create a module that is not object oriented in nature, but rather a collection of useful functions.

Let’s say we are working on a team that is developing software for the Acme webserver.1 We have been assigned the role of developing an easy-to-use logging interface. It will utilize the idea of log levels, or logging at varying degrees of detail. Level 1 is the least detail, and higher values indicate more details.

We want to make our module easy to use and functional. What we need the module to do is to open and close the log file, write into the log file, and set the log level (which has the default value of 1, or the least level of detail).

First we need to create a name for our logging interface. Since we work for the Acme company and are creating a logging system for a webserver, let’s call the module Acme::Webserver::Logger . Recall that this name means that somewhere under @INC will be a directory named Acme , and under that directory will be a directory named Webserver , and in that directory is the file Logger.pm . To declare its name, we say this at the top of the file:

package Acme::Webserver::Logger;

We want to provide the user a function to open the file. A good name for the function is open_log() , since it is opening the log file, and it might look like this:

sub open_log {
   
my $filename = shift;
   
open(LOGFILE, ‘>>’, $filename) or die "can’t open $filename: $!";
   
print LOGFILE "Log started: ", scalar(localtime), "n";
}

This function grabs the first argument, which is the filename to open. Then, the log file is opened in append mode and a message is printed to the log file stating that the logging has begun. We also need a function to close the log file:

sub close_log {
    close LOGFILE;
}

Next, we need a function to write into the log file:

sub write_log {
   
my($level, $message) = @_;
   
print LOGFILE "$messagen" if $level <= $LEVEL;
}

This function is expecting two arguments: the log message level and the message. The message is then printed if the level of the message is less than or equal to the level that is set for this logger.

Finally, we need a way to set the log level in case we want more (or less) detail. Here it is:

sub log_level {
   
my $level = shift;
   
$LEVEL = $level if $level =~ /^d+$/;
}

The argument is assigned to $LEVEL if the argument is a positive integer.


Note  A note about these functions: we should probably add a lot more error checking to these functions to make them a bit harder to break. For instance, what if write_log() was called with no log level and message? The function would work (printing an empty string to the log file since it would treat the level as 0, less than our minimum level, and the message would be undef ), but it would be polite to instead report to the user that they are using the function incorrectly. Also, any real logging module would lock the file with flock() . But if error checking and file locking were added to this example, it would be way too long and complicated for our purpose here.


Here is the whole module, including the initial value assigned to $LEVEL :

package Acme::Webserver::Logger;
# Acme/Webserver/Logger.pm

# always a good idea to turn these on
# use warnings is needed because there is
# no -w in modules
use strict;
use warnings;

my $LEVEL = 1; # default level is 1

sub open_log {
    my $filename = shift;
    open(LOGFILE, ‘>>’, $filename) or die "can’t open $filename: $!";
    print LOGFILE "Log started: ", scalar(localtime), "n";
}

sub close_log {
    close LOGFILE;
}

sub write_log {
    my($level, $message) = @_;
    print LOGFILE "$messagen" if $level <= $LEVEL;
}

sub log_level {
    my $level = shift;
    $LEVEL = $level if $level =~ /^d+$/;
}

1;

Here is a program that uses the module. Notice how the functions are invoked with the package name preceding the function names.

#!/usr/bin/perl -w
# logtest1.pl

use strict;
use Acme::Webserver::Logger;

Acme::Webserver::Logger::open_log("webserver.log");

# this will go to the log file Acme::Webserver::Logger::write_log(1, "A basic message");

# this won’t – the level is too high Acme::Webserver::Logger::write_log(10, "A debugging message");

# set the level so the debugging message will end up
# in the log file Acme::Webserver::Logger::log_level(10); Acme::Webserver::Logger::write_log(10, "Another debugging message");

Acme::Webserver::Logger::close_log();

When executed, this program creates and adds text to the log file webserver.log .

$ perl logtest1.pl

Here is the content of the log file:

Log started: Fri Jul 2 11:42:12 2004
A basic message
Another debugging message

The syntax for calling the functions in the module is way too long! We can shorten these lines by exporting the function names in the module. We discussed how to do this previously in this chapter—by becoming an Exporter . So let’s modify the module a bit to look like this:

package Acme::Webserver::Logger;
# Acme/Webserver/Logger.pm

# always a good idea to turn these on
# use warnings is needed because there is
# no -w in modules
use strict;
use warnings;

# become an exporter and export the functions
use Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(open_log close_log write_log log_level);

my $LEVEL = 1;  # default level is 1

sub open_log {
    my $filename = shift;
    open(LOGFILE, ‘>>’, $filename) or die "can’t open $filename: $!";
    print LOGFILE "Log started: ", scalar(localtime), "n";
}

sub close_log {
    close LOGFILE;
}
 

sub write_log {
    my($level, $message) = @_;
    print LOGFILE "$messagen" if $level <= $LEVEL;
}

sub log_level {
    my $level = shift;
    $LEVEL = $level if $level =~ /^d+$/;
}

1;

Now we can modify the program that calls these functions to be

#!/usr/bin/perl -w
# logtest2.pl

use strict;
use Acme::Webserver::Logger;

open_log("webserver.log");

# this will go to the log file
write_log(1, "A basic message");

# this won’t – the level is too high
write_log(10, "A debugging message");

# set the level so the debugging message will end up
# in the log file
log_level(10);
write_log(10, "Another debugging message");

close_log();

Ah, much better! Executing this program will add to the log file:

$ perl logtest2.pl

so that its content is

Log started: Fri Jul  2 11:42:12 2004
A basic message
Another debugging message
Log started: Fri Jul  2 11:50:41 2004
A basic message
Another debugging message

The Perl Standard Modules

Not only can we create our own modules, we can also use modules that others have created and made available to us at CPAN (more on using CPAN later in this chapter). When Perl is installed, there are many modules automatically installed. These are called the standard modules. We will look at a few of the more interesting ones here. For a complete list of all the modules in the Perl distribution, execute perldoc perlmodlib at a shell prompt.

Data::Dumper

Data::Dumper stringifies data types in Perl syntax so a programmer can see a visual representation of the data structure. Here is a simple example:

#!/usr/bin/perl – w
# data1.pl

use strict;
use Data::Dumper qw(Dumper); # import the Dumper() function

# create a complex data type

my @a = (
   
‘hello, world’,
    1234.56,
   
[ 2, 4, 6 ],
    { one => ‘first’, two => ‘second’ }
);

# create a reference to it

my $r = @a;

# dump it out
print Dumper($r);

This program first uses Data::Dumper , importing the Dumper() function. It then creates a complex data type: an array that contains a string, a float, an anonymous array, and an anonymous hash. Then, a reference to the array is created. Finally, that reference is dumped out. This code produces

$ perl data1.pl
$VAR1 = [ 
          
‘hello, world’,
           ‘1234.56’,
          
[
            
2,
             4,
            
6
          
],
          
{
            
‘one’ => ‘first’,
             ‘two’ => ‘second’
          
}
        ];

This displays the complex data type so we programmers can read it and understand it. It appears that $VAR1 (a name chosen for us by Data::Dumper ) is a reference to an array that contains a string, a float, an anonymous array, and an anonymous hash. Being able to view this output can assist in debugging our program.2

Data::Dumper chooses the variable name $VAR1 for us. Perhaps we want to name the vari able ourselves. A small change to data1.pl will do the trick:

#!/usr/bin/perl -w
# data2.pl

use strict;
use Data::Dumper;

# create a complex data type

my @a = (
   
‘hello, world’,
   
1234.56,
   
[ 2, 4, 6 ],
    { one => ‘first’, two => ‘second’ }
);

# create a reference to it

my $r = @a;

# dump it out
print Data::Dumper->Dump([$r], [‘myvarname’]);

This code produces the following:

$ perl data2.pl
$myvarname = [
              
‘hello, world’,
               ‘1234.56’,
               [
                 2,
                 4,
                
6
              
],
              
{
                
‘one’ => ‘first’,
                 ‘two’ => ‘second’
              
}
             ];

File::Find

File::Find is a module for traversing directory trees, visiting each file in turn and running a subroutine (the callback) on them. This module has a very useful method: find(). It does a depth-first search, visiting directories only after their files have been processed. This is useful if, for example, you want to delete entire directory trees, since you’re not usually permitted to delete a directory until you’ve deleted all the files in it.

We call the subroutine with two parameters: the callback subroutine reference, and the directory (or a list of directories) from which to start:

find(&wanted, "/home/simon/");

The subroutine wanted() is executed for every file that it finds in the directory. For each of the files, the following is true:

  1. You are moved into the same directory as the file under consideration.
  2. The current directory, relative to the top of the tree, is held in $File::Find::dir
     
  3. $_ contains the name of the current file. 
     
  4. $File::Find::name is the name including the directory.

With that, we can do anything we want to do. Here is a program to delete useless files:

#!/usr/bin/perl -w
# hoover.pl

use strict;
use File::Find;

find(&cleanup, "/");

sub cleanup {
   # Not been accessed in six months?
   if (-A > 180) {
      print "Deleting old file $_n";
      unlink $_ or print "oops, couldn’t delete $_: $!n";
      return;
   }
   open (FH, $_) or die "Couldn’t open $_: $!n";
   foreach (1..5) { # You’ve got five chances.
      my $line = <FH>;
      if ($line =~ /Perl|Camel|important/i) {
         # Spare it.
         return;
      }
   }
   print "Deleting unimportant file $_n";
   unlink $_ or print "oops, couldn’t delete $_: $!n";
}

This code assumes, of course, that any file that contains “Perl,” “Camel,” or “important” in the first five lines is, well, important. You can alter this so it doesn’t look for the words “Perl,” “Camel,” or “important” in the first five lines and indeed so it doesn’t look through and delete files from your entire directory structure.

Getopt::Std

The Getopt::Long and Getopt::Std modules provide a flexible way to use command line argu ments in our programs. Getopt::Std is the simpler of the two, providing us with a way to get single-letter switches with values and support for clustered flags ( -a -l written as -al )—we can also arrange to have the flags placed in a hash. For instance, to provide our wonderful “Hello World” program (from Chapter 1) with help, a version identifier, and internationalization, we could do this:

#!/usr/bin/perl – w
# hello3.pl
# Hello World (Deluxe)

use strict;
use Getopt::Std;

my %options;
getopts("vhl:", %options);

if ($options{v}) {
   print "Hello World, version 3.n";
   exit;
} elsif ($options{h}) {
   print <<EOF;

$0: Typical Hello World program

Syntax: $0 [-h|-v|-l <language>]

   -h : This help message
   -v : Print version on standard output and exit
   -l : Turn on international language support.
EOF
   exit;
} elsif ($options{l}) {
   if ($options{l} eq "french") {
      print "Bonjour, tout le monde.n";
   } else {
      die "$0: unsupported languagen";
   }
} else {
   print "Hello, world.n";
}

getopts() takes the following as its arguments: a specification (the letters for which we provide options) and a hash reference. If we follow a letter with a colon, we expect that a value will be stored in the hash. If we don’t use a colon, then the hash value stored is just true or false depending on whether or not the option was given. We can now get output like this:

$ perl hello3.pl -l french
Bonjour, tout le monde.
$

Getopt::Std also produces a warning if it sees options it’s not prepared for:

$ perl hello3.pl -f
Unknown option: f
Hello, world.
$

Getopt::Long

The Free Software Foundation, when they were developing the GNU project, decided that single-letter flags weren’t friendly enough, so they invented “long” flags. These use a double minus sign followed by a word. To give a value for the option, you’d say
something like –language=french .

The module Getopt::Long handles this style of option. Its documentation is extremely informative ( perldoc Getopt::Long ), but it’s still useful to see an example. Let’s convert the preceding program to GNU options:

#!/usr/bin/perl -w
# hellolong.pl
# Hello World (Deluxe) – with long flags

use strict;

use Getopt::Long;

my %options;
GetOptions(%options, "language:s", "help", "version");

if ($options{version}) {
   print "Hello World, version 3.n";
   exit;
} elsif ($options{help}) {
   print <<EOF;

$0: Typical Hello World program

Syntax: $0 [–help|–version|–language=<language>]

   –help     : This help message
   –version  : Print version on standard output and exit
   –language : Turn on international language support.
EOF
   exit;
} elsif ($options{language}) {
   if ($options{language} eq "french") {
      print "Bonjour, tout le monde.n";
   } else {
      die "$0: unsupported languagen";
   }
} else {
   print "Hello, world.n";
}

We can still use the previous syntax, but now we can also say

$ perl hellolong.pl –language=french Bonjour, tout le monde.
$

File::Spec

If we want to write really portable programs in Perl, we have to be careful when doing things like dealing with filenames. File::Spec is a module for handling, constructing, and breaking apart filenames.

Normally it has an object-oriented interface, but it’s much easier to use the subroutine interface, File::Spec::Functions . Here are some of the subroutines it provides:  

Function and Syntax

Description

canonpath($path)

Cleans up $path to its simplest form

catdir($directory1,

Concatenates the two directories together to form a new path to

$directory2)

a directory, ensuring an appropriate separator in the middle, and

 

removing the separator from the end

catfile($directory,

Like catdir(), but the path will end with a filename

$file)

 

tmpdir()

Finds a writable directory for temporary files (See the File::Temp

 

module before working with temporary files!)

splitpath($path)

Splits up a path into volume (drive on Windows, nothing on Unix),

 

directories, and filename

splitdir($path)

Splits a path into its constituent directories: the opposite of catdir()

path()

Returns the search path for executable files

Here is an example of locating a copy of the sort program:

#!/usr/bin/perl -w
# whereisit.pl

use strict;
use File::Spec::Functions;

foreach my $path (path()) {
    my $test = catfile($path, "sort");
    if (-e $test) {
        print "Yes, sort is in the $_ directory.n";
        exit;
    }
}
print "sort was not found here.n";

Executing this code might produce the following:

$ perl whereisit.pl
Yes, sort is in the /usr/bin directory.
$


Note  To read all the documentation for File::Spec , be sure to check out File::Spec::Unix or File::Spec:Win32 , depending on your operating system.


Benchmark

There’s More Than One Way To Do It—that’s our motto (TMTOWTDI). However, some ways are always going to be faster than others. How can you tell? You could analyze each of the statements for efficiency, or you could simply roll up your sleeves and try it out.

Our next module is for testing and timing code. Benchmark provides two methods: timethis() and timethese() . The first of these, timethis() , is quite easy to use:

#!/usr/bin/perl -w
# benchtest1.pl

use strict;
use Benchmark;

my $howmany = 10000;
my $what    = q/my $j=1; foreach (1..100) {$j *= $_}/;

timethis($howmany, $what);

This program provides timethis() some code and a number of times to run it. Make sure the code is in single quotes so that Perl doesn’t attempt to interpolate it. You should, after a little while, see some output. This will, of course, vary depending on the speed of your CPU and how busy your computer is, but here is an example:

$ perl benchtest1.pl
timethis 10000:  3 wallclock secs ( 2.58 usr +  0.00 sys =  2.58 CPU) @
3871.47/s (n=10000)
$

This tells us we ran something 10,000 times, and it took 3 seconds of real time. These seconds were 2.58 spent in calculating (“usr” time) and 0 seconds interacting with the disk (or other noncalculating time). It also tells us that we ran through 3871.47 iterations of the test code each second.

To test several things and compare them, we can use timethese() . This method takes as its second argument an anonymous hash. The values of the hash are strings (single quoted again) that will be executed $howmany number of times.

To check the fastest way to read a file from the disk, we could do this:

#!/usr/bin/perl -w
# benchtest2.pl

use strict;
use Benchmark;

my $howmany = 100;

timethese($howmany, {
    line => q{
        my $file;
        open TEST, "words" or die $!;
        while (<TEST>) { $file .= $_ }
        close TEST;
    },
   
slurp => q{
        my $file;
        local undef $/;
        open TEST, "words" or die $!;
        $file = <TEST>;
        close TEST;
    },
    join => q{
        my $file;
        open TEST, "words" or die $!;
        $file = join "", <TEST>;
        close TEST;
   
}
});

One way reads the file in a line at a time, one slurps the whole file in at once, and one joins the lines together. As you might expect, the slurp method is considerably faster:

$ perl benchtest2.pl
Benchmark: timing 100 iterations of join, line, slurp…
      join: 42 wallclock secs (35.64 usr + 3.78 sys = 39.43 CPU) @  2.54/s (n=100)
      line: 37 wallclock secs (29.77 usr + 3.17 sys = 32.94 CPU) @  3.04/s (n=100)
     slurp:  6 wallclock secs ( 2.87 usr + 2.65 sys =  5.53 CPU) @ 18.09/s (n=100)
$

Also bear in mind that each benchmark will not only time differently between each machine and the next, but often between times you run the test—so don’t base your life around bench mark tests. If a pretty way to do it is a thousandth of a second slower than an ugly way to do it, choose the pretty one.

Win32

Those familiar with Windows’ labyrinthine Win32 APIs will probably want to examine the libwin32 modules. These all live in the Win32:: hierarchy and come as standard with ActiveState Perl. If you’ve compiled another Perl yourself on Windows, you can get a copy of the modules from CPAN—we’ll see how later in this chapter.

These modules, which give you access to such things as Semaphores, Services, OLE, the Clipboard, and a whole bunch of other things besides, will probably be of most interest to existing Windows programmers. For the rest of us though, there are two modules that will be of particular use:

Win32::Sound

The first, Win32::Sound , lets us play with the sound subsystem—we can play .wav files, set the speaker volume, and so on. We can also use it to play the standard system sounds.

The following program will play all the .wav files in the current directory:

#!/usr/bin/perl – w
# wavplay.pl

use strict;
use Win32::Sound;

Win32::Sound::Volume(65535);
while (<*.WAV>) {
  
Win32::Sound::Play($_);
}

You won’t see any output, but if you’re in a directory containing .wav files, you should certainly be able to hear some!

The Win32::Sound module provides us with a number of subroutines.  

Function

Description

Win32::Sound::Volume($left, $right)

Sets the left and right speaker volumes to the requested

 

amount. If only $left is given, both speakers are set to that volume. If neither is given, the current volume is returned. You can give the volume either as a percentage or a number from 0 to 65535.

Win32::Sound::Play($name)

Plays the named sound file, or the named system

 

sound (for example, SystemStart).

Win32::Sound::Format($filename)

Returns information about the format of the given

 

sound file.

Win32::Sound::Devices()

Lists all the available sound-related devices on the

 

system.

Win32::Sound::DeviceInfo($device)

Provides information on the given sound device.

You can get a full list of the subroutines from the Win32::Sound documentation page if you have the module installed ( perldoc Win32::Sound ).

Win32::TieRegistry

Windows uses a centralized system database to store information about applications, users, and its own state. This is called the registry, and we can get at it by using Perl’s Win32::TieRegistry module. This just provides a convenient layer around the Win32::Registry module, which is rather more technical in nature. Win32::TieRegistry transforms the Windows registry into a Perl hash.

The registry is a complicated beast, and revolves around a hierarchical tree structure—like a hash of hashes or a directory. For instance, information about users’ software is stored under HKEY_CURRENT_USERMicrosoftWindowsCurrentVersion. Now we can get to this partic ular part of the hash by saying the following:

#!/usr/bin/perl – w
# registry.pl

use strict;
use Win32::TieRegistry (Delimiter => "/") ;

We load the module, and change the delimiter from a backslash to a forward slash so we don’t end up drowning in a sea of backslashes.

my $users = $Registry->  
  {HKEY_CURRENT_USER/Software/Microsoft/ Windows/CurrentVersion/};

Now that we’ve got that key, we can dig further into the depths of the registry. This is where the Windows Explorer tips are stored:

my $tips = $users->{Explorer/Tips};

and from there we can add our own tips:

$tips->{/186} = "It’s easy to use Perl as a Registry editor with the " .
                "Win32::TieRegistry module.";

We can always delete them again, using ordinary hash techniques.

delete $tips->{/186};

Again, if you’re after more information, it’s available in the Win32::TieRegistry documentation.

CPAN

So far we’ve been looking at standard modules provided with most Perl distributions. However, as we mentioned in the introduction, there’s also a central repository for Perl modules—collections of code that will do virtually any kind of job: the Comprehensive Perl Archive Network, or CPAN, which you can find on the web at www.cpan.org. You can also find the standard Perl modules on CPAN and can read their documentation in web browser–friendly HTML by surfing http://search.cpan.org/.

So before you ask “How do I do . . . ?” or start plugging away at any long task, it’s always worth taking a quick look here to see if it’s already been done. CPAN is searchable in plenty of different ways—the most common are by keyword, by topic, or by module name. There are also a few CPAN search engines, but the easiest for browsing is probably the web-based CPAN search engine at http://search.cpan.org/.

This lets us look up modules by category, as well as searching for words in the modules’ documentation. Once we’ve found a module that might do what we want, we follow a link to get further information on it and get ourselves a download. For example, this is what we get for the Archive::Tar module:

Now that we’ve seen how to find the modules we want, we’re ready to look at the various ways in which we can install them.

Installing Modules with PPM

If you’re using ActivePerl, module installation is made very simple by the Perl Package Manager (PPM). This is a useful little tool that’s provided along with installations of ActivePerl, which allows us to install modules from the command line with the minimum of effort.


Note  It is important to mention that PPM is not an interface to CPAN; it is a convenient program that allows us to install copies from CPAN, many of which are in some stage of being out-of-date. There is no guarantee that what is available on CPAN will be available with PPM. The rule of thumb is for the latest and greatest, visit CPAN.


So without further ado, let’s install Net::Telnet —a module that allows us to automate a telnet session.

  1. Type ppm at the command line; this will give you the PPM prompt: PPM> .
  2. Now type install Net::Telnet—you may be asked to confirm your request, if so type y
     
  3. Exit the PPM prompt by typing quit, and now you have Net::Telnet installed.

Installing a Module Manually

We’ll now take a look at what’s involved in installing a module using CPAN. If you search CPAN for the module Net::Telnet , you should find yourself looking at the file libnet-1.18.tar.gz (unless there’s a newer version out by the time you read this . . . ) Download and unpack this file. On Unix systems, gzip -dc libnet-1.18.tar.gz | tar -xvf (or tar xzvf libnet-1.18.tar.gz if your version of tar also unzips) should do the trick, while you can use WinZip to extract these files on Windows.

Every module should contain a Makefile.PL , which can be used to generate the instructions to install the module. Let’s run that file first:

$ perl Makefile.PL

If you can’t install in Perl’s site directories because you don’t have the appropriate permissions, run

perl Makefile.PL PREFIX=/my/module/path

Makefile.PL first checks that we have all the modules it requires, and then that we’ve got everything we should have in the module archive itself—a file called MANIFEST contains a list of what should be in the archive.

Now we’re ready to type make —assuming, of course, we have make on our system:

$ make

Once that’s done, we check to see if our module’s working:

$ make test

Finally, we actually install it, moving the files to the correct location:

$ make install

Hooray! The module’s now installed.

However, there’s a much, much easier way of doing it.

The CPAN Module

Another easy way to navigate and install modules from CPAN is to use the standard module called CPAN . The “CPAN Shell” is an extremely powerful tool for finding, downloading, building, and installing modules.

To get into the CPAN shell, type

$ perl -MCPAN -e shell

This is actually just the same as saying

#!/usr/bin/perl
use CPAN;
shell();

The whole shell is actually a function in the (massively complex) CPAN module. The first time we run it, we’ll see something like this:

/usr/local/lib/perl5/5.8.3/CPAN/Config.pm initialized.

CPAN is the world-wide archive of perl resources. It consists of about
100 sites that all replicate the same contents all around the globe.
Many countries have at least one CPAN site already. The resources
found on CPAN are easily accessible with the CPAN.pm module. If you
want to use CPAN.pm, you have to configure it properly.

If you do not want to enter a dialog now, you can answer ‘no’ to this
question and I’ll try to autoconfigure. (Note: you can revisit this
dialog anytime later by typing ‘o conf init’ at the cpan prompt.)

Are you ready for manual configuration? [yes]

Press the Enter key, and you’ll be asked a series of questions about your computer and the nearest CPAN server—if you don’t know, just keep hitting Enter through the answers. Eventually, you’ll end up at a prompt like this:

cpan shell — CPAN exploration and modules installation (v1.7601)
ReadLine support available (try "install Bundle::CPAN")

cpan>

Now we’re ready to issue commands. The install command, as shown in the prompt, will download and install a module. For example, we could install the DBD::mysql module by simply saying

cpan>install DBD::mysql

Alternatively, we could get information on a module with the i command. Let’s get some information on the MLDBM module:

cpan>i MLDBM
Module id = MLDBM
    DESCRIPTION  Transparently store multi-level data in DBM
   
CPAN_USERID  GSAR (Gurusamy Sarathy gsar@ActiveState.com)
    CPAN_VERSION 2.01
   
CPAN_FILE    C/CH/CHAMAS/MLDBM-2.01.tar.gz
    DSLI_STATUS  RdpO (released,developer,perl,object-oriented)
    INST_FILE    (not installed)

This tells us the module is called MLDBM, and there’s a description of it. It was written by the CPAN author GSAR, which translates to Gurusamy Sarathy in the real world. It’s at version 2.01, and it’s stored on CPAN in the directory C/CH/CHAMAS/MLDBM-2.01.tar.gz .

The funny little code thing is the CPAN classification. It tells us this module has been released (the implication being that it’s been released for a while), that you should contact the developer if you need any support on it, that it’s written purely in Perl without any extensions in C, and that it’s object oriented—and finally, that we don’t have it installed. So let’s install it:

cpan> install MLDBM


Note  In fact, you don’t even have to go into the shell to install a module. As well as exporting the shell subroutine, CPAN provides us with install , with which we can simply say perl -MCPAN -e ‘install "MLDBM"’ to produce the same results.


You’ll then see a few lines that will be specific to your computer—different systems have different ways of downloading files, and depend on whether or not you have the external programs lynx , ftp , or ncftp , or the Perl Net::FTP module installed.

The CPAN module will download the file, and then, if you’ve got the Digest::MD5 module installed, download a special file called a checksum—it’s like a summary of that file so we make sure that what we’ve downloaded is what’s on the server.

Checksum for /home/simon/.cpan/sources/authors/id/ C/CH/CHAMAS/MLDBM-2.01.tar.gz ok

You should then see tons of output: the tar file is unpacked, a Makefile is generated and executed, the module is tested, and then installed. Once all this takes place, you will see the CPAN prompt again:

cpan>

Successfully installed, and with the minimum of effort!

How about if we don’t actually know the name of the module we’re looking for? CPAN lets us use a regular expression match to locate modules. For instance, if we’re about to do some work involving MIDI electronic music files, we could search for “MIDI.” Here is a portion of what we might see:

cpan>i /MIDI/

Author

MIDI ("Michael Diekmann" <michael.diekmann@undef.de>)

Distribution

B/BM/BMAMES/MIDI-XML-0.02.tar.gz

Distribution

C/CH/CHURCH/MIDI-Trans-0.15.zip

Module

MIDI

(S/SB/SBURKE/MIDI-Perl-0.8.tar.gz)

 

continued 

Module

MIDI::Event

(S/SB/SBURKE/MIDI-Perl-0.8.tar.gz)

Module

MIDI::Music

(S/SE/SETHJ/MIDI-Music-0.01.tar.gz)

Module

MIDI::Opus

(S/SB/SBURKE/MIDI-Perl-0.8.tar.gz)

Module

MIDI::Realtime

(F/FO/FOOCHRE/MIDI-Realtime-0.01.tar.gz)

Module

MIDI::Score

(S/SB/SBURKE/MIDI-Perl-0.8.tar.gz)

Module

MIDI::Simple

(S/SB/SBURKE/MIDI-Perl-0.8.tar.gz)

Module

MIDI::Tab

(R/RS/RSYMES/MIDI-Tab-0.01.tar.gz)

Module

MIDI::Tools

(C/CR/CRENZ/MIDI-Tools-0.01.tar.gz)

Module

MIDI::Track

(S/SB/SBURKE/MIDI-Perl-0.8.tar.gz)

Module

MIDI::Trans

(C/CH/CHURCH/MIDI-Trans-0.15.zip)

“Distributions” are archive files: zips or tar.gz files containing one or more Perl modules. We see that MIDI-Realtime contains just the MIDI::Realtime module.

Bundles

Some modules depend on other modules being installed. For instance, the Win32::TieRegistry module needs Win32::Registry to do the hard work of getting at the registry. If you’re downloading packages from CPAN manually, you’ll have to try each package, find out what’s missing, and download another repeatedly until you’ve got everything you need. The CPAN module does a lot of this work for you—it can detect dependencies in packages and download and install everything that’s missing.

This is fine for making sure that things work, but as well as needing other modules, some merely suggest other modules. For instance, the CPAN module itself works fine with nothing other than what’s in the core, but if you have Term::Readline installed, it gives you a much more flexible prompt, with tab completion, a command history (meaning you can use the up and down arrows to scroll through previous commands), and other niceties.

Enter bundles—collections of packages that go well together. The CPAN bundle, Bundle::CPAN , for instance, contains various modules that make the CPAN shell easier to use: Term::ReadLine as mentioned previously, Digest::MD5 for security checking the files downloaded, some Net:: modules to make network communication with the CPAN servers nicer, and so on.

We’ll now look here at two particularly useful bundles, which contain modules that we personally wouldn’t go anywhere without.

Bundle::LWP

Bundle::LWP contains modules for everything to do with the Web. It has modules for dealing with HTML, HTTP, MIME types, handling URLs, downloading and mirroring remote web sites, creating web spiders and robots, and so on.

The main chunk of the bundle is the LWP ( libwww-perl ) distribution, containing the modules for visiting remote web sites. Let’s have a look at what it gives us.

This module will export five methods to our current package.

  1. The get() method fetches a web site and returns the underlying HTML. This subroutine knows all about proxies, error codes, and other things:

    $file = get("http://www.perl.com/");

  2. The head() method fetches the header of the site and returns a few headers: what type of document the page is (such as text/html ), how big it is in bytes, when it was last modified, when it should be regarded as old (these are both Unix times suitable for feeding to localtime() ), and what the server has to say about itself. Some servers may not return all these headers.

    ($content_type, $document_length, $modified_time, $expires, $server) =
      head("http://www.perl.com/");

The next three methods are all quite similar in that they all involve retrieving an HTML page.

  • The first, getprint() , retrieves the HTML file and then prints it out to standard output—useful if you’re redirecting to a file or using a filter as some sort of HTML formatter. You can copy a web page to a local file like this:

    getprint(http://www.perl.com/); 
  • Alternatively, you can use the getstore() subroutine to store it to a file.

    perl -MLWP::Simple – e
       ‘getstore
    ("http://www.perl.com/", "perlpage.html")’
     
  •   Finally, mirror() is like getstore() , except it checks to see if the remote site’s page is newer than the one we’ve already got.

    perl -MLWP::Simple – e
       ‘mirror("http://www.perl.com/","perlpage.html")’

Be sure to read the main LWP documentation and the lwpcook page, which contains a few ideas for things to do with LWP .

Bundle::libnet

Similarly, Bundle::libnet contains a bunch of stuff for dealing with the network, although it’s not nearly as big as LWP. The modules in Bundle::libnet and its dependencies allow you to use FTP, telnet, SMTP mail, and other network protocols.

Submitting Your Own Module to CPAN

CPAN contains almost everything you’ll ever need. Almost. There’ll surely come a day when you’re faced with a problem where no known module can help you. If you think it’s a sufficiently general problem that other people are going to come across, why not consider making your solution into a module and submitting it to CPAN? Think of it as a way of giving something back to the community that gave you all this . . .

Seriously, if you do have something you think would be useful to others, there are a few things you need to do to get it to CPAN:

  • Check to make sure it has not already been written. Search CPAN a t http://search.cpan.org/. 
     
  • Read the perlmod and perlmodlib documentation pages until you really understand them. 
     
  • Learn about the Carp module, and use carp() and croak() instead of warn() and die()
     
  • Learn about the Test module and how to produce test suites for modules. 
     
  • Learn about documenting your modules in POD, Plain Old Documentation. 
     
  • Look at the source to a few simple modules like Text::Wrap and Text::Tabs to get a feel of how modules are written. 
     
  • Take a deep breath, and issue the following command:  

    $ h2xs -AXn Your::Module::Name
  1. Edit the files produced, remembering to create a test suite and provide really good documentation. 
     
  2. Run perl Makefile.PL and then make .

Edit the files produced, remembering to create a test suite and provide really good documentation.

Your module’s now ready to ship!

For more information, check out the excellent book Writing Perl Modules for CPAN by Sam Tregar (Apress, 2002). Also, be sure to read perldoc perlnewmod , written by one of your humble authors.

Summary

Modules save you time. In essence, a module is just a package stored in a file, which we load with the use statement.

Perl provides a number of standard modules. You can get documentation on each and every one by running perldoc . We looked briefly at Data::Dumper (to print out data structures), File::Find (for examining files in directory trees), the Getopt modules (for reading options from the command line), the File::Spec::Functions module (for portable filename handling), the Benchmark module (for timing and testing code), and the Win32 modules (for access to the Windows system and registry).

CPAN is the Comprehensive Perl Archive Network. It’s a repository of free Perl code. You can search it from http://search.cpan.org/, or use the Perl module CPAN for easy searching and installation. The CPAN module has the advantage of knowing about file dependencies and can therefore download and install files in the correct order.

Bundles provide sets of related modules. We looked at LWP::Simple (from the libwww bundle) and the libnet bundle. Finally, we looked at some of what’s involved in abstracting your code and putting it into a module.

 


 

1. This is probably not a good idea, since there is already a really good webserver available for free–
www.apache.org.

2. This output can also be stored for later use. If we store this output into a scalar variable, we can eval() that variable, which will reconstruct the data structure (for information on eval(), check out perldoc -f eval).

[gp-comments width="770" linklove="off" ]

chat sex hikayeleri Ensest hikaye