Perl Cd Bookshelf [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Perl Cd Bookshelf [Electronic resources] - نسخه متنی

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید

8.16. Reading Configuration Files


8.16.1. Problem




You want to allow users of your
program to change its behavior through configuration files.

8.16.2. Solution


Either process a file in trivial VAR=VALUE format, setting a hash
key-value pair for each setting:

while (<CONFIG>) {
chomp; # no newline
s/#.*//; # no comments
s/^\s+//; # no leading white
s/\s+$//; # no trailing white
next unless length; # anything left?
my ($var, $value) = split(/\s*=\s*/, $_, 2);
$User_Preferences{$var} = $value;
}

or better yet, treat the config file as full Perl code:

do "$ENV{HOME}/.progrc";

8.16.3. Discussion


The first solution lets you read config files in a trivial format
like this (comments and empty lines are allowed):

# set class C net
NETMASK = 255.255.255.0
MTU = 296
DEVICE = cua1
RATE = 115200
MODE = adaptive

After you''re done, you can pull in a setting by using something like
$User_Preferences{"RATE"} to find the value
115200. If you wanted the config file to set the global variable by
that name, instead of assigning to the hash, use this:

no strict "refs";
$$var = $value;

and the $RATE variable would contain 115200.

The second solution uses
do to pull in raw Perl code directly. When used
with an expression instead of a block, do
interprets the expression as a filename. This is nearly identical to
using require, but without risk of taking a fatal
exception. In the second format, the config file would look like:

# set class C net
$NETMASK = "255.255.255.0";
$MTU = 0x128;
# Brent, please turn on the modem
$DEVICE = "cua1";
$RATE = 115_200;
$MODE = "adaptive";

If you don''t see the point of having extra punctuation and live code,
consider this: you can have all of Perl at your disposal. You can now
add arbitrary logic and tests to your simple assignments:

if ($DEVICE =~ /1$/) {
$RATE = 28_800;
} else {
$RATE = 115_200;
}

Many programs support system and personal configuration files. If you
want the user''s choices to override the system ones, load the user
file second:

$APPDFLT = "/usr/local/share/myprog";
do "$APPDFLT/sysconfig.pl";
do "$ENV{HOME}/.myprogrc";

If you want to ignore the system config file when the user has his
own, test the return value of the do.

do "$APPDFLT/sysconfig.pl"
or
do "$ENV{HOME}/.myprogrc";

You might wonder what package those files are compiled in. They will
be in the same package that do itself was compiled
into. Typically you''ll direct users to set particular variables,
which, being unqualified globals, will end up in the current package.
If you''d prefer unqualified variables go into a particular package,
do this:

{ package Settings; do "$ENV{HOME}/.myprogrc" }

As with a file read using require or
use, those read using do count
as a separate and unrelated lexical scope. That means the
configuration file can''t access its caller''s lexical
(my) variables, nor can the caller find any such
variables that might have been set in the file. It also means that
the user''s code isn''t held accountable to a lexically scoped pragma
like use strict or
use warnings, which may be in
effect in the caller.

If you don''t want clean partitioning of variable visibility, you can
get the config file''s code executed in your own lexical scope. If you
have a cat program or its technical equivalent
handy, you could write yourself a hand-rolled do:

eval `cat $ENV{HOME}/.myprogrc`;

We''ve never actually seen anyone (except Larry Wall himself) use that
approach in production code.

For one thing, do is a lot easier to type. Also,
it respects the @INC path, which is normally
searched if a full path is not specified, but, unlike using a
require, no implicit error checking happens under
do. This means you don''t have to wrap it in an
eval to catch exceptions that would otherwise
cause your program to die, because do already
functions as an eval.

You can still check for errors on your own if you''d like:

$file = "someprog.pl";
unless ($return = do $file) {
warn "couldn''t parse $file: $@" if $@;
warn "couldn''t do $file: $!" unless defined $return;
warn "couldn''t run $file" unless $return;
}

This is much simpler for the programmer to source in code than it
would be to invent and then parse a complicated, new syntax. It''s
also much easier on the users than forcing them to learn the syntax
rules of yet another configuration file. Even better, you give the
user access to a powerful algorithmic programming language.

One reasonable concern is security. How do you know that the file
hasn''t been tampered with by someone other than the user? The
traditional approach here is to do nothing, trusting the directory
and file permissions. Nine times out of ten, this is also the right
approach. Most projects just aren''t worth being that paranoid over.
For those that are, see the next recipe.

8.16.4. See Also


The eval and require functions
in perlfunc(1) and in Chapter 29 of
Programming Perl; Recipe 8.17

/ 875