|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159
|
|
Chapter 11:
|
|
|
|
Extensibility And Re-use
|
|
This freedom we shall observe ourselves,
and desire to be observed in good faith
by our heirs in perpetuity.
|
|
- Magna Carta, 1215 A.D.
|
|
Perl's extensibility and ability to reuse code are among its most important
features. A Perl programmer can ease maintenance by separating auxiliary
code from the main program and/or reusing code from other programmers. If
the task requires it (and few do!), a Perl programmer can change or expand
the code of MacPerl itself.
|
|
Packages, Modules, Extensions (Oh My!)
|
|
Packageswere discussed briefly in the introductory chapters and are cov-
ered more fully below. For now, just think of a package as a grouping of
related code and data: code blocks, subroutines, variables, etc.
|
|
A moduleis a file that contains the Perl code for a package. For consistency
and simplicity, the names of modules are based on the names of the corres-
ponding packages. For instance, the module file CGI.pmcontains the CGI
package.1This allows a package's code to be stored and loaded as a unit.
|
|
Modules are the primary method of importing external code into programs.
The Internet-based CPAN(Comprehensive Perl Archive Network) contains
a large number of modules, covering a wide variety of capabilities.
|
|
|
|
1Pieces of the CGIpackage can be kept elsewhere, and other packages can be in the
CGI.pmfile, but the main pieces of the package are in the module file.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
If you plan to create substantial pieces of Perl software, you will want to
become comfortable with the ins and outs of package and module construc-
tion.2If you merely plan to usepackages and modules, however, our intro-
ductory coverage should suffice.
|
|
Extensionscan be very powerful, because they directly affect the code of
MacPerl itself. They are difficult to implement, however, as they are not
even written in Perl! Consequently, we will not cover them in any detail.
|
|
An extension is accessed through a corresponding module; the fact that a
module loads or accesses an extension is entirely invisible to the user of the
module. Nonetheless, some understanding of the basic nature of extensions
may serve to keep you out of trouble.
|
|
Normally, a module's documentation will note the fact that an extension is
being used. Nonetheless, keep your eyes out for files with the .xssuffix.
Most extensions are written for use with Unix and will need to be ported
(edited, compiled, etc.) to the Macintosh before you can make use of them.3
|
|
If an extension is required for a module, you probably should forget about
using it with MacPerl. But, if you are feeling brave and/or confident, don't
let us stop you. The perlxstutdocumentation and Advanced Perl Pro-
grammingare good places to start learning what you'll need to know.
|
|
Librariesare collections of related subroutines that are grouped together in
single files. Perl libraries usually have the suffix .pland were primarily
written for Perl version 4.4During the past few years, libraries have been
mostly replaced by modules. Modules do not work under Perl version 4, but
libraries do work under Perl version 5.
|
|
Finally, remember that the purpose of all of these forms of code encapsula-
tion is to make yourlife easier. Rather than writing the same code over and
over again or - worse - spending time duplicating the functionality of code
someone else has already written, code reuse allows you to spend your time
and brainpower more efficiently.
|
|
|
|
2See the perlref, perldsc, perllol, perltoot, perlobj, and perlbotmanual
pages, as well as Modules: Creation, Use and Abusein the perlmodlibmanual page
and, as always,Programming Perl.
3See Chapter 23, Building MacPerl And Extensions, for more information.
4Many people use the .plsuffix for general Perl scripts, too, not just for Perl libraries.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Note: Installation and use of modules requires substantial understand-
ing of Perl. If much of this chapter seems incomprehensible, get help
from an experienced Perl user the first time you install or use a module.
|
|
Understanding Modules
|
|
In order to understand the structure of a module, it is necessary to understand
the concepts of namespacesand packages. A namespace is a specifiable con-
text in which a name has meaning. By giving a namespace a unique label,
ambiguous interpretations can be avoided. The name "Chris", for instance,
is very meaningful within the Nandor home, but quite ambiguous outside it.
As such, it must be tied to a unique namespace (i.e., "Nandor").
|
|
If Chris has an unmarried sister named Jennifer, and then marries a woman
named Jennifer who takes his family name, a name clashwill occur with
the names of the two ladies. The name clash may be alleviated by chang-
ing one of the ladies' names (unlikely), removing one of them from existence
(usually illegal), or by moving one of them to another namespace (i.e., mar-
rying off the sister). If the name clash is not alleviated, we might find the
ladies opening each other's gifts at Christmas.
|
|
Similarly, Perl's packages implement namespaces for variable names, sub-
routines, etc. Within a given package, care must be taken that all variables
and subroutines have unique names, to avoid name clashes.
|
|
If a piece of external code needs to access data within a package, the exter-
nal code must make the context clear to MacPerl. In other words, the pro-
gram must somehow tell MacPerl where a particular variable or subroutine
resides. This is done by using the "double-colon" syntax5, as:
|
|
Package::subroutine()
|
|
If the package name is omitted, MacPerl will assume that the current pack-
age is meant. The starting package is always called main. Thus, the two
printstatements below are exactly equivalent:
|
|
$x = "Hello world.\n";
print $x;
print $main::x;
|
|
|
|
5You may see older code that uses the single-tick syntax (e.g., Package'variable), but
this has been officially deprecated and should be avoided.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
If the current package is main, the variable $xcan be accessed as either $x
or, more specifically, as $main::x. The current package can be changed at
any time within a program, using the packagedeclaration:
|
|
$v = 'foo';
|
|
package A;
$v = 'bar';
sub myprint { print $_[0] || $v }
|
|
package main;
print $v;# prints 'foo'
print $A::v;# prints 'bar'
A::myprint();# prints 'bar'
A::myprint($v);# prints 'foo'
|
|
There are two different variables here, $main::vand $A::v. Because
myprint()is in packageA, when it looks for $v, it finds $A::v. In the
main package, however, $vcorresponds to $main::v.And, when code in
the main package wants to access myprint(), it must ask specifically for it
as A::myprint(). (That is, perl will not "guess" what is meant.)
|
|
As we discussed in
Chapter 8, Curious Constructions, global variables can be
"seen" from any part of the program. Package variables are visible in the
same way. In fact, Perl considers global variables to be a special case of
package variables, with mainas the default package.
|
|
A couple of cautions are in order, however. Accesses from other packages
must, in general, be qualified with the variable's package name.6Also, the
effects of a package declaration are limited to the enclosing block; thus:
|
|
$i = 1;
print "$i\n";
if ($i == 1) {
package A;
$i = 2;
print "$i\n";
}
print "$i\n";
|
|
|
|
# prints '1'
|
|
|
# prints '2'
|
|
|
# prints '1'
|
|
|
|
6Some special global variables, such as $], belong to package mainbut do not need to
be qualified with the package name when accessed from other packages.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Getting Modules
|
|
Modules of all shapes and sizes are available from many places; finding,
understanding, and using them is, of course, your responsibility. The module
information on our CD-ROM is a very good starting point. We also recom-
mend the module reference books in O'Reilly's Perl Resource Kit.
|
|
The best place to find modules is in the MacPerl distribution. The modules
that come with MacPerl have, in general, been tested and (if need be) modi-
fied for use with MacPerl. The distribution includes a slew of modules for
doing CGI, text manipulation, database access, benchmarking, networking,
and other fun things all developers should keep in their bag o' tricks.
|
|
If, however, you do not see what you need in the distribution, you will have
to start hunting around. The first stop on your treasure hunt should be the
MacPerl Pages ( www.ptf.com/macperl). Drop into the Online Support
area, look through the MacPerl FAQ-O-Matic, and see if someone has left
a trail of crumbs for you to follow.
|
|
While you are there, be sure to join the MacPerl mailing list. The list is a
great resource for MacPerl users; if you have a question about MacPerl that
isn'tanswered in this book or on the MacPerl Pages, the MacPerl list is a
very good place to ask. Specifically, if you need a module that works under
MacPerl, these folks can probably find one for you.
|
|
Before asking the list, however, you might want to check the Comprehen-
sive Perl Archive Network. The CPAN ( www.perl.com/CPAN/CPAN
.html) is the authoritative repository for Perl-related materials. It is a
world-wide, distributed network of archive sites, providing fast and reli-
able access in many parts of the world. It is also, unfortunately, strongly
oriented towards Unix-based Perl and its organization is imperfect.
|
|
The CPAN includes the source code for Perl, ports to non-Unix platforms
(including the Macintosh), assorted Perl scripts, documentation, and many
hundreds of modules. Although the CPAN includes a fair amount of index-
ing, it is a large repository and can be a bit confusing. Relax and take your
time; eventually, you'll (probably :-) find something you can use.
|
|
We have included an indexed snapshot of the CPAN on the enclosed CD-
ROM. We have expanded and unpacked many of the archives of Perl source
code and documentation. The CPAN is very active, however, so you may
want to look for (and perhaps retrieve) updated or new modules.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Installing Modules
|
|
Be sure to examine modules before you attempt to install them. Some of the
CPAN's modules are accessed via extensions; in general, you can't use these
with MacPerl. Other modules may be platform-specific, which usually
means "specific to Unix", but a substantial number of modules are also spec-
ific to other platforms, such as Microsoft Windows 95/NT.
|
|
Most modules, however, require only pure Perl. These are usually safe for
use with MacPerl, as long as their authors followed the guidelines for good
cross-platform Perl (see
Chapter 9, Odd Corners). There are also some mod-
ules on the CPAN that are specific to MacPerl. You will usually find these
in the area CPAN/modules/by-module/Mac.
|
|
Even assuming these constraints, modules from the CPAN require certain
steps to be followed before they can be used with MacPerl. This process is
not substantially different from the mostly automated process followed on
Unix, but you will need to perform some manual steps:
|
|
-
Decompress and extract the file from any archive
-
Check the contents
-
Move the files to an appropriate location
-
Handle line breaks
-
Check for AutoSplit
|
|
We'll cover these steps in detail below.
|
|
-
Decompress and extract from archive
|
|
Many modules are "tarred and gzipped", and have the double suffix .tar.gz
or .tgz. taris a program that archives (bundles together) any number of files
and directory structures into a single file. It does not compress the files at
all, however; it simply archives them. So, module developers then use the
gzip(GNU zip) program to compress the archive.
|
|
In order to use a tarred and gzipped file, the process must be reversed; the
file must be "gunzipped and untarred". There are, of course, versions of tar
and gzip for Mac. MacGzipand suntarare freeware programs (included on
the CD-ROM) that can create and extract from tar and gzip files.
|
|
If there is no need to create tar or gzip archives, but only to extract from
them, the most common and probably easiest solution is Aladdin Systems'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
StuffIt Expanderand DropStuff with Expander Enhancer.7The Expander
Enhancer that comes with DropStuff (shareware) allows StuffIt Expander
(freeware) to extract from many UNIX formats, including tar and gzip.
|
|
-
Check the contents
|
|
Untarring the archive should create a folder containing all the files in the
module's distribution, including documentation. Start by looking over the
documentation files, often called README and INSTALL.
|
|
The module's usage documentation may be embedded in the module itself,
using Perl's POD (plain old documentation) format (see perlpod). You can
read it with any text editor, as the markup is reasonably simple and unob-
trusive, but it is meant to be viewed with a POD viewer. Shuck, bundled
with MacPerl, is probably the best tool to use for viewing POD on a Mac.
|
|
If the documentation mentions any files with an .xssuffix, or you see such
files in the unpacked directory, the module is probably based on a Perl
extension. If so, you should probably forget about using it with MacPerl.
|
|
In general, notes or directions having to do with "make", "Makefile", or
"MakeMaker" can be ignored. Make is a Unix facility that can compile and
install extensions, install the modules themselves, and more. Unfortunate-
ly, the installation under MacPerl will have to be done manually.
|
|
-
Move the files to an appropriate location
|
|
When MacPerl looks for a module, it looks in the folders specified in the
LibrariesPreferences (found under the Editmenu). Specificially, it exam-
ines the folders in the specified order, checking for the requested module.
Naming conflicts are not an issue for MacPerl (it just grabs the first match it
finds), but programmers must keep them in mind.
|
|
Create a new folder (conventionally named site_perl) for storing locally-
added modules. Then, in the Preferencesdialog, add the folder to Mac-
Perl's search list by clicking on Add Pathand selecting the directory.8
|
|
|
|
7Both Stuffit Expander and DropStuff are available at www.aladdinsys.com.
8If you name the folder site_perland put it in the MacPerl folder, you do not need to
add it to your preferences, as that folder name is specially added for you. But, when
you upgrade your version of MacPerl, don't forget to retain a copy of the folder!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Note:No part of any path added to the preferences can have a comma
in it, including the names of the folders enclosing the target folder.
|
|
MacPerl needs to know the complete path of the module file, including its
position in the folder hierarchy. Consequently, you must tell MacPerl the
module file's complete path name, including the entire series of folders
that leads from the hard disk to the file.
|
|
Because of the Finder's interactive user interface, Mac OS users don't deal
very often with path names, so a short review may be appropriate. Let's
say that your hard disk is named HD, that you have installed the MacPerl
distribution in a top-level folder named MacPerl , and that you have
created a folder named site_perlwithin the MacPerl folder, as:
|
|
HD
MacPerl
site_perl
|
|
In Mac OS file naming syntax, the location of the site_perlfolder is:
|
|
HD:MacPerl :site_perl:
|
|
This name specifies the full pathfrom the top of the file tree (the hard
disk volume) down to the site_perlfolder. Assuming that the CGImodule
were installed in site_perl, its full path name would be:
|
|
HD:MacPerl :site_perl:CGI.pm
|
|
Fortunately, MacPerl doesn't need to know the complete path when finding
modules referenced by your program. It is capable of using a relative path,
starting from the directories specified in your Libraries preferences.
|
|
In the example above, the directive use CGIwould cause MacPerl to look
for a file named CGI.pm, installed directly within site_perl. If the module
is installed at a lower level, however, more complicated syntax would be
needed. Let's say that we need to use the module:
|
|
HD
MacPerl
site_perl
Mac
Apps
Anarchie.pm
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Recall that the package separator for Perl is the double colon (::). When a
package is in a module, the double colon also represents a certain directory
structure. Thus, our Perl code would ask for Mac::Apps::Anarchie, caus-
ing MacPerl to look for a file named:
|
|
HD:MacPerl :site_perl:Mac:Apps:Anarchie.pm
|
|
Note:MacPerl packages and Mac OS paths use similar, but different
syntax (i.e., double colons, rather than single colons). The fact that sim-
ilar symbols are used to represent these slightly different concepts is
purely coincidental. Remember the difference, however!
|
|
Sometimes, there are many modules in one archive, as is the case with LWP
(also known as libwww-perl), a set of modules providing World Wide Web
access (see Chapter 17,
Network Programming). It is imperative that each
file with the .pmsuffix get installed in its proper directory. Otherwise,
MacPerl will not be able to find (and load) the required module code.
|
|
-
Handle breaks
|
|
Computers use certain characters - usually invisible - to represent line
breaks. Mac OS uses the octal character \015for line breaks (sometimes
called carriage return, or CR). Unix uses \012(line feed, or LF). DOS and
Windows use the sequence \015\012. (Aren't standards wonderful? :-)
|
|
Most of the time, the decompression and extraction process will automati-
cally convert the line breaks for you. But, if you need to fix them yourself,
there are innumerable ways to do it. Advanced text editors (e.g., BBEdit)
and many utilities can do the conversion. You can also do the conversion
with Perl. Drop any file on the droplet called lf2cr4mac(included on the
CD-ROM) and any line breaks will be converted automagically.
|
|
Note: If you open a file in MacPerl and it shows as one long line, the file
is probably using \012as its line break character. If every line is pre-
ceded by a tall rectangle or other funny-looking symbol, then \015\012
is probably being used. In either case, you will need to fix the file.
|
|
-
Check for AutoSplit
|
|
During the automated process Unix uses to install modules, some modules
are automatically split up (autosplit) into smaller files. The AutoSplit
module can be used with MacPerl, but it must be invoked explicitly, as
described below. Alternatively, you can simply avoid using this feature.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The basic idea behind AutoSplit(using the AutoLoadermodule to do all
the real work) is this: if a part of a module is not used, it is a waste of
coputing power to interpret and compile that part. So, some modules are
designed to have subroutines moved to separate files.
|
|
We don't need to discuss the intricacies of AutoSplithere, except to say
that there are two easy ways to help MacPerl deal with modules that need
to be autosplit. One is to comment out the __END__line in the module. The
subroutines to be split out are stored after that line, so MacPerl will be able
to find and compile them (regardless of whether they are needed).
|
|
The other way is a bit more complicated, but allows the AutoSplitopti-
mization to be used. After putting the module in the proper directory, use
AutoSplitto do the work for you. Keep in mind that you must redefine
$dirand complete the full path to the module to be autosplit:
|
|
#!perl -w
use AutoSplit;
my $dir = "$ENV{MACPERL}site_perl";
autosplit("$dir:Mac:Apps:Anarchie.pm",
"$dir:auto", 0, 1, 1);
|
|
This will split any subroutines after __END__into separate files (named
<subname>.al), and will put the files in the specified folder:9
|
|
HD:MacPerl :site_perl:auto:Mac:Apps:Anarchie:
|
|
Nothing bad happens, by the way, if this script is run on a module that
isn't meant to be autosplit. So, if you aren't sure whether a module needs to
be autosplit, feel free to run autosplit on it as a precautionary measure.
|
|
use-ing Modules
|
|
A module file can be included in your program with either the useor
requiredirective; useis more typical, however. The differences are
both syntactic and functional. Syntactically, requireis usually given a
filename, while usemust be given a package name (which MacPerl then
translates into a filename).10
|
|
|
|
9The autodirectory will be created automatically if it does not exist already.
10Since libraries are not packages, as modules are, they are called with require.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The functional differences are twofold. First, usepreloads and executes the
requested module at compile time; requireloads the module at runtime.
Second, if the module tries to export any symbols (such as subroutines or var-
iables) into the current package, usewill import the symbols automatical-
ly and requirewill not.11The following code snippets are equivalent:
|
|
use Some::Module;# package name,
... # auto-imports symbols
|
|
BEGIN {
require ':Some:Module.pm';# relative path name
Some::Module->import();# force import symbols
}
...
|
|
The special BEGINblock tells perl to execute a given block of code at com-
pile time. If requireis not enclosed in a BEGINblock, its execution will be
delayed until runtime.
|
|
What Next?
|
|
At this point, your actions will be dependent upon the specifics of the mod-
ule itself. The documentation - usually embedded POD in the module - will
dictate how you should continue. Read the documentation, then start writ-
ing code that will use the module. However, if the module is object-orien-
ted, then you will need to be familiar with a few more concepts.
|
|
Object-Oriented Programming
|
|
As with libraries, the primary purpose of modules is to define a collection
of subroutines. But, in many of the available modules, a collection of subrou-
tines or data is accessed through an object, bringing the wonders of Object-
Oriented Programming(OOP) to Perl.12
|
|
OOP techniques are useful because they hide the implementation details of
objects behind well-documented access methods. This enables a very useful
|
|
|
|
11If requireis called with a package name instead of a filename (e.g., require
Some::Module), then it, too, will preload the module at compile time, like use. How-
ever, it will not import the exported data as usedoes.
12We cannot possibly teach OOP here in this book, or even sufficiently cover OOP as
it relates to Perl. Hopefully, this will help you understand a little bit more about what
some modules are doing, and frame OOP terms in Perl terms for you.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bargain to be made: the programmer that is using a module promises not to
make use of the implementation details; the programmer that creates the
module promises not to modify the interfaces to the access methods.
|
|
Many modern programming languages, such as C++ and Java, include sup-
port for OOP. With the advent of Perl version 5 and modules, Perl does too.
Many of the modules in the CPAN are written using OOP concepts and
syntax, so you will need to learn a bit about OOP in order to get by.
|
|
Let's start with a discussion of some OOP concepts and terminology, as used
in the Perl community. Don't feel that you have to memorize these terms;
we won't be depending on them much, except in the Toolbox Module chap-
ters. You may encounter them, however, as you read literature on Perl.
|
|
An objectis a referencethat knows which class it belongs to. A classis a
package that provides for working with objects. A methodis a subroutine
that is accessed via objects or classes. That's it. Really!
|
|
The bottom line is that in OOP, all of the information and interactions
related to an item are accessed through an object. We touched on this in
Chapter 1,
with Rachel's "egg" object and its get()and put()methods.
|
|
A module that implements OOP style defines how each new instanceof an
object is to be created. For example, an egg is an object; each individual egg
is an instanceof the egg object: very alike, but distinct.
|
|
If the client code wants a new egg object, it asks the appropriate module to
create one, passing back a reference. The creation is done by a special type
of method, often called a constructor(conventionally named new).
|
|
The reference to the object can then be used to invoke methods that are
defined for the object's class.
Virtualmethods are called through the object
reference; staticmethods are called through the class.
|
|
use Carton::Eggs;
$cart = new Carton::Eggs;# construct a carton
print $cart->count();# should print "12"
$egg= $cart->getEgg();# get an "egg" object
print $cart->count();# should print "11"
|
|
For more information on OOP theory, check your local bookstore. Many
books on OOP theory and programming are available. Alternatively, read
Advanced Perl Programming, which covers OOP in a Perlish context.
|
Copyright © 1997-1998 by Prime Time Freeware. All Rights Reserved.