Beefy Boxes and Bandwidth Generously Provided by pair Networks RobOMonk
No such thing as a small change
 
PerlMonks  

Unexpected results when removing a HERE-DOC "ending" newline, with map and/or s/// depending on context.

by olivierp (Hermit)
on Dec 09, 2004 at 01:32 UTC ( #413397=perlquestion: print w/ replies, xml ) Need Help??
olivierp has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks,
While searching for a way to remove the "last" newline in a here-doc, i.e. the one ahead of the end tag, I stumbled across behaviour(s) I do not understand, for which I seek enlightenment
I am probably missing something obvious...
Consider these snippets: (the complete script is at the end of the post)
(my $var1 = <<EOT) =~ s/\r?\n/(munched)/g; First line of "var1" Second line of "var1" has a newline here -> EOT (my $var2 = <<EOT) =~ s/\r?\n\Z/(munched)/; First line of "var2" Second line of "var2" had a newline here -> EOT
Nothing unexpected here. The first replaces every newline, not what I want, and the second is part of what I need.

Now something strange:Fixed following fglock's and Errto's comments.
# Was building $var3 in scalar instead of list context # my $var3 = map { s/\r?\n\Z/(munched)/; $_ } <<EOT; my ($var3) = map { s/\r?\n\Z/(munched)/; $_ } <<EOT; Var also has an interpolated var: $interpolated And the last newline is also absent -> EOT
var3 now contains the "count" of substitutions. I don't understand why,
If I change the above to a here-doc with no interpolated var(s), as here:
my $var4; # This generates "Modification of a read-only value attempted at"; eval { # Still dies, even when in list context. # $var4 = map { s/\r?\n\Z/(munched)/; $_ } <<EOT ($var4) = map { s/\r?\n\Z/(munched)/; $_ } <<EOT var4 has _NO_ interpolated var, and will generate a runtime error EOT }; if ($@){ ($var4 = $@) =~ s/\r?\n\Z//; $@ = undef; print map {s/\r?\n\Z//;$_ }(${^__} =<<EOT); The error generated by \$var4 = map { s/\\r?\\n\\Z/(munched)/; \$_ } <<EOT; is: $var4 EOT }
I get Modification of a read-only value attempted at... Why is $var4's here-doc considered read-only, when the only difference with $var3's is the $interpolated item ?

While I could do with my working snippet, I actually want to do this while creating a HoH. And this is where I stumble again on things I cannot grasp:
# map{}' on the last key is ok. my $href = { key1 => { subkey1 => "Defined first is OK", subkey2 => map{s/\r?\n\Z/(munched)/;$_} (${^__}=<<EOT), First line in sub key. Second line. The third contains an interpolated value, and all is OK. Line 3 $interpolated and no newline here -> EOT }, }; # This explodes... # map{}' ing, then defining another key leads to a runtime error. eval { $href->{key2} = { subkey1 => map{s/\r?\n\Z/(munched)/;$_} ($ {^__}=<<EOT), First line in sub key. Second line. The third contains an interpolated value, and all is OK. Line 3 $var3 and no newline here -> EOT subkey2 => "Kaboom !", }; }; if ($@) { ($href->{key2}->{subkey1} = $@) =~ s/\r?\n\Z//; $href->{key2}->{subkey2} = "Set after eval"; $@ = undef; }
Why is it that using map during the definition of the first key is OK, and if used in another key definition blows up ?
In both cases I do have an interpolated value, and I think that ${^__} is not a read-only value.

Now, let's try with something "cleaner" than map:
# This doesn't die, but gives the count of matches... $href->{key3} = { subkey1 => "Hello", subkey2 => ($ {^__} =<<EOT) =~ s/\r?\n\Z/(munched)/, This works fine, and also strips my ending newline -> EOT subkey3 => "No explosion here...but the count of matches", };
Here again, I get a count of substitutions, and do not understand why.
And finally the las thing I tried, that does what I want:
$href->{key4} = { subkey1 => "Hello", subkey2 => eval { ($ {^__} =<<EOT) =~ s/\r?\n\Z/(munched)/; This works fine, and also strips my ending newline -> EOT return $ {^__}; }, subkey3 => "No explosion here...", };
Would someone kindly explain what I am messing up ?
Update:
To answer why I would map or s/// a here-doc, I am dealing with window's WMI Query language, which does not appreciate having a newline in certain places of its queries. In particular, the condition in a WHERE clause:
WHERE Path='something' is OK.
WHERe Path='
something'
is not.
Complete script here:
use strict; use warnings; my $interpolated = "I was interpolated"; # This strips _every_ newline (my $var1 = <<EOT) =~ s/\r?\n/(munched)/g; First line of "var1" Second line of "var1" has a newline here -> EOT #This only strips the "ending" newline (my $var2 = <<EOT) =~ s/\r?\n\Z/(munched)/; First line of "var2" Second line of "var2" had a newline here -> EOT # This will return the number of substitutions # Fixed. Was building $var3 in scalar instead of list context. #my $var3 = map { s/\r?\n\Z/(munched)/; $_ } <<EOT; my ($var3) = map { s/\r?\n\Z/(munched)/; $_ } <<EOT; Var also has an interpolated var: $interpolated And the last newline is also absent -> EOT my $var4; # This generates "Modification of a read-only value attempted at"; eval { # Still dies, even if called in list context. # $var4 = map { s/\r?\n\Z/(munched)/; $_ } <<EOT; ($var4) = map { s/\r?\n\Z/(munched)/; $_ } <<EOT; var4 also has _NO_ interpolated var, and will generate a runtime error EOT }; if ($@){ ($var4 = $@) =~ s/\r?\n\Z//; $@ = undef; print map {s/\r?\n\Z//;$_ }(${^__} =<<EOT); The error generated by \$var4 = map { s/\\r?\\n\\Z/(munched)/; \$_ } <<EOT; is: $var4 EOT } # map{}' on the last key is ok. my $href = { key1 => { subkey1 => "Defined first is OK", subkey2 => map{s/\r?\n\Z/(munched)/;$_} (${^__}=<<EOT), First line in sub key. Second line. The third contains an interpolated value, and all is OK. Line 3 $interpolated and no newline here -> EOT }, }; # This explodes... # map{}' ing, then defining another key leads to a runtime error. eval { $href->{key2} = { subkey1 => map{s/\r?\n\Z/(munched)/;$_} ($ {^__}=<<EOT), First line in sub key. Second line. The third contains an interpolated value, and all is OK. Line 3 $var3 and no newline here -> EOT subkey2 => "Kaboom !", }; }; if ($@) { ($href->{key2}->{subkey1} = $@) =~ s/\r?\n\Z//; $href->{key2}->{subkey2} = "Set after eval"; $@ = undef; } # This doesn't die, but gives the count of matches... $href->{key3} = { subkey1 => "Hello", subkey2 => ($ {^__} =<<EOT) =~ s/\r?\n\Z/(munched)/, This works fine, and also strips my ending newline -> EOT subkey3 => "No explosion here...but the count of matches abov +e", }; $href->{key4} = { subkey1 => "Hello", subkey2 => eval { ($ {^__} =<<EOT) =~ s/\r?\n\Z/(munched)/; This works fine, and also strips my ending newline -> EOT return $ {^__}; }, subkey3 => "No explosion here...", }; print map {s/\r?\n\Z//; $_} <<EOF; var1 : <$var1> ------ var2 : <$var2> ------ var3 : <$var3> ------ var4 : <$var4> ------ From the hash refs: key1->subkey1 <$href->{key1}->{subkey1}> key1->subkey2 <$href->{key1}->{subkey2}> ------ key2->subkey1 <$href->{key2}->{subkey1}> key2->subkey2 <$href->{key2}->{subkey2}> ------ key3->subkey1 <$href->{key3}->{subkey1}> key3->subkey2 <$href->{key3}->{subkey2}> key3->subkey3 <$href->{key3}->{subkey3}> ----- key4->subkey1 <$href->{key4}->{subkey1}> key4->subkey2 <$href->{key4}->{subkey2}> key4->subkey3 <$href->{key4}->{subkey3}> EOF

--
Olivier

Comment on Unexpected results when removing a HERE-DOC "ending" newline, with map and/or s/// depending on context.
Select or Download Code
Re: Unexpected results when removing a HERE-DOC "ending" newline, with map and/or s/// depending on context.
by fglock (Vicar) on Dec 09, 2004 at 02:19 UTC

    map() normally returns a list. However, if the result is being assigned to a scalar, it returns a count. See perldoc -f map

Re: Unexpected results when removing a HERE-DOC "ending" newline, with map and/or s/// depending on context.
by Errto (Vicar) on Dec 09, 2004 at 03:50 UTC

    Couple of comments here:

    1. I admit that the discrepancy between what happens with $var3 and $var4 is bizarre. I can't figure out why one is allowed and one isn't.
    2. On the other hand, a here doc is kind of like a string literal. You're effectively trying to modify a string literal without assigning it to a variable first. This is dangerous even if it does sometimes work.
    3. Why are you applying map to a single string? map is meant to work on lists, and a here doc is only a single string, that is a scalar, that is a list of length one. Just assign it to a variable and then use s///. You've already shown how to do that in a single line of code (i.e. (my $foo = <<EOT) =~ s/foo/bar/).
    4. Update: You say in your comments that map returns the number of substitutions. That's not true. That's what s/// returns in scalar context. map in scalar context returns a count of the elements in the list, which in your case is always 1.
      Doh !
      Thanks to fglock and Errto for pointing out the obivous.
      This at least "fixes" my $var3:
      my ($var3) = map { s/\r?\n\Z/(munched)/; $_ } <<EOT; Var also has an interpolated var: $interpolated And the last newline is also absent -> EOT
      However, $var4 still explodes on a read-only value, and I still haven't found, apart from eval'ing the whole thing, how to do the same for $href->{key3} = {...

      --
      Olivier

        Very interesting - that's because an interpolated string is actually an unnamed variable, while a simple string is just a constant.

Re: Unexpected results when removing a HERE-DOC "ending" newline, with map and/or s/// depending on context. (qq++)
by tye (Cardinal) on Dec 09, 2004 at 17:11 UTC

    But here-docs are so ugly for so many reasons. Not being able to omit the final newline is just one. They also aren't very flexible at interpolating in the middle. They break if you reindent code. Worst of all, they break in the face of invisible whitespace (trailing whitespace is not even indirectly visible in most environments).

    Use qq<>.

    - tye        

      Thanks. I forgot most of the q.// operators.
      I'll see if I can get some "strange" behaviour out of it :)

      --
      Olivier

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://413397]
Approved by davido
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (8)
As of 2014-04-20 18:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (486 votes), past polls