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

Hello:

I wrote a subroutine to format three string variables. The subroutine is:
sub format_email_text { my $str; my $str1; my $str2; $str=sprintf("%-30s %-50s","Player Name:",$player); $str1=sprintf("%-30s %-50s","Parent's Name:",$parent); $str2=sprintf("%-30s %-50s","Member ID:",$memberid); return ($str); return ($str1); return ($str2); }
I then call this subroutine in another subroutine which sends an email. The email subroutine looks like:
sub send_confirmation_email { my $text = format_email_text (); my %mail = ( From => "info\@somewhere.com", To => $email, Subject => "Some Subject", Message => "" ); my $page; $mail{Message} = <<EOF; This is the information you submitted. $text EOF sendmail (%mail) or $page .= p (escapeHTML ("Oops, failure sending mail to $mai +l{To}")); return (defined ($page) ? $page : ""); }
When I run the script, I should receive an email showing all three variables instead the email only shows the first variable. Can someone tell me what I'm doing wrong?

Thank you.

Replies are listed 'Best First'.
Re: Format text problem
by thekestrel (Friar) on Apr 02, 2005 at 20:08 UTC
    Hi,
    Once you hit a return statement in a subroutine it never returns back again so everything after the first return is ignored. It never actually gets to the 2nd and 3rd return statements. Try returning an array that contains the Player Name, Parents Name and Member ID.
    Try something like
    sub format_email_text { my @arr; $arr[0]=sprintf("%-30s %-50s","Player Name:",$player); $arr[1]=sprintf("%-30s %-50s","Parent's Name:",$parent); $arr[2]=sprintf("%-30s %-50s","Member ID:",$memberid); return (@arr); } my @vals = format_email_text(); print "Player Name : " . $vals[0] . "\n"; print "Parent Name : " . $vals[1] . "\n"; print "Member ID : " . $vals[2] . "\n";


    Regards Paul

      True, but why not do this:

      sub format_email_text { return join("\n", sprintf("%-30s %-50s", "Player Name:", $player), sprintf("%-30s %-50s", "Parent's Name:", $parent), sprintf("%-30s %-50s", "Member ID:", $memberid), ); } ... $text = format_email_text(); ...

      It would probably be cleaner if the data was passed as arguments, too:

      sub format_email_text { my ($player, $parent, $memberid) = @_; return join("\n", sprintf("%-30s %-50s", "Player Name:", $player), sprintf("%-30s %-50s", "Parent's Name:", $parent), sprintf("%-30s %-50s", "Member ID:", $memberid), ); } ... $text = format_email_text($player, $parent, $memberid); ...
        Hi,

        In reply to your second method, the result that appears in my email looks like: print format_email_text(Minnie Mouse, Mickey Mouse, 78787);

        Each variable should appear underneath each other.
        Hi,

        It worked perfectly. Oh, thank you so much.

        Can you explain to me what the "join" portion of the code is doing?

        Thanks for your help.
      Hi,

      Thank you for the reply. I tried your suggestion and it worked, sort of. This is the result that I'm getting from my email.

      print "Player Name : " . Player Name: Mickey Mouse . " ";

      print "Parent Name : " . Parent's Name: Donald Duck . " ";

      print "Member ID : " . Member ID: 78787 . " ";

      The result should appear and line up like:
      Player Name: value
      Parent's Name: value

      I'm not sure what's going on here. Any ideas? Thank you so much.
Re: Format text problem
by Zaxo (Archbishop) on Apr 02, 2005 at 20:17 UTC

    The first return you hit is the only one that executes. Concatenate all your strings and make a single return with them. It is sufficient to make the concatenation the last statement in the sub. Here's one way to write it,

    sub format_email_text { my ($player, $parent, $memberid) = @_; sprintf "%-30s %-50s\n" x 3, 'Player Name:', $player, 'Parent\'s Name:', $parent, 'Member ID:', $memberid; }
    I've removed the use of variables from outside the sub, so you'll now need to call it with arguments to get the values inside. That helps prevent some hard to find bugs that may crop up with lexical closures or uninitialized globals.

    After Compline,
    Zaxo

