Creating Perl Modules
From TechWiki
Contents |
Modular Programming
Modular programming is a software design technique that increases the extent to which software is composed from separate parts, called modules. Conceptually, modules represent a separation of concerns, and improve maintainability by enforcing logical boundaries between components. Modules are typically incorporated into the program through interfaces. A module interface expresses the elements that are provided and required by the module. The elements defined in the interface are visible to other modules. The implementation contains the working code that corresponds to the elements declared in the interface.
Modular programming greatly improves both the readability along with maintainability of code.
Perl and Modules
Perl comes with certain inbuilt modules. The true power of Perl however is derived from CPAN. CPAN (Comprehensive Perl Archive Network) is an excellent and exhaustive source of Perl modules. CPAN modules are nearly all Open Source. The advantage of this is that CPAN provides some incredible tools to easily create and document your own Perl modules.
Perl also allows the creation of local packages, please make sure you know how to write local packages before you attempt to create a CPAN ready package.
Installing from CPAN
Please make sure you know how to install CPAN Modules before actually attempting to create one.
Creating a Perl Module
Please note that Perl modules are also called Perl Packages. The following sections describe the creation of Perl modules, and it is assumed that you know the following:
Please also note that this article assumes that you are working on Linux although most steps can be easily adapted to Windows.
Getting started
Before you start you need to be clear on whether you want to create a module that you want to eventually upload to CPAN or if you want to create one for your personal (or organizational use).
In general the process itself is identical - however when uploading to CPAN you need to be very careful regarding the additional things such as naming, flexibility and adherence to standards.
This article provides a way to create Perl modules for your personal use. Although the general principals behind the creation of modules remains the same please read the article on Creating Perl Modules for CPAN if you do want to eventually upload your module.
Setting things up
Perl modules ( at least the type you are attempting to create ) require a certain directory structure. You could of course go ahead and create this yourself. A simpler way to achieve this is by use of either module-starter or h2xs.
Since h2xs is a slightly older method of doing this we will limit this article to the use of module-stater.
The module-starter utility is distributed as part of the Module::Starter CPAN package. It creates a directory with stubs of all the necessary files to start a new module, according to recent "best practice" for module development, and is invoked from the command line, thus:
module-starter --module=Foo::Bar --author="Your Name" --email=yourname@yourdomain.com
Writing your Module
When writing modules there are certain things that are slightly different from when writing ordinary programs. Make sure you do the following:
use Strict and warnings
A module's code has to be warning and strict-clean, since you can't guarantee the conditions that it'll be used under.
WARNING: This is NOT 'just a standard'. The failure to use this will result in errors at in subsequent steps.
use Carp
Not at first!!
Well Carp is a way to ensure that you warn of errors from the perspective of the caller; this gives you a way to signal a problem with the caller and not your module. For instance, if you say this:
warn "No hostname given";
the user will see something like this:
No hostname given at /usr/local/lib/perl5/site_perl/5.6.0/Net/Acme.pm line 123.
which looks like your module is doing something wrong. Instead, you want to put the blame on the user, and say this:
No hostname given at bad_code, line 10.
You do this by using Carp and replacing your warns with carps. If you need to die, say croak instead.
NOTE: Keep warn and die in place for your sanity checks - where it really is your module at fault.
use Exporter
Exporter gives you a standard way of exporting symbols and subroutines from your module into the caller's namespace. For instance, saying use Net::Acme qw(&frob) would import the frob subroutine.
The package variable @EXPORT will determine which symbols will get exported when the caller simply says use Net::Acme - you will hardly ever want to put anything in there. @EXPORT_OK, on the other hand, specifies which symbols you're willing to export. If you do want to export a bunch of symbols, use the %EXPORT_TAGS and define a standard export set.
There a lot of ways of using Export, a simple way is as follows:
use base 'Exporter'; our @EXPORT_OK = qw(<Function and variable names here>);
NOTE:
- Function names can be written either as "&func" or simply "func"
- All other variables need to be exported as "$scalar", "@array", "%hash" and so on.
- Ensure that variables that are being exported are NOT local.
use POD
POD stands for Plain Old Documentation, module-starter or h2xs will provide a stub for you to fill in; if you're not sure about the format, look at perlpod for an introduction. Provide a good synopsis of how your module is used in code, a description, and then notes on the syntax and function of the individual subroutines or methods. Use Perl comments for developer notes and POD for end-user notes.
Write tests
By default there are certain tests that your module has to pass. However, you're encouraged to create self-tests for your module to ensure it's working as intended on the myriad platforms Perl supports; if you upload your module to CPAN, a host of testers will build your module and send you the results of the tests. Again, module-starter and h2xs provide a test framework which you can extend - you should do something more than just checking your module will compile. Test::Simple and Test::More are good places to start when writing a test suite.
Installing your Module
Now that you have created your Perl module, its time to install it onto your system.
Traverse to the root of your module directory structure - this directory should contain the following files:
blib Changes lib Makefile.PL MANIFEST README t
Now execute the following commands in sequence.
perl MakeFile.pl make make test make install --- Should be run as root, unless you intend to install this module locally.
Chances are there will be errors at various stages. Do Not Panic. Read them carefully and you should be able to sort things out.
Example
What follows are examples of "Hello, World" implemented in different styles of modules. It must be understood that a module is not necessary in Perl; functions and code can be defined and used anywhere. This is just for example purposes.
Procedural Example
Here is "Hello, World" implemented as a procedural module with a customizable target for the greeting, just to make things interesting. Also included is a short script to illustrate the module's use.
hello_world.pl
#!/usr/bin/perl
# Loads the module and imports any functions into our namespace
# (defaults to "main") exported by the module. Hello::World exports
# hello() by default. Exports can usually be controlled by the caller.
use Hello::World;
print hello(); # prints "Hello, world!\n"
print hello("Milky Way"); # prints "Hello, Milky Way\n"
Hello/World.pm
# "package" gives the namespace the module will reside in and also
# dictates the name of the file if you want it to be "use"d.
package Hello::World;
# By default Perl allows you to use variables without declaring
# them. While this may be convenient for short scripts and
# one-liners, in a longer module it is wise to declare your variables
# both to catch typos and to keep them from being accessible outside
# the module.
use strict;
# Similarly, Perl does not issue warnings by default. A module, being
# more complicated then a script, usually will find them very helpful
# for debugging.
use warnings;
# A module's version number is stored in $ModuleName::VERSION; certain
# forms of the "use" built-in depend on this variable being defined.
our $VERSION = '1.00';
# Inherit from the "Exporter" module which handles exporting functions.
# Most procedural modules make use of this.
use base 'Exporter';
# Export, by default, the function "hello" into the namespace of
# any code which uses this module.
our @EXPORT = qw(hello);
# Lines starting with an equal sign indicate embedded POD
# documentation. POD sections end with an =cut directive, and can
# be intermixed almost freely with normal code.
=head1 NAME
Hello::World - An encapsulation of a commonly output message
=head1 SYNOPSIS
use Hello::World;
print hello();
print hello("Milky Way");
=head1 DESCRIPTION
This is a procedural module which gives you the famous "Hello, world!"
message, and its even customizable!
=head2 Functions
The following functions are exported by default
=head3 hello
print hello();
print hello($target);
Returns the famous greeting. If a C<$target> is given it will be used,
otherwise "world" is the target of your greeting.
=cut
# define the function hello().
sub hello {
my $target = shift;
$target = 'world' unless defined $target;
return "Hello, $target!\n";
}
=head1 AUTHOR
Joe Hacker <joe@joehacker.org>
=cut
# A Perl module must end with a true value or else it is considered not to
# have loaded. By convention this value is usually 1 though it can be
# any true value. A module can end with false to indicate failure but
# this is rarely used and it would instead die() (exit with an error).
1;
Object-Oriented Example
And now here's an example of the same thing done in an object oriented style. The advantage of an OO module is each object can be configured independent of other objects.
hello_world.pl
#!/usr/bin/perl
use Hello::World;
my $hello = Hello::World->new;
$hello->print; # prints "Hello, world!\n"
$hello->target("Milky Way");
$hello->print; # prints "Hello, Milky Way!\n"
my $greeting = Hello::World->new(target => "Pittsburgh");
$greeting->print; # prints "Hello, Pittsburgh!\n"
$hello->print; # still prints "Hello, Milky Way!\n"
Hello/World.pm
# In Perl there is no special 'class' definition. A namespace is a class.
package Hello::World;
use strict;
use warnings;
our $VERSION = "1.00";
=head1 NAME
Hello::World - An encapsulation of a commonly output message
=head1 SYNOPSIS
use Hello::World;
my $hello = Hello::World->new();
$hello->print;
=head1 DESCRIPTION
This is an object-oriented library which can print the famous "H.W."
message.
=head2 Methods
=head3 new
my $hello = Hello::World->new();
my $hello = Hello::World->new( target => $target );
Instantiates an object which holds a greeting message. If a C<$target> is
given it is passed to C<< $hello->target >>.
=cut
# The constructor of an object is called new() by convention. Any
# method may construct an object and you can have as many as you like.
sub new {
my($class, %args) = @_;
my $self = bless({}, $class);
my $target = exists $args{target} ? $args{target} : "world";
$self->target($target);
return $self;
}
=head3 target
my $target = $hello->target;
$hello->target($target);
Gets and sets the current target of our message.
=cut
sub target {
my $self = shift;
if( @_ ) {
my $target = shift;
$self->{target} = $target;
}
return $self->{target};
}
=head3 to_string
my $greeting = $hello->to_string;
Returns the $greeting as a string
=cut
sub to_string {
my $self = shift;
return "Hello, $self->{target}!";
}
=head3 print
$hello->print;
Outputs the greeting to STDOUT
=cut
sub print {
my $self = shift;
print $self->to_string(), "\n";
}
=head1 AUTHOR
Joe Hacker <joe@joehacker.org>
=cut
1;

