DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

IniParser.pm, My First Perl Module

10.17.2008
| 3449 views |
  • submit to reddit
        // I don't think this still works, just found this in my backups and got sentimental.
// You don't and shouldn't use INI files for your projects in 2008, it's stupid. YAML is the way to go!

package IniParser;
require 5.00307;

$IniParser::VERSION='1.224';

sub new {
 
    shift;
    my $file = shift;
    my $dir = shift;
    
    my $parsing = {
       'file'          => $file,
       'dir'           => $dir
    };

    &set_file($parsing) if !$file;
    
    bless $parsing, 'IniParser';
    return $parsing;

}

sub import_names {

    # this method aliases the hashes in the $parse_classes
    # rarray of the object to the name of the respective
    # ini class and import them into the namespace of the
    # caller package

    my $rparse = shift; 
    my $rarray = shift;
    my $caller_pkg = caller;
    my ($class,$item);

      foreach $item (@$rarray) {
         if (!ref($item)) {
            $class = $item;
         }
         else {
            *{"${caller_pkg}::${class}"} = $item;
         }
      }
}

sub set_file {

    my $rparse = shift;
    my $new_name = shift;

    # if set_file is not called with an argument
    # with the name of the ini file, set_file
    # will look for an ini file with the name of the
    # script that is currently using the package

    if ($new_name) {
       $rparse->{'file'} = $new_name;
    }

    elsif (!defined($rparse->{'file'})) {
        $rparse->{'file'} = $0;
        $rparse->{'file'} =~ s/(\.?[\w\-.]+)\.([\w]+)?/$1\.ini/;
        # a dot *has* literal meaning inside a character class!!!
        # in the case above a dot means a period.
    }

    return $rparse->{'file'};
}

sub set_dir {

    my $rparse = shift;
    my $new_dir = shift;

    if ($new_dir) {
        $rparse->{'dir'} = $new_dir;
    }
    return $rparse->{'dir'};

}

    
sub which_file {

     # returns the name of the current ini file

     my $rparse = shift;
     return $rparse->{'file'};
}

sub parse_file {
     # the spawned hashes will still persist after
     # perl exits the sub since
     # they are referenced in the mem alocated to $classes

     my $rparse = shift;
     my $new_class;
     $classes = [ ];
 
     open (INI,"$rparse->{'dir'}"."$rparse->{'file'}") or die "$!: couldn't open ini file";
     flock (INI, 2);
     
     while ($_ = <INI>) {
        chomp($_);
        next if $_ eq ''; # skips blank lines
        if ($_ =~ m/^\[([^\]]+)\]$/) {
            $new_class = $1;
            push (@$classes,$new_class);
            push (@$classes,\%$new_class);
        }
        elsif ($_ =~ m/^([\w\-]+) *= *("?(.+?) *"?)$/) { # laziness wanted
            my $key = $1;
            my $value = $2;
            $value =~ s/^"(.+)"$/$1/; # greediness wanted
            $$new_class{$key} = $value;
        }
     }

     flock (INI, 8);
     close(INI);
     return $classes;
    
}


1;

=head1 NAME

IniParser v.1.0 beta 2 - Simple Ini File Parser and Value Importer

=head1 SYNOPSIS

       use IniParser;

       $this_ini = new IniParser('foobar.ini','');

       $rarray = $this_ini->parse_file();
       $this_ini->import_names($rarray);

       # or, in perl's traditional oneliners:

       $this_ini->import_names(this_ini->parse_file());

=head1 ABSTRACT

This perl library is meant to parse simple ini files for values that you
want to use on your script. I wrote it because I needed to keep simple
info such as directory pathes, URLs, database information outside my perl
scripts so that it would be easier to port it to another system without
having to edit the script file.

IniParser uses a rather fast, object oriented interface. It parses ini files
that should look like this:


     [database_info]

     db = potvall
     user = spiceee
     passwd = candy

     [paths]

     img = http://www.potentialvalleys.com/images/
     flash = http://www.potentialvalleys.com/fx/

IniParse imports hashes to your current namespace with the keys and
values specified in your ini file. So for the above ini file, you
could access the value for the image path like this:

print "$paths{'img'}\n";

The output for this command should be:

http://www.potentialvalleys.com/images/

I should emphasize that you should only keep small but relevant info
in your ini file. This is not a database system whatsoever!

=head1 DESCRIPTION

=head2 PROGRAMMING STYLE

If you create a new IniParser without any argument, such as:

$this_ini = new IniParser();

IniParser will suppose your ini file has the same name of the current
script, only with a .ini extension. For instance, if the file using
IniParser is named foobar.pl, IniParser will look for a foobar.ini
if no filename is passed to it.

With the ini file directory, if not passed to it, IniFile will suppose
the dir is the same dir of the script using IniParser.

=head2 CALLING IniParser.pm ROUTINES

You can set the name of the ini file after initializing the object with
the routine call:

         $this_ini = new IniParser();
         $this_ini->set_file('foobar.ini');

Same works for the directory:

         $this_ini->set_dir('stuff/ini-bin/');

If at any time you need to know what is the working ini file name, use:

         $this_file = $this_ini->which_file();
         # This will return the name of the file.

To tell IniParser to parse your file, use:

         $rarray = $this_ini->parse_file();
 
$rrarray is a hard reference to the array that contains the data
of the parsed file, to tell IniParser to import those data to
your namespace, use:

         $this_ini->import_names($rarray);

It's pretty much it.

=head1 BUGS

The parsing engine is still lacking a definitive reference, mostly because
the ini file lacks some reference too.

Here are some rules:

=item 1.

  if you want your value to start with a relevant space, quote the value:

  Ex:
     
     [foobar]
     foobar = " i really need the space"

     $foobar{'foobar'} points to the value:

     (space)i really need the space.

=item 2.

  if you have opening and closing quotes in the middle of the value,
  IniParser will keep them:

  Ex:

     [foobar]
     script_tag = script language = "JavaScript"

     $foobar{'script_tag'} holds:

     script language = "JavaScript"


     Note that this could be so much clearer if you write it like that:

     [foobar]
     script_language = JavaScript

=item 3.

  Important!! If you use spaces in the "class" name, IniParser will fail
  to import the names of the hashes to your namespace:

  Ex:
 
     [foo bar]
     foobar = foobar

     %foo(space)bar is not a valid variable name in perl!!!!


Please report bugs to perl@potentialvalleys.com

=cut