Re: Format text problem
by davidg (Initiate) on Apr 02, 2005 at 20:18 UTC
    You might also try this:
    $str = sprintf("Player Name: %-50s\nParent's Name: %-50s\nMember ID: % +-50s\n",$player,$parent,$memberid); return $str;
    That way, I don't think you will need to change your main code.
      Hi,

      I tried your suggestions. It worked sort of. This is my result in the email:

      Player Name: Dopey
      Parent's Name: Pluto
      Member ID: 7878
      The information is not aligned directly underneath each other. My objective was to have the first column which displays the labels to be a width of 30 and the second column should be a width of 50.
        That will be very difficult to achieve in an e-mail as it depends on the e-mail client that gets the message, the fonts used on the user's system, ...

        One should never expect that the formatting one has applied will "survive" after sending the e-mail.

        CountZero

        "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: Format text problem
by TedPride (Priest) on Apr 03, 2005 at 08:57 UTC
    I would also like to note here that unless there is zero possibility of $text changing in format, you might want to make your sub a bit more adaptable - something like the following:
    use strict; use warnings; my $player = 'Bingo'; my $parent = 'Bob'; my $memberid = 'sad324gsg'; print format_email_text(30,50, "Player Name", $player, "Parent's Name", $parent, "Member ID", $memberid); sub format_email_text { my ($name, $val, $out, $nd, $vd); $nd = shift; $vd = shift; while ($name = shift) { $val = shift; $out .= sprintf('%-'.$nd.'s %-'.$vd.'s', "$name:", $val) . "\n +"; } return $out; }
    This would allow you to change the dimensions of the columns and the names and quantity of fields without having to rewrite the sub itself.
      Hi,

      I applied your suggestion to my script.

      The variables $player to $event line up perfectly. All the variables starting with $street are not lining up at all.

      This is the subroutine that generates the result:
      sub send_confirmation_email { my $text = format_email_text(30,50, "Player Name", $player, "Parent's Name", $parent, "Member ID", $memberid, "Email Address", $email, "Camp Date(s)", $dates, "Camp Event", $event, "Street", $street, "City", $city, "State", $state, "Zip Code", $zip, "Payment Method", $payment, "Message", $message); my %mail = ( From => "info\@anywhwere.com", To => $email, Subject => "Registration", Message => "" ); my $page; $mail{Message} = <<EOF; This is the information you submitted. $text EOF sendmail (%mail) or $page .= p (escapeHTML ("Oops, failure sending mail to $mai +l{To}")); return (defined ($page) ? $page : ""); }

      Plus, this is the subroutine you gave me:
      sub format_email_text { my ($name, $val, $out, $nd, $vd); $nd = shift; $vd = shift; while ($name = shift) { $val = shift; $out .= sprintf('%-'.$nd.'s %-'.$vd.'s', "$name:", $val) . "\n +"; } return $out; }

      Any ideas why some of the variables are appearing differently?

      Also, can you explain to me what your code is doing? I'm not sure what this line is doing:
      sprintf('%-'.$nd.'s %-'.$vd.'s',
      Thanks.
        Any ideas why some of the variables are appearing differently?
        No. Perhaps it's something that's happinging after the fact. Try printing out $text before you construct the mail and seeing if it layed out correctly.
        I'm not sure what this line is doing:
        sprintf('%-'.$nd.'s %-'.$vd.'s',
        Rathar than ask us to explain everything you could possibly being having trouble understanding, it would more efficient if you could be more precise about what about this you are finding difficult to understand.
        • Something documentation for the sprintf()
        • The effect of '-' in printf templates?
        • Concatenation of strings using the . operator?
        • Something else...?