Let's start by navigating into the folder where I currently keep my perl sources.
In here are loads of .pm files. Usually I just symlink this directory into my Perl path so that the .pm files are available. I don't think this is quite as cool as it could be. I want modules which I can easily install on a new box and just call up in my perl sources.
from here, I'll create the module structure for a new module. I am going to call it TestDB and it is just going to be a database connection later over DBI. It will read my database config from /etc and will provide me with simple connect, query and execute methods.
$ h2xs -AX Spiration::TestDB
This creates a new directory in my cwd called Spiration. The new Spiration directory in turn contains a TestDB directory, which contains the following files:
root@www:/export/spiration/perllibs# ls -al Spiration/TestDB/
drwxr-xr-x 3 root root 4096 Sep 16 12:31 ./
drwxr-xr-x 4 root root 4096 Sep 16 12:31 ../
-rw-r--r-- 1 root root 168 Sep 16 12:31 Changes
-rw-r--r-- 1 root root 52 Sep 16 12:31 MANIFEST
-rw-r--r-- 1 root root 507 Sep 16 12:31 Makefile.PL
-rw-r--r-- 1 root root 1081 Sep 16 12:31 README
-rw-r--r-- 1 root root 1916 Sep 16 12:31 TestDB.pm
drwxr-xr-x 2 root root 4096 Sep 16 12:31 t/
The Changes file is used to track changes in the source. I generally ignore this, becuase I use cvs to manage versioning.
The MANIFEST file contains a list of files in this directory - This should be kept up-to-date if you add new files in here.
Makefile.PL is a perl script used to create a makefile. You will use the makefile to test and install the module.
TestDB.pm is the perl module itselft. This is where the actual source code of this extension will hide.
So the next stage is to put the perl sources into TestDB.pm. I won't go into all the details, but I will identify the main items which should remain in TestDB.pm. This is what you will see in the package .pm file:
This declares the name of this package. Any variables defined within will exist within this package scope, unless defined otherwise.
These statements force the interpreter to use other useful perl extensions. Carp provides more verbose information to the CLI about things which might be or are going wrong during execution.
Strict is very important. It forces us to define the scope of a variable we are creating. This means that instead of just making every new variable a global, we have to scope our variables lexically using the 'my' keyword. This means that the variable is only available within the smallest containing block. This is important. It prevents us from colliding with other variables of the same name in other packages or subroutines.
Warnings - give us warnings about things which might cause problems. These are not fatal errors, but hints to the programmer of potenially problematic behaviour.
DBI - this is the module which our new TestDB module is going to leverage. DBI is a huge database interface for perl. My module is going to instantiate a new DBI connection object and call methods against it (such as query, execute, prepare, connect etc).
Spiration::Config - oh look! another module in the Spiration namespace. This is one I created earlier to expose configuration variables to the calling package - this allows me to define the database connection settings and other bits and pieces elsewhere. I can't be sure how many scripts will use them, but I can be sure that when I want to change them, I don't want to have to open every single script and make the modification - this allows me to abstract system-specific values out from the application logic.
Exporter - this line loads a module called Exporter. This will allow me to export certain variables into the namespace of the package which uses this extension.
So what comes next in our perl extension?:
our @ISA = qw(Exporter);
our @EXPORT = qw($dbh db_connect db_close db_query db_rows db_execute);
So first I initialise a variable called $dbh.
The following line indicates that this package is a subclass of the Exporter package. This allows me to call methods define in Exporter as if they are part of this package. Here we are using perl's object oriented behaviour to leverage functionality from one module to another, even though in this case we aren't actually defining a class.
In the next line I declare what subroutines and variables I want to export from this extension into the 'calling' package. This means that when another package uses 'use Spiration::TestDB';, then these are the functions and variables which will magically become available to it. In this case I define the single variable $dbh (which will contain the db connection object) and some database methods.
The next line looks like this
This is useful when we come to build a package later on.
From this point, I am free to start writing code and defining subroutines.. The rest of the program (up until the __END__ bit) does just that. The perl interpreter will continue reading the script until it reaches the __END__ string. At this point the file will no longer be interpreted by perl, so we are free here to enter our own documentation. If you are building your own module it is important that you work through this section beyond the '__END__' bit and fill in your own documentation to replace the snooty defaults .
Once all this hard work is done, we can proceed to compiling and installing the module and then building a package. Do this with:
Okay, so let's just explain these steps -
perl Makefile.PL - this runs the Makefile.PL script, which creates a makefile - this is required for the 'make' stages.
make - this creates the perl module
make install - this will isntall your module in to perl's path. It is now available to any other perl script running on this system.
make dist - this creates a .tgz archive of all your module's files. This is where the MANIFEST is important - it tells the builder what files are important for this module so that they can be included in the package. You will also notice that the tgz is versioned. This version string is taken from the $VERSION='0.01' in the TestDB.pm file itself - you see - everything has its purpose! This tgz file can now be distributed to other users on other systems and easily installed to offer the new functionality which our extension provides.
That concludes this article. I hope that's useful. It'll be useful to me in 6 months time when I come back to writing another Perl module. Perhaps I'll put something on CPAN too sometime.