views:

809

answers:

5

Hello,

I would like to know if there was a way to set a width for lines outputted to aid in formatting, to make sure that lines always wrap after a certain amount. I will be using the code below to sort and print emails, and would prefer messages that are on very long lines are neatly broken up, but I am unsure how to do this. I have attempted with Text::Wrap

#!/usr/bin/perl
use warnings;
use strict;
use Text::Wrap
use Mail::Box::Manager;

open (MYFILE, '>>data.txt');
binmode(MYFILE, ':encoding(UTF-8)');


my $file = shift || $ENV{MAIL};
my $mgr = Mail::Box::Manager->new(
    access          => 'r',
);

my $folder = $mgr->open( folder => $file )
or die "$file: Unable to open: $!\n";

for my $msg ( sort { $a->timestamp <=> $b->timestamp } $folder->messages)
{
    my $to          = join( ', ', map { $_->format } $msg->to );
    my $from        = join( ', ', map { $_->format } $msg->from );
    my $date        = localtime( $msg->timestamp );
    my $subject     = $msg->subject;
    my $body        = $msg->decoded->string;

    # Strip all quoted text
    $body =~ s/^>.*$//msg;

$Text::Wrap::columns=20;

print MYFILE wrap("", "", <<"");
From: $from
To: $to
Date: $date
Subject: $subject
\n
$body

}

I am using the above code, but now get this error:

Undefined subroutine &main::wrap called at x.pl line 29, line 136516.

+4  A: 

Look at the routines provided by Text::Wrap. Do they do what you want?

Cirno de Bergerac
They seem to, is the way I have used it in my edited code correct?
Joshxtothe4
No. It would be more correct as print MYFILE wrap("", "", <<"");
Cirno de Bergerac
I get an error and I am unsure why?
Joshxtothe4
A: 
  1. There will almost certainly be a module in CPAN that does this.
  2. It's not hard to implement - for each line of unformatted text split it on the spaces. Then iterate through the components incrementing a column count by the width of each word (+1 for the space after). Once you hit your line wrap column, start a new line in your formatted string. Append that word (and a space) to your formatted string.
  3. It's a lot harder when you have "> " to deal with in email messages, as you want to preserve them. It might be better to write an email message parser that will turn an email into a more structured object that handles various quotation levels, and then have a prettyPrint method on that.
JeeBee
I have removed all > and quoted mails from my messages so that should not be a problem
Joshxtothe4
A: 

There's no builtin way, although I'd be amazed if there wasn't a module that can do it (Text::Wrap ?).

In general terms, you're going to have to split your $body into words, and then join it back together with a new line inserted each time the length of the current line plus the next word exceeds your required width, i.e. something like (untested):

my @words = split(/\s+/, $body);
my $line = '';
$body = '';
my $maxwidth = 72;
do {
  my $word = shift(@words);
  if (length($line) + length($word) > $maxwidth) {
    $body .= $line . "\n";
    $line = $word;
  } else {
    $line .= ' ' . $word;
  }
} while (@words);
$body .= $line . "\n";
Alnitak
+1  A: 

Have you, by any chance, tried to import the wrap subroutine explicitly?

use Text::Wrap qw/ wrap /;
innaM
+4  A: 

Your code has a syntax error at line 4:

use Text::Wrap

should be:

use Text::Wrap;  # note the semi-colon

I don't recommend the use of an empty string as a here-document delimiter. Use something that makes it clear to the reader where the document ends:

    print <<EOF;
This is some text.
More text.
EOF

The error message you listed, "Undefined subroutine &main::wrap called at x.pl line 29," suggests that you were running your code from a file that did not include the 'use Text::Wrap;' statement, otherwise the exported &Text::Wrap::wrap subroutine would have been defined.

Learn to simplify problems. With dynamic languages like Perl it's easy to test code on the command line. After a two-minute refresher read of the Text::Wrap documentation I banged this out in an xterm:

$ perl -MText::Wrap -le 'print wrap("","",<<EOF)
> This is a long line of text. This is a long line of text. This is a long line of text. This is a long line of text. This is a long line of text. 
> EOF
> '
This is a long line of text. This is a long line of text. This is a long
line of text. This is a long line of text. This is a long line of text.
converter42