16 Part 15 Using Modules and OOP

LinuxChix Perl Course Part 15: Using Modules and OOP

1) Introduction
2) A Simple Module
3) Using Objects
4) Where to go from here
5) Exercises
6) Answers to Previous Exercises
7) Acknowledgements
8) Licensing


----------------------------------------

1) Introduction

Even though it seems quite long, this course just scratches the
surface of Perl. Perl really does have a whole universe of
functionalities and tricks, and this course is already drawing to a
close.

But before we end things, we're going to see how to use Perl modules,
which (as it turns out) is closely related to object-oriented
programming in Perl. We're not going to see how to WRITE a module or
class; just how to USE one, because we're not yet at a level where it
would be useful to write a module. (But see the further reading
section if you want to write your own.)

----------------------------------------

2) A Simple Module

Here's an example of a Perl program that uses a module:

#!/usr/bin/perl -w
use strict;
use HTML::Entities;

my $line = <STDIN>; # Read line of text.
print encode_entities($line);

As you might have noticed, we start by declaring that we use the
"HTML::Entities" module. This handy module encodes and decodes HTML
entities (e.g., replacing "<" with "&lt;". After we declare that we
use the module, we can call the functions that it contains, in this
case "encode_entities".

By the way, we could also have written the function call like this:

HTML::Entities::encode_entities($line)

As you might have noticed, the double-colon separates namespaces in
Perl (just as it does in C++).

All Perl modules include documentation, so you can read more about
"HTML::Entities" like this:

perldoc HTML::Entities

----------------------------------------

3) Using Objects

Now that we've seen basic module use, we're going to look at a module
that contains a class.

#!/usr/bin/perl -w
use strict;
use LWP::UserAgent;

my $browser = LWP::UserAgent->new();

my $response = $browser->get('http://www.w3.org/');

if ($response->is_success) {
print $response->content;
}
else {
die $response->status_line;
}

This program retrieves the W3C's home page. Let's go through it
line-by-line.

The first thing we do is declare that we're going to use the
"LWP::UserAgent" module. This module contains a user-agent (often
called a web browser) which retrieves web pages.

Next we create a new object with "LWP::UserAgent->new()". A few
things to note here:
a) The class name is "LWP::UserAgent", just like the package name.
This is a byproduct of the way OOP is built into Perl.
b) The object is created with "new". This is NOT a requirement (the
constructor could be called anything), but it is common.
c) The object is in fact a reference. This means that if you write
"$object1=$object2", both variables will refer to the same object.

When we call "$browser->get()", the user-agent contacts the web
server and returns its response. The response is actually a
"HTTP::Response", but notice that we don't have to import that module
or even use its name.

Finally, we check whether the request was successful and output the
result. Note that "$response->is_success", "$response->content" and
"$response->status_line" are method (function) calls just like
"$browser->get", even though there are no parentheses.

----------------------------------------

4) Where to go from here

Whatever you want to do, there's probably a Perl module that does a
good portion of it. Search the Comprehensive Perl Archive Network
(CPAN: http://www.cpan.org/ ).

Many of the modules on CPAN are actually already installed on your
system, so check before going to the trouble of installing a module.
The easiest way to see if a module is installed is to try to "use"
it, or try to read its documentation (as explained next).

To read the documentation of an (installed) module, use "perldoc":

perldoc LWP::UserAgent

(You can also use "man"; both work. There Is More Than One Way To Do
It!)

To see all the modules installed on your system, you might want to
see the fourth item under:

perldoc perlfaq3

However, that doesn't work for me :-/ so I do this:

locate '*.pm'

One last thing: while you could download and install modules from
CPAN, the most popular Perl modules are probably available via your
Linux distro's package management system (such as "rpm" or "apt"). Do
a quick search there first.

----------------------------------------

5) Exercises

a) Consider this program:

use strict;
use LWP::UserAgent;

my $ua = LWP::UserAgent->new();
print ref($ua) . "\n";

What does "ref" return when passed an object?

b) Consider this code:

#!/usr/bin/perl -w
use strict;
use English;

$INPUT_RECORD_SEPARATOR = ':';
print $/;

What does "use English" accomplish?

For more information, you can consult:

perldoc perlvar

----------------------------------------

6) Answers to Previous Exercises

a) This Perl program stores the password file in a list of lists:

#!/usr/bin/perl -w
use strict;

my @list;

open PASSWD, "< /etc/passwd" or die "Couldn't open file.";
while ( <PASSWD> ) {
push @list, [ split /:/ ];
}
close PASSWD;

Here is one way to search such a list:

print "Enter a username and I'll give you a UID.\n";

while ( defined( my $username = <STDIN> ) ) {
chomp($username);
my @matches = grep { $_->[0] eq $username } @list;
if ( @matches ) {
print "User $username has UID $matches[0][2]\n";
}
else {
print "Sorry: I don't know that user.\n";
}
}

b) Here's a way of storing the password file as an array of hashes:

#!/usr/bin/perl -w
use strict;

my @list;

open PASSWD, "< /etc/passwd" or die "Couldn't open file.";
while ( <PASSWD> ) {
my @fields = split /:/;
push @list, { username=>$fields[0], password=>$fields[1],
uid=>$fields[2], gid=>$fields[3],
name=>$fields[4], home=>$fields[5],
shell=>$fields[6] };
}
close PASSWD;

It can be searched like this:

print "Enter a username and I'll give you a UID.\n";

while ( defined( my $username = <STDIN> ) ) {
chomp($username);
my @matches = grep { $_->{username} eq $username } @list;
if ( @matches ) {
print "User $username has UID $matches[0]{uid}\n";
}
else {
print "Sorry: I don't know that user.\n";
}
}

c) The "ref" function allows you to determine whether a scalar is a
reference, and even the data type to which it refers.

d) Perl 4 included a mechanism called "symbolic" references, which
allowed one variable to access another using its name. This method is
not recommended because it can make your life even more miserable
than normal pointers can.

e) The "\&" operator creates a reference to a function.

f) Larry Wall provides us with some very interesting syntax:

sub try (&@) {
my($try,$catch) = @_;
eval { &$try };
if ($@) {
local $_ = $@;
&$catch;
}
}
sub catch (&) { $_[0] }

try {
die "phooey";
} catch {
/phooey/ and print "unphooey\n";
};

Briefly, this example takes advantage of Perl's "$@" variable, which
stores the latest "exception" (a "die" inside an "eval").

----------------------------------------

7) Acknowledgements

A big thank you to Jacinta Richardson for suggestions and
proofreading. More advanced Perl users might want to check out the
free material from Perl Training Australia
<http://www.perltraining.com.au/>, which she is a part of.

Other contributors include Meryll Larkin.

----------------------------------------

8) Licensing

This course (i.e., all parts of it) is copyright 2003-2005 by Dan
Richter and Alice Wood, and is released under the same license as
Perl itself (Artistic License or GPL, your choice). This is the
license of choice to make it easy for other people to integrate your
Perl code/documentation into their own projects. It is not generally
used in projects unrelated to Perl.