Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Heredoc in one-liner?

by loris (Hermit)
on Nov 27, 2013 at 15:09 UTC ( [id://1064633]=perlquestion: print w/replies, xml ) Need Help??

loris has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

Wanting to use a heredoc in a one-liner is obviously a bit daft, but here's my problem:

I'm trying to create a hash of text blocks to autogenerate mail texts in multiple languages. For this I have something like:

my %text_blocks; $text_blocks{en}{prolog} =<<'PROLOG'; You have received this email because something happened. Please send feedback and suggestions to tldr@nohelp.org. PROLOG

This works in a script, but when I run the tests for my module I get:

# Error: syntax error at Automailer.pm line 32, near "tldr@nohelp +" # Global symbol "@nohelp" requires explicit package name at Automailer +.pm line 32.

To see whether the heredoc with an "@" behaves differently in a script and a module, I wanted to try something goofy like:

perl -e 'package test;$text <<'TEST';test@heredoc;\r\nTEST;print "$tex +t\n"'

The carriage return and newline obviously don't get interpolated, but I hope you get the idea. Is this at all possible, or is the only way to just write a minimal module?

Thanks,

loris

Replies are listed 'Best First'.
Re: Heredoc in one-liner?
by MidLifeXis (Monsignor) on Nov 27, 2013 at 15:29 UTC

    The quotes around 'TEST' are matching the quotes around the one liner. The shell is passing

    package test;$text <<TEST;test@heredoc;\r\nTEST;print "$text\n"
    to perl. The contents of the heredoc are then being interpolated. There are also some funky dealing with the multi-line stuff you will need to work through.

    (Update) Perhaps:

    perl -e 'package test;$text=q(test@heredoc);print "$text\n"'

    --MidLifeXis

Re: Heredoc in one-liner?
by johngg (Canon) on Nov 27, 2013 at 15:34 UTC

    Escaping the @ might let you get further and a one-liner can span more than one line :-)

    $ perl -Mstrict -Mwarnings -E ' my $text = <<'EOT'; some text fred\@bloggs.com EOT say $text;' some text fred@bloggs.com $

    I hope this is helpful.

    Cheers,

    JohnGG

Re: Heredoc in one-liner?
by kcott (Archbishop) on Nov 28, 2013 at 03:27 UTC

    G'day loris,

    The reason you're getting that error is because the heredoc (in your module) is being interpolated.

    In your module, you've probably either coded <<"PROLOG" or <<PROLOG.

    See perlop: Quote-Like Operators for an explanation of how explicit single- and double-quoted terminating strings (i.e. PROLOG in your example) are interpolated; also note that the absence of explicit quotes assumes double-quotes.

    There are a variety of hoops you have to jump through to get similar code working in a one-liner. These have mostly been pointed out in various replies. You could embed newlines in your one-liner and do something like this:

    $ perl -Mstrict -Mwarnings -e 'package test; my $text = <<\TEST; test@heredoc TEST print $text' test@heredoc

    That's not using the module as such; just running the code in a package other than main. You're also using a different (albeit equivalent) method of quoting the terminator (i.e. <<\TEST). What you'd really want is something closer to this:

    $ perl -Mstrict -Mwarnings -e 'package test; my $text = <<\TEST; test@heredoc TEST sub test_print { print $text } package main; use parent -norequire => "test"; test::test_print()' test@heredoc

    That's a lot of effort; it's not really comparing apples with apples; and, given you could have copied most of the code you already had, probably takes a similar amount of time as coding this test script:

    #!/usr/bin/env perl use strict; use warnings; use pm_example_module; pm_example_module::test_print();

    and this test module:

    package pm_example_module; use strict; use warnings; my %text_blocks; $text_blocks{en}{prolog} =<<'PROLOG'; You have received this email because something happened. Please send feedback and suggestions to tldr@nohelp.org. PROLOG sub test_print { print $text_blocks{en}{prolog}; } 1;

    Running that script produces:

    You have received this email because something happened. Please send feedback and suggestions to tldr@nohelp.org.

    Changing <<'PROLOG' to either <<"PROLOG" or <<PROLOG, produces (in both cases):

    Possible unintended interpolation of @nohelp in string at pm_example_m +odule.pm line 8. Global symbol "@nohelp" requires explicit package name at pm_example_m +odule.pm line 8. Compilation failed in require at ./pm_example.pl line 6. BEGIN failed--compilation aborted at ./pm_example.pl line 6.

    You now have a valid test which reproduces what you were attempting to test and, I suspect, would have taken less time than writing and posting your OP.

    -- Ken

      Hi,

      Thanks to everyone for all the help. The problem was that I had

      $text_blocks{en}{prolog} <<'PROLOG';

      instead of

      $text_blocks{en}{prolog} = <<'PROLOG';

      in my first heredoc. Subsequent heredocs were OK, so I somehow missed it. D'oh!

      Of course the point about the time spent writing and posting is correct. However, thanks to the your answer I now realise that I didn't need a one-liner to actually be on one line, but could simply embed the newlines.

      Cheers,

      loris

Re: Heredoc in one-liner?
by taint (Chaplain) on Nov 27, 2013 at 15:28 UTC

    What does your test involve/include? Other (mail related) Modules?

    Reason I ask, is that mail headers use < and >. As memory serves, the relevant RFC probably mentions this. Point being; that unless Perl has processed your text prior to mail related Modules, or the SMTP(d) itself. This might be the problem.

    Mind you, I'm going by memory on the RFC, and I don't know your test method.

    The following may be pertinent RFC 6531, RFC 6152, (RFC 5248 interesting, but probably not relevant), RFC 2852

    Just a thought

    --Chris

    #!/usr/bin/perl -Tw
    use Perl::Always or die;
    my $perl_version = (5.12.5);
    print $perl_version;
Re: Heredoc in one-liner?
by taint (Chaplain) on Nov 27, 2013 at 15:49 UTC

    Given that you mentioned "several languages", I'll assume UTF-8. so joe@example.com (joe &#64; example.com) should also do the trick.

    --Chris

    #!/usr/bin/perl -Tw
    use Perl::Always or die;
    my $perl_version = (5.12.5);
    print $perl_version;
Re: Heredoc in one-liner?
by taint (Chaplain) on Nov 27, 2013 at 15:55 UTC
    Does quotemeta work for you?

    --Chris

    #!/usr/bin/perl -Tw
    use Perl::Always or die;
    my $perl_version = (5.12.5);
    print $perl_version;

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (6)
As of 2024-04-18 13:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found