Stumped by eval and scoping problem

S

shanx

I am not a perl newbie, but I am really stumped by this eval problem.
I cannot change a lot of the existing code since it is legacy stuff, so
any solution to redo this in a totally different manner won't work for
me.

The Problem:

A perl program called bug_find includes a test-suite library called
foo.pl using 'do'. bug_find has 'use strict' declaration and it passes
a perl -c, (we're using perl 5.6), but foo.pl doesn't have a 'use
strict' declaration. The relevant parts of the code from both files are
shown below:

####bug_find####
...
sub run_test {
my ($ref) = @_;

my $command = $ref->{cmd};
local $results = {};

open(FH, "$command 2>&1 |") or die $!;

my @output = <FH>;
$results->{output} = @output;

if (exists($ref->{post}) and defined($ref->{post}) {
eval $ref->{post};
}

return $results;
}

...

# What follows is main part of bug_find.
{
do $suite; # let us say $suite is foo.pl

foreach $i (@tests) {
$result = run_test($i);
}
}

####end of bug_find####


####start of foo.pl (or whatever $suite is)####


@specific_tests = (
{
'cmd' => "cleartool $blah $blah", # This is some shell
command
'post' => "$gotit = $1 if ($results->{output} =~ m/success
(\w+)/); print \"Value of gotit is $gotit\n\"",
},
{
'cmd' => 'cd /var/tmp/$gotit; ./do_something.sh',
}
);

@tests = (@specific_tests);

###end of foo.pl####

Note that the variable @tests in foo.pl is being used by bug_find after
'do'.

My problem is that when I run bug_find, I see the correct value of
$gotit in the print statement but when I try to read the value of
$gotit (just before do_something.sh), the variable seems to be unset
and it is empty.

What is going on?

-Shanker
 
S

shanx

Let me correct a little typo.
...
{
'cmd' => "cd /var/tmp/$gotit; ./do_something.sh",
}
...
The hash value is within double quotes, not single quotes.
 
B

Bob Walton

shanx said:
I am not a perl newbie, but I am really stumped by this eval problem.
I cannot change a lot of the existing code since it is legacy stuff, so
----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Huh? Why not? It's Perl code and you've got the source. And
besides, that stuff can't be legacy code -- there's no way it
could ever have worked. See below.
any solution to redo this in a totally different manner won't work for
me.

The Problem:

A perl program called bug_find includes a test-suite library called
foo.pl using 'do'. bug_find has 'use strict' declaration and it passes
a perl -c, (we're using perl 5.6), but foo.pl doesn't have a 'use
strict' declaration. The relevant parts of the code from both files are
shown below:

####bug_find####
..

Some comments below...
sub run_test {
my ($ref) = @_;

my $command = $ref->{cmd};
local $results = {};

open(FH, "$command 2>&1 |") or die $!;

my @output = <FH>;
$results->{output} = @output;
In the above statement, the left-hand-side is a scalar lvalue;
hence, the thing that will get store will be the number of
elements in array @output. Is that what you want? I doubt it
since you are trying to match against a string that is
non-numeric later on (starting with 'success').
if (exists($ref->{post}) and defined($ref->{post}) {
eval $ref->{post};
You should test the results of eval to see if the eval compiled
and ran. The results of that test should be quite revealing, as
would printing what you are about to eval just before you eval
it. Or running it in the debugger. Did you try that??
}

return $results;
}

..

# What follows is main part of bug_find.
{
do $suite; # let us say $suite is foo.pl

foreach $i (@tests) {
$result = run_test($i);
}
}

####end of bug_find####


####start of foo.pl (or whatever $suite is)####


@specific_tests = (
{
'cmd' => "cleartool $blah $blah", # This is some shell
command
'post' => "$gotit = $1 if ($results->{output} =~ m/success
(\w+)/); print \"Value of gotit is $gotit\n\"",
When the above statement is executed by Perl, the values of
$gotit, $1 and $results->{output} are all interpolated into the
double-quoted string, which is then stored in
$specifictests[0]->{post}. The code you give doesn't clue us in
to what is in those variables, but note that if $gotit contained
'foo', $1 contained 'bar', and $results->{output} contained
'baz', then @specifictests[0]->{post} will contain:

foo = bar if(baz =~m/success
(\w+)/); print "Value of gotit is foo
"

Since that isn't legal Perl, the eval back in your other code
will fail. But you didn't test for that. And this makes me
amazed at your statement below that the print statement revealed
a correct value for $gotit, since the print never even compiled.
Or perhaps $gotit etc actually contained value which, when
interpolated into the string, made up something the Perl could
compile and execute? It seems very unlikely that $1 would
contain such a value at that point.
},
{
'cmd' => 'cd /var/tmp/$gotit; ./do_something.sh',
You mention in a followup note that the ' above are actually ",
so $gotit is substituted at the time @specifictests[1] is
defined. That probably isn't what you wanted -- you probably
*do* want the apostrophe string so the $gotit is preserved until
eval time. Use the debugger to see what you actually have in
your data structures at various times during execution.

And, BTW, if you're retyping your code (otherwise how would you
have made that "mistake"?), *don't* *do* *that*. Copy/paste
tested code into your posts so we don't have fight typos. Read
the posting guidelines.
}
);

@tests = (@specific_tests);

###end of foo.pl####

Note that the variable @tests in foo.pl is being used by bug_find after
'do'.

My problem is that when I run bug_find, I see the correct value of
------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^
I doubt it. The print statement would never have even compiled.
Can you post concice but complete code that anyone can
copy/paste/execute which demonstrates this (per the posting
guidelines, BTW), please?
$gotit in the print statement but when I try to read the value of
$gotit (just before do_something.sh), the variable seems to be unset
and it is empty.

What is going on?

Run your code in the debugger (perl -d filename.pl) and see for
yourself.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top