SPUG: use strict and do files.

Doug Beaver dougb at scalar.org
Fri Jul 30 03:21:55 CDT 1999


On Thu, Jul 29, 1999 at 07:34:33PM -0700, charles.e.derykus at boeing.com wrote:
> 
> > I was looking for a cheap rc type file behavior.  I thought I could
> > just use a "do" file with variables in it - but I wanted "use
> > strict" to be enforced. The perlfunc man page says:
> >    do 'stat.pl';
> >      is just like
> >    scalar eval `cat stat.pl`;
> 
> > This doesn't appear to be true.  This is on win98 so s/cat/type/ but
> > "type" is expensive as far as run time.  Is there a way to force a
> > "use strict" on do files?
> 
> Stu,
> 
> 
> I noticed now that Tom Christiansen has amended the docs
> slightly to say:
> 
> do $file is like eval `cat $file`, except the former:
> 
>   1.1  searchs @INC and updates @INC
>   1.2  bequeaths an unrelated "lexical" scope on the eval'ed code
> 
> (See:  http://x32.deja.com/[ST_rn=ps]/getdoc.xp?AN=503977526&CONTEXT=933300222.1535180873&hitnum=1)
> 
> That's rather confusing though and doesn't account for instance
> why 'use constant' is visible whereas 'use strict' pragma isn't 
> in the case below:
> 
>      package main;
>      ...
>      package doit:
>      use strict;              # doesn't propagate to 'do file'  
>      use constant CONS => 3   # does       "       "    "
> 
>      package main;
>     
>      package doit;
>      do "doit.pl";
> 
> 
>     #--------------------------
>     # doit.pl
>       $whoops = "toss_an_error";
>       print "CONS = ", CONS, "\n";  # prints CONS = 3
> 
> 
> So, you'll probably have to insert a 'use strict' in doit.pl
> unless I'm missing something.
 
The funny thing is, if you add C<use strict> to doit.pl, then you have
to declare the variables as either globals (with C<use vars> or by
stating the package name explicitly) or make them lexical.

C<do 'doit.pl'> is supposed to be like C<scalar eval `cat doit.pl`>, and
because lexicals lose their scope outside of an eval (search perlsub for
'eval' for more info), any lexical variables that are declared in
doit.pl will not be visible after the do(), so it really doesn't make
sense to use strict in doit.pl.

(Try declaring $whoops with a my in doit.pl and see if you can see it
after the do() happens.  You can only see the variables that were
globals.)

You can still use do() to implement a quick and useful rc system though:

-------
doit.pl
-------
$LOGGING_DAEMON_CONFIG = {
    logdir => '/var/log',
    proclimit => 32,
    valid_domains => [qw/ibm.com sun.com hp.com/],
};
--snip--

#!/usr/bin/perl

$rc = do 'doit.pl';

print "Logging directory is: ", $rc->{'logdir'}, "\n";
print "Max num of processes: ", $rc->{'proclimit'}, "\n";

$domains = $rc->{'valid_domains'};
for (@$domains) {
    print "Allow connection from $_\n";
}
__END__

Since do() returns the value of the last evaluated expression in the
file it was called with, you can store the data structure inside a
variable in doit.pl and then assign it to $rc using do().

I like it because you can check the syntax of your rc file with perl -c,
and you can use perl syntax to create the different elements of the data
structure (no new special syntax to learn in order to start adding items
to your rc file).

This also works with Data::Dumper because it's output is very similar to
the example doit.pl above (in fact, I got the idea for implementing rc
files this way after fiddling around with some dumps I made with
Data::Dumper).

That also makes it really easy to have your software create the rc file
based on questions they ask the user, because all you have to do is
add their responses to a data structure and then use Data::Dumper to
dump it to a rc file.

#!/usr/bin/perl

use Data::Dumper;

$prefs = {};
$prefs->{'logdir'} = prompt("Where do you keep your logs: ");
$prefs->{'proclimit'} = prompt("How many processes to run at once: ");
while ($domain = prompt("Enter a domain to allow connections from: ")) {
    push @{ $prefs->{'valid_domains'} }, $domain;
}

open(RC, ">rc.pl") || die "Can't write rc.pl: $!";
print RC Dumper($prefs);
close RC;

sub prompt {
    my ($question) = @_;
    print $question;
    chomp($answer = <STDIN>);
    return $answer;
}
__END__

Use rc.pl instead of doit.pl in the first program and it will print the
new values you entered.

Only bad thing is that Data::Dumper dumps in a certain format, but it
has variables that let you tweak it's output so that you can probably
make it closely resemble the format you use in your rc files.  (Look at
some Data::Dumper output to see what I mean.)

Sorry this ended up being such a long email, but I thought Stu and
others might see this and get an idea or two from it.  Perhaps I
misunderstood why he wanted to use strict, but it seemed to me that he
wanted it for the wrong reason, and I figured I would share this method
just in case nobody knew about it.

HTH,

Doug

p.s.  I used C<> for some of the code snippets because I puked the first
time I typed 'do 'doit.pl''.  ;-)

p.p.s.  The variable that you use in the rc file is meaningless, it's
just a place to store the data structure.  I usually name it
descriptively so that you can glance at the top of the rc file and see
what program it's for.  Data::Dumper will let you set the variable name
by setting $Data::Dumper::Varname, so you can name the generated rc
file's variable descriptively too...

-- 
  Ned: So recycling is our way of giving Mother Earth a great big hug!
Burns: Yes, well, it does sound like fun.  I can't wait to start pawing
       through my trash like some starving racoon!
       [To Smithers] Release the hounds!

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    POST TO: spug-list at pm.org        PROBLEMS: owner-spug-list at pm.org
 Seattle Perl Users Group (SPUG) Home Page: http://www.halcyon.com/spug/
 SUBSCRIBE/UNSUBSCRIBE: Replace ACTION below by subscribe or unsubscribe
        Email to majordomo at pm.org: ACTION spug-list your_address





More information about the spug-list mailing list