Item 45: Use h2xs to generate module boilerplate.

'h2xs' to generate module boilerplate ."-->

Item 45: Use h2xs to generate module boilerplate.

From Item 42 you know that modules are packages that follow certain conventions. There is enough nitpicky detail in these conventions to make it difficult to write a module on your own without some help. This is particularly true if you are planning to package and release a module for public use. Fortunately, help is available in the form of a utility called h2xs .

The h2xs program was originally designed to simplify the process of writing an XS module (see Item 47), but has long since been used for the broader purpose of providing a starting point for writing all Perl modules, XS or not. You should always use h2xs to create the boilerplate for a new Perl module. This will save you and your module's potential users many hours of grief , confusion, and frustration. Trust me on this one.

The easiest way to get started with h2xs is to try it for yourself. Let's look at an example.

Creating a module using h2xs

Let's use h2xs to create a skeleton for a new module called File::Cmp , then flesh it out so that it works. File::Cmp will contain a function that will compare the contents of two files and return a value indicating whether they are identical. (There already is a File::Compare module that does the same thing, but, remember, this is just an example.)

The first step is to run h2xs . This will create some directories and files, so be sure to execute the command in a "scratch" directory in which it's okay for you to work. We will use the -A , -X , and -n options. The -A option tells h2xs not to generate any code for function autoloading. The -X option tells h2xs that this is an ordinary module and that no XS skeleton will be needed (see Item 47). The -n option supplies the module name . This is the usual combination of options for starting work on a "plain old module":

Begin work on a module by running h2xs .

 %  h2xs -A -X -n File::Cmp  Writing File/Cmp/Cmp.pm  Writing File/Cmp/Makefile.PL  Writing File/Cmp/test.pl  Writing File/Cmp/Changes  Writing File/Cmp/MANIFEST 

No XS or autoloading.

h2xs creates some files.

At this point you already have a "working" module that does nothing. You could build, test, and install it just as if you had downloaded it from the CPAN (see Item 41). Before we do that, however, let's add some code so that it actually does something useful. Let's start with the file Cmp.pm , which contains the new module's Perl source code. It should look something like the followingminus the italicized annotations, of course:

The file Cmp.pm

Begin by setting the default package to File::Cmp , turning on strict , and declaring a few package variables .

 package File::Cmp;  use strict;  use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); 

Use the Perl library's Exporter module. We can require rather than use it because this module will be use -d.

 require Exporter; 

Subclass Exporter and AutoLoader . We're not actually using AutoLoader in this example, so you can delete any references to it if you like. For more about subclassing and inheritance in Perl, see Item 50.

 @ISA = qw(Exporter AutoLoader); 

Here's a place to add the names of functions and other package variables that we want to export by default. When we use this module, Exporter will import these names into the calling package. You also can add names to an array called @EXPORT_OK . Exporter will allow those names to be exported on request.

 # Items to export into callers namespace by default. Do not export  # names by default without a very good reason. Use EXPORT_OK instead.  # Do not simply export all your public functions/methods/constants.  @EXPORT = qw(  ); 

A version number that you should increment every time you generate a new release of the module.

 $VERSION = '0.01'; 

Insert function(s) after the next line.

 # Preloaded methods go here. 

We're not autoloading anything, so ignore this.

 # Autoload methods go after =cut, and are processed by the autosplit program. 

Modules must return a true value to load properly (see Item 54 ). Make sure you don't get rid of this all-important 1 .

 1;  __END__ 

The stub for the built-in POD documentation (see Item 46 ) follows the __END__ of the source code.

 # Below is the stub of documentation for your module. You better edit it!  =head1 NAME  File::Cmp - Perl extension for blah blah blah  =head1 SYNOPSIS    use File::Cmp;    blah blah blah  =head1 DESCRIPTION  Stub documentation for File::Cmp was created by h2xs. It looks like  the author of the extension was negligent enough to leave the stub  unedited.  Blah blah blah.  =head1 AUTHOR  A. U. Thor, a.u.thor@a.galaxy.far.far.away =head1 SEE ALSO  perl(1).  =cut 

Let's add a function called cmp_file . It will compare the contents of two files, then return if they are identical, a positive number if they are different, and -1 if some sort of error has occurred. Insert the following code after the line that says Preloaded methods go here :

