May 2006

Local Perl Libs

Sometimes a site has need for easily accessible Perl libraries. Three methods to go about keeping handy Perl code readily available are:

  1. Just keep a code repository of functions and dump them into programs on an as needed basis.
  2. Write a Perl library with a group of functions in them.
  3. Write Perl modules.

A text on this site discusses the first option, this text deals with the second option. All three bear discussion though. Within this article, setting up a library (not module) will be addressed.

Weighing In

Many factors have to be weighed to argue either for or against simply yank putting versus a local requires versus writing a module.

The yank put method seems appropriate for low frequency deployment. An example is a one time or limited time program. Many system administrators use this method because, well managing libraries is no fun. When a small set of programs or low frequency of development exists is the effort worth it?

Creating local libraries using the requires include method in Perl is a middle ground. A shared local set of libraries may be created that the Perl administrator does not have to solely maintain. A possible scenario is the line between sysadmin and system programmer. It is safe to say that the programmer is a competent programmer but may not know much about administering a Perl installation on the system. By creating a shared area on the filesystem, the sysadmin and programmer can deposit their libraries and indeed - benefit from each other's work.

Going the full monty of modules requires a bit more work. Modules can be setup with shared access. To keep downloaded modules from interfering with local modules, some administrative work needs to be done. If a module is good enough, it may be uploaded to CPAN and installed as part of the site install. Note that perl libs - just files with some functions in them - can also be uploaded to CPAN.

The last item to discuss is documentation. Method one has no real strict rules for documentation. Method two does not either, generally documentation is included. Method three requires documentation.

Implementation Examples

Since yanking/putting functions from one file to another is pretty self explanatory, a look at creating a local library is presented.

Implementation Details

At the imaginary site is an archive nfs server. On the server are directories packed with archives and a set of files listing archives. How the archives are organized is not important, what is important is the number of growing Perl programs and scripts that access them. These particular bits do the same operations over and over:

  • Loading directories into arrays
  • Loading files into arrays
  • Reverse sorting
  • Chomping every item in the directory list

The goal: put those tasks into a separate readable location to save time.

The Subroutines

load_file
##
# load_file: Open a file, read each line into an array, close the
#            file and return the array of lines.
##
sub load_file 
{
  my ($file) = shift;
  my @file_contents;

  open(FILE, $file) or die "Unable to open file $file: $!\n";
  @file_contents = <FILE>;
  close FILE;

  return @file_contents;
}
load_dir
##
# load_dir: Open a directory, read each entry into an array, close
#           the directory handle and return the array.
##
sub load_dir 
{
  my ($dir) = shift;  
  my @dir_contents;  

  opendir(DIR, $dir) or die "Unable to open dir $dir: $!\n";
  @dir_contents = readdir(DIR);
  close(DIR);

  return @dir_contents;
}
rsort
##
# rsort: Sort then reverse an array.
##
sub rsort 
{
  my (@contents) = @_;

  @contents = sort(@contents);

  return (reverse(@contents));  
}
atomic_chomp
##
# atomic_chomp: Chomp every item on an array, return the array.
##
sub atomic_chomp
{
  my (@list2chomp) = @_;

  foreach(@list2chomp) {
    chomp($_);
  }

  return @list2chomp;
}

Documentation

Time to add documentation. Perldoc tags go in the source file as a stub. The markup is self explanatory:

__END__
=head1 DESCRIPTION

This small library provides four simple function: load a file
into an array, load a directory into an array, sort and reverse
an array and chomp every item in an array.

The usage for each is:

    load_file(filename);
    load_dir(dirname);
    rsort(@array);
    atomic_chomp(@array);

=head1 EXAMPLES

 my @foo = load_dir("/home/mui");
 @foo = rsort(@foo);
 ($item1, $item2) = atomic_chomp($item1, $item2);

=head1 PREREQUISITES

none

=head1 COREQUISITES

none

=cut

Putting It Together

The now finished lib is ready:

##
# load_file: Open a file, read each line into an array, close the
#            file and return the array of lines.
##
sub load_file
{ 
  my ($file) = shift;
  my @file_contents;

  open(FILE, $file) or die "Unable to open file $file: $!\n";
  @file_contents = <FILE>;
  close FILE;

  return @file_contents;
} 

##  
# load_dir: Open a directory, read each entry into an array, close
#           the directory handle and return the array.
##
sub load_dir
{
  my ($dir) = shift;
  my @dir_contents;

  opendir(DIR, $dir) or die "Unable to open dir $dir: $!\n";
  @dir_contents = readdir(DIR);
  close(DIR);

  return @dir_contents;
}

##
# rsort: Sort then reverse an array.
##
sub rsort
{
  my (@contents) = @_;

  @contents = sort(@contents);

  return (reverse(@contents));
}

##
# atomic_chomp: Chomp every item on an array, return the array.
##
sub atomic_chomp
{
  my (@list2chomp) = @_;

  foreach(@list2chomp) {
    chomp($_);
  }

  return @list2chomp;
}

1; # Main - return a true value

__END__
=head1 DESCRIPTION

This small library provides four simple function: load a file
into an array, load a directory into an array, sort and reverse
an array and chomp every item in an array.

The usage for each is:

    load_file(filename);
    load_dir(dirname);
    rsort(@array);
    atomic_chomp(@array);

=head1 EXAMPLES

 my @foo = load_dir("/home/mui");
 @foo = rsort(@foo);
 ($item1, $item2) = atomic_chomp($item1, $item2);

=head1 PREREQUISITES

none

=head1 COREQUISITES

none

=cut

The only change is the addition of the ;1, a true return signal is needed to use the library.

The Lib in Action

Time to take a look at the lib in action, first, the perldoc output:

[mui@vela:~$] perldoc atomic.pl
ATOMIC(1)  User Contributed Perl Documentation ATOMIC(1)

DESCRIPTION
  This small library provides four simple function: load a file into an
  array, load a directory into an array, sort and reverse an array and
  chomp every item in an array.

  The usage for each is:

      load_file(filename);
      load_dir(dirname);
      rsort(@array);
      atomic_chomp(@array);

EXAMPLES
   my @foo = load_dir("/home/mui");
   @foo = rsort(@foo);
   ($item1, $item2) = atomic_chomp($item1, $item2);

PREREQUISITES
  none

COREQUISITES
  none

perl v5.8.8            2006-05-16              ATOMIC(1)

An example of using the library:

#!/usr/bin/env perl
# atomtest - test out the atomic functions

use strict;

require "/path/to/atomic.pl";

my @dirlist = load_dir("/etc");
my @file    = load_file("/etc/passwd");

@dirlist = rsort(@dirlist);        # Sort and reverse the directory
@dirlist = atomic_chomp(@dirlist); # Chomp the directory list

listall(@dirlist);
listall(@file);
sub listall 
{
        my @list2print = @_;

        foreach(@list2print) {
                print "$_\n";
        }
}

Instead of cluttering the output atomtest is piped to wc:

[mui@vela:~$] ./atomtest | wc -l
244

Summary

Creating a Perl library and sharing via a path is easy. Creating any shared libraries in an organization can save time and reduce headaches.