views:

236

answers:

5

Hi, this code:

$i=1;
while($i<3) {
    print << "EOT";
    def px$i = new E(user) 
    if (!px$i.hasErrors()) {
            println "${px$i.name} / ${px$i.empr.to} OK"
    }

EOT

    $i++;
}

produces the error:

Can't call method "px" without a package or object reference at borrar.pl line 3.

How can I "escape" the if ?

Thanks.

+6  A: 

It's kind of hard to tell what this code is supposed to accomplish, but maybe you want the outer dollar signs in the println statement to be preserved in the final output?

println "\${px$i.name} / \${px$i.empr.to} OK"

With that change, the error-free output I see is:

def px1 = new E(user) 
if (!px1.hasErrors()) {
        println "${px1.name} / ${px1.empr.to} OK"
}

def px2 = new E(user) 
if (!px2.hasErrors()) {
        println "${px2.name} / ${px2.empr.to} OK"
}
Sean
The code is part of a bigger script that loads a cvs and creates groovy classes from its data. The question is Why the perl compiler is trying to compile the block inside the print/EOT and how to tell it not to.(BTW, thanks for the recommendation but it didn't work)
xain
@xain: What do you mean exactly by "it didn't work"? Show the exact output you expect to get. How does it differ from Sean's output?
toolic
Sean, my mistake. It worked just fine. Thanks!
xain
+1  A: 

This should fix the problem.

println "${"px$i.name"} / ${"px$i.empr.to"} OK"
println "px$i.name" / px$i.empr.to OK"
Brad Gilbert
+1  A: 

As you have seen, the $px part of the string is getting evaluated. You simply need to escape it:

$i=1;
while($i<3) {
    print << "EOT";
    def px$i = new E(user) 
    if (!px$i.hasErrors()) {
            println "\${px$i.name} / \${px$i.empr.to} OK"
    }

EOT

    $i++;
}

Read more about string escaping at perldoc perlop under "Gory details of parsing quoted constructs".

Ether
+4  A: 

The command line option -MO=Deparse shows you how Perl has interpreted your code after simplifying it (e.g. converting heredocs to qq{} blocks). e.g.

$ perl -MO=Deparse test.pl
$i = 1;
while ($i < 3) {
    print qq[    def px$i = new E(user) \n    if (!px$i.hasErrors()) {\n            println "${$i->px . 'name';} / ${$i->px . 'empr' . 'to';} OK"\n    }\n\n];
    ++$i;
}

The relevant part is:

println "${$i->px . 'name';} / ${$i->px . 'empr' . 'to';}

Perl has converted ${px$i.name} to ${$i->px . 'name'} !

In perl, ${...} means to evaluate whatever is inside the block, and treat it as a symbolic reference (i.e. a variable name) or a scalar reference, then dereference it to turn it back into a scalar. So Perl tries to execute whatever is inside those blocks, treating their contents as Perl code. This is because your heredoc, "EOT" is like a double-quoted string, and interpolates dollar signs.

Solution is: escape your dollar signs ($ -> \$) or use single quotes and concatenation rather than heredocs.

rjh
+1  A: 
my $format = << 'EOT';
def px%d = new E(user)
    if (!px%d.hasErrors()) {
            println "${px%d.name} / ${px%d.empr.to} OK"
    }
EOT

for my $i ( 1 .. 3 ) {
    printf $format, ($i) x 4;
}
Sinan Ünür
(+1) there are multiple kinds of heredocs single-quotes are non-interpolated. another type is backticks, e.g. `EOT` which would execute the string via shell.
harschware