Siaris

Requiring Configuration Data
02 Aug 01 - http://www.siaris.net/index.cgi/Programming/LanguageBits/Perl/20010802.rdoc

Often we write programs that need to use configuration data supplied by the user, but we do not wish the user to have to supply that information on the command line every time they run it. In such circumstances it can be useful to allow the user to store the information somewhere and have the program utilize it on each invocation.

One way to simple way to do this is to have the user put the data after the DATA in the script and have the script read it in:

    #!/usr/bin/perl -w
    use strict;
    my %config = configure();

    foreach my $opt (keys %config) {
        print "$opt : $config{$opt}\n";
    }

    sub configure {
        my %cfg;
        while(<DATA>){
            next if /^\s*#/ or /^\s*$/;
            chomp;
            my($option, $value) = split /\s*=\s*/;
            $cfg{$option} = $value;
        }
        return %cfg;
    }

    __DATA__
    # This is the configuration section. Syntax is:
    # OPTION_NAME = VALUE

    # set user name:
    USER_NAME = nobody

    # set email address
    EMAIL = nobody@nowhere.com

    # debugging level (1,2,3)
    DEBUG = 2

The pitfalls of this approach are twofold: first, only one user of the script may configure it (each user must run their own copy of the program with their own configuration details), and second, we are responsible for parsing the configuration info.

We can get around the second pitfall if we just ask the user to use Perl’s hash syntax and set their configuration info in the hash at the top of the script:

    #!/usr/bin/perl -w
    use strict;
    my %config = (
        # set user name:
        USER_NAME => 'nobody',

        # set email address:
        EMAIL => 'nobody@nowhere.com',

        # set debugging level (1,2,3):
        DEBUG => 2,
    );

However, this is still set within the script and we want to allow for different users of the same program. To do this we use a separate config file for each user (stored in the users home directory with a special name). We can choose to use same form as the DATA example above and write our own parser, or we can specify a format that Perl can understand. One trick for having Perl do the work is to realize that Perl’s require() function (used to load in modules or other chunks of Perl code) has a return value of the last expression evaluated in the file. This means we can use an anonymous hash as our configuration format and have it be the only thing in the file — for example, a config file could look like:

    {
        # set user name:
        USER_NAME => 'nobody',

        # set email address:
        EMAIL => 'nobody@nowhere.com',

        # set debugging level (1,2,3):
        DEBUG => 2,
    }

As far as Perl is concerned, that is an anonymous hash and if this file is stored as ’.config’ in the users HOME directory (where the environment variable $HOME points to), we can simply require() it and grab the return value:

    #!/usr/bin/perl -w
    use strict;
    my $config = require "$ENV{HOME}/.config";
    foreach my $opt (keys %$config) {
        print "$opt : $config->{$opt}\n";
    }

Now each user can have their own config file and we avoid having to parse it by using a format (an anonymous hash) that Perl understands. Utilizing the return value of the require() function can be useful in other situations as well.