cmp_file : Compare contents of two files

 sub cmp_file {    my ($file1, $file2) = @_;    local(*FH1, *FH2); 

This subroutine takes two filenames as arguments.

 return -1 if !-e $file1 or !-e $file2;    return 0 if $file1 eq $file2; 

See if files exist.

Same filenames = same contents.

 open FH1, $file1 or return -1;    open FH2, $file2 or        close(FH1), return -1;    return 1 if -s FH1 != -s FH2; 

Open files.

Different sizes = different contents.

 my $chunk = 4096;    my ($bytes, $buf1, $buf2, $diff);    while ($bytes =          sysread FH1, $buf1, $chunk) {      sysread FH2, $buf2, $chunk;      $diff++, last if $buf1 ne $buf2;    } 

We will read one "chunk" at a time.

Read a chunk from each file and compare as strings.

 close FH1;    close FH2;    $diff;  } 

close files, return status

We will want to export cmp_file from this module automatically (see Item 42). Just add it to the @EXPORT list:

 @EXPORT = qw(      cmp_file  ); 

Now we need a test script. Open the file test.pl and add the following at the end:

Test script for File::Cmp

This script creates three files containing some random data. Two files are identical and the third is different. We start by creating the data:

 srand();  for ($i = 0; $i < 10000; $i++) {    $test_blob .= pack 'S', rand 0xffff;  }  $test_num = 2; 

Do the testing inside an eval block (see Item 54 ) to make error handling easier.

 eval {    open F, '>xx' or die "couldn't create: $!";    print F $test_blob;    open F, '>xxcopy' or die "couldn't create: $!";    print F $test_blob;    open F, '>xxshort' or die "couldn't create: $!";    print F substr $test_blob, 0, 19999; 

The test files have been created. Now, use cmp_file to compare them.

 if (cmp_file('xx', 'xxcopy') == 0) {      print "ok ", $test_num++, "\n";    } else {      print "NOT ok ", $test_num++, "\n";    }    if (cmp_file('xx', 'xxshort') > 0) {      print "ok ", $test_num++, "\n";    } else {      print "NOT ok ", $test_num++, "\n";    }  }; 

Report any exceptions from the eval block, tidy up, and we're done.

 if ($@) {    print "... error: $@\n";  }  unlink glob 'xx*'; 

You also should change the line near the top of test.pl so that the count of tests reads correctly:

 BEGIN { $ = 1; print "1..3\n"; } 

At this point, we can build and test the module (see Item 41):

 %  perl Makefile.PL  Checking if your kit is complete...  Looks good  Writing Makefile for File::Cmp  %  make test  cp Cmp.pm ./blib/lib/File/Cmp.pm  AutoSplitting File::Cmp (./blib/lib/auto/File/Cmp)  PERL_DL_NONLAZY=1 /usr/local/bin/perl -I./blib/arch  -I./blib/lib -I/usr/local/lib/perl5/sun4-solaris/5.003  -I/usr/local/lib/perl5 test.pl  1..3  ok 1  ok 2  ok 3 

Cool.

There are still some things to be done. You will need to replace the documentation stub in Cmp.pm with something more informative (see Item 46). You also should add a description of the work you did to the log in Changes . You could add some more thorough tests to test.pl .

Once you have whipped the module into shape, you can prepare a distribution. Just make the tardist target:

 %  make tardist  rm -rf File-Cmp-0.01  /usr/local/bin/perl -I/usr/local/lib/perl5/sun4-solaris/5.003  -I/usr/local/lib/perl5 -MExtUtils::Manifest=manicopy,maniread \          -e 'manicopy(maniread(),"File-Cmp-0.01", "best");'  mkdir File-Cmp-0.01  tar cvf File-Cmp-0.01.tar File-Cmp-0.01  File-Cmp-0.01/  File-Cmp-0.01/Makefile.PL  File-Cmp-0.01/Changes  File-Cmp-0.01/test.pl  File-Cmp-0.01/Cmp.pm  File-Cmp-0.01/MANIFEST  rm -rf File-Cmp-0.01  compress File-Cmp-0.01.tar 

Voila! You now have a file called File-Cmp-0.01.tar.Z , which contains the source to your module. This file follows the conventions of the CPAN and is ready for distribution to the world.

If you have written a useful module, consider sharing it with the rest of the worldsee Item 48.



Effective Perl Programming. Writing Better Programs with Perl
Effective Perl Programming: Writing Better Programs with Perl
ISBN: 0201419750
EAN: 2147483647
Year: 1996
Pages: 116

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net