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

I use a here-doc to format the message body of an email. Within this email I need to print the contents of an array called @output_array. Is this possible?
sub ReportThreshholdExceeded { LogMsg("Running ReportThreshholdExceeded"); my $msg = <<END_OF_BODY; The number of SKUs that have been flagged as DeleteMe is greater than +the threshold of $threshold and thus Manager approval is required. Here is the list of SKUs and their counts: PLANNERCODE\tDEALER\tCOUNT ================================= << THIS IS WHERE I WANT TO PRINT THE ARRAY ELEMENTS>> END_OF_BODY my $address = "ssmith\@xyz.com"; open(MAILER, "| mailx -s \"Manager Approval Required for DeleteMe +flagged SKUs on $instance\" $address") or warn("Couldn't start mailx: $!\n"); print MAILER $msg; # send the mail close(MAILER); LogMsg("Email sent"); }

Replies are listed 'Best First'.
Re: Print array from here-doc
by johngg (Canon) on Apr 25, 2007 at 22:30 UTC
    I'm guessing from your post here and from what look like column headings in your here-doc that you have an array of arrays that you want to make a table from. The following code does that by using sprintf to format each sub-array. The code seems to have a glitch where the second and subsequent lines have the first column pushed one space to the right. I can't see what's causing that at present so I'll show the code as it stands to illustrate the principle.

    use strict; use warnings; my @SKUs = ( [ q{Bumble}, q{Broth}, 16 ], [ q{Wedgie}, q{Benns}, 22 ], [ q{Party}, q{Games}, 6 ], ); local $"; my $msg = <<END_OF_BODY; The number of SKUs that have been flagged as DeleteMe Here is the list of SKUs and their counts: PLANNERCODE\tDEALER\tCOUNT ----------------------------- @{ [ map { sprintf qq{%11s\t%6s\t%5d\n}, @$_ } @SKUs ] } END_OF_BODY print $msg;

    Here's the (slightly flawed) output. If any Monk can see what is causing the misalignment I'd be very interested in finding out.

    The number of SKUs that have been flagged as DeleteMe Here is the list of SKUs and their counts: PLANNERCODE DEALER COUNT ----------------------------- Bumble Broth 16 Wedgie Benns 22 Party Games 6

    I hope I have guessed right and this of use to you.

    Cheers,

    JohnGG

    Update: shigetsu spotted my error, thanks. local $"; line inserted above here-doc to suppress the normal list separator of a space that was throwing things off.

      If you replace
      my $msg = <<END_OF_BODY;
      with
      local $"; my $msg = <<END_OF_BODY;
      it should work as expected.
        Ahhh, of course! Why didn't I think of that?

        Thank you,

        JohnGG

Re: Print array from here-doc
by jZed (Prior) on Apr 25, 2007 at 19:29 UTC
    Did you try it? Something like:
    #!/usr/bin/perl use warnings; use strict; my @x=qw(a b c); print <<EOS; foo @x bar EOS
    # output : foo a b c bar
      I tried that but it prints out as: ARRAY(0x40052a44) ARRAY(0x40052a80) ARRAY(0x40052abc) ARRAY(0x40052af8) ARRAY(0x400f8310)
        One trick to do that is the "babycart operator" @{[]}:
        my $t = "\t"; my $msg = <<"END_OF_BODY"; The number of SKUs that have been flagged as DeleteMe is greater than +the threshold of $threshold and thus Manager approval is required. Here is the list of SKUs and their counts: PLANNERCODE${t}DEALER${t}COUNT ================================= @{[ join("\n", map {join("\t",@$_)} @output_array) ]} END_OF_BODY

        The here-doc construct <<"END_OF_BODY"interpolates as within double quotes. The @{ } thingy dereferences (even between double quotes) an anonymous array, which is - inside that - constructed with [ ] (see perlref). To build that anonymous array, the content must first be expanded - and here's where the magic is: it can be any valid expression which returns a list, up to e.g. a complex do BLOCK statement.

        Note that '\t' is not expanded into a <Tab> in here-docs. You have to stuff that char into a variable first. The ${t} construct serves to disambiguate from e.g. $tCOUNT.

        But generally, when you need to do strange and funny things in here-docs, formats are better, provided you have a somehwat regular data set (i.e. a fixed number of elements in an array). format templates are static, though you could also whip them up on the fly using formline and the accumulator (see perlvar).

        But that, again, also means doing funny things.

        When you reach the limits of formats, use some templating solution.

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
        Then you probably have an array *reference* like $foo, in which case you need to de-reference it in the heredoc with @$foo.
Re: Print array from here-doc
by akho (Hermit) on Apr 25, 2007 at 21:04 UTC
    You will probably want to format your array too (it looks like you want to print a table). Why not use formats?

    upd Sorry, I failed to notice you actually want to get a string, not print it.

    You still should format this array somehow, like add necessary spaces or somesuch.

    my $text = join "\t", @{$array}; my $msg = <<"END"; stuff $text END

    may help.

      Yes, all I want to do is to print the array elements in the message body. Can I do that using formats?
        I've somehow fixed my original reply.