From ee46374edfb377f57169f2b1de9afd19bf052da2 Mon Sep 17 00:00:00 2001 From: fukachan Date: Thu, 18 Oct 2001 08:32:16 +0000 Subject: Initial revision --- cpan/dist/HTML-FromText/FromText.pm | 736 ++++++++++++++++++++++++++++++++++ cpan/dist/HTML-FromText/MANIFEST | 6 + cpan/dist/HTML-FromText/Makefile.PL | 5 + cpan/dist/HTML-FromText/README | 58 +++ cpan/dist/HTML-FromText/TODO | 33 ++ cpan/dist/HTML-FromText/t/text2html.t | 698 ++++++++++++++++++++++++++++++++ 6 files changed, 1536 insertions(+) create mode 100644 cpan/dist/HTML-FromText/FromText.pm create mode 100644 cpan/dist/HTML-FromText/MANIFEST create mode 100644 cpan/dist/HTML-FromText/Makefile.PL create mode 100644 cpan/dist/HTML-FromText/README create mode 100644 cpan/dist/HTML-FromText/TODO create mode 100644 cpan/dist/HTML-FromText/t/text2html.t (limited to 'cpan/dist/HTML-FromText') diff --git a/cpan/dist/HTML-FromText/FromText.pm b/cpan/dist/HTML-FromText/FromText.pm new file mode 100644 index 00000000..2b7f1753 --- /dev/null +++ b/cpan/dist/HTML-FromText/FromText.pm @@ -0,0 +1,736 @@ +require 5.004; +use strict; + +package HTML::FromText; +use Carp; +use Exporter; +use Text::Tabs 'expand'; +use vars qw($RCSID $VERSION $QUIET @EXPORT @ISA); + +@ISA = qw(Exporter); +@EXPORT = qw(text2html); +$RCSID = q$Id: FromText.pm,v 1.14 1999/10/06 10:53:37 garethr Exp $; +$VERSION = '1.005'; +$QUIET = 0; + +# This list of protocols is taken from RFC 1630: "Universal Resource +# Identifiers in WWW". The protocol "file" is omitted because +# experience suggests that it results in many false positives; "https" +# postdates RFC 1630. The protocol "mailto" is handled separately, by +# the email address matching code. + +my $protocol = join '|', + qw(afs cid ftp gopher http https mid news nntp prospero telnet wais); + +# The regular expressions matching email addresses use the following +# syntax elements from RFC 822. I can't use the full details of +# structured field bodies, because that would give too many false +# positives. (See Tom Christiansen's ckaddr.gz for a full +# implementation of the RFC 822.) +# +# addr-spec = local-part "@" domain +# local-part = word *("." word) +# word = atom +# domain = sub-domain *("." sub-domain) +# sub-domain = domain-ref +# domain-ref = atom +# atom = 1* +# specials = "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "\" +# / <"> / "." / "[" / "]" +# +# I have ignored quoting, domain literals and comments. +# +# Note that '&' can legally appear in email addresses (for example, +# 'fred&barney@stonehenge.com'). If the 'metachars' option is passed to +# text2html then I must use '&' to recognize '&'. Thus the regular +# expression $atom[0] recognizes an atom in the case where the option +# 'metachars' is false; $atom[1] recognizes an atom in the case where +# 'metachars' is true. Similarly for the regular expressions $email[0] +# and $email[1], which recognize email addresses. + +my @atom = + ( '[!#$%&\'*+\\-/0123456789=?ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz{|}~]+', + '(?:&|[!#$%\'*+\\-/0123456789=?ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz{|}~])+' ); + +my @email = ( "$atom[0](\\.$atom[0])*\@$atom[0](\\.$atom[0])*", + "$atom[1](\\.$atom[1])*\@$atom[1](\\.$atom[1])*" ); + +my @alignments = ( '', '', ' ALIGN="RIGHT"', ' ALIGN="CENTER"' ); + +sub string2html ($$) { + my $options = $_[1]; + for ($_[0]) { # Modify in-place. + + # METACHARS: mark up HTML metacharacters as corresponding entities. + if ($options->{metachars}) { + s/&/&/g; + s//>/g; + s/\"/"/g; + } + + # EMAIL, URLS: spot electronic mail addresses and turn them into + # links. Note (1) if `urls' is set but not `email', then only + # addresses prefixed by `mailto:' will be marked up; (2) that we leave + # the `mailto:' prefix in the anchor text. + if ($options->{email} or $options->{urls}) { + s|((?:mailto:)?)($email[$options->{metachars}?1:0])| + ($options->{email} or $1) + ? "$1$2" : $2|gex; + } + + # URLS: mark up URLs as links (note that `mailto' links are handled + # above). + if ($options->{urls}) { + s|\b((?:$protocol):\S+[\w/])|$1|g; + } + + # BOLD: mark up words in *asterisks* as bold. + if ($options->{bold}) { + s#(^|\s)\*([^*]+)\*(?=\s|$)#$1$2#g; + } + + # UNDERLINE: mark up words in _underscores_ as underlined. + if ($options->{underline}) { + s#(^|\s)_([^_]+?)_(?=\s|$)#$1$2#g; + } + } + + return $_[0]; +} + +sub text2html { + local $_ = shift; # Take a copy; don't modify in-place. + return $_ unless $_; + + my %options = ( metachars => 1, @_ ); + + # Check options for sanity. + unless ($QUIET) { + carp "text2html: `spaces' will be ignored since `lines' is not specified" + if $options{spaces} and not $options{lines}; + if ($options{paras}) { + if ($options{blockparas}) { + foreach my $o (qw(blockquotes blockcode)) { + carp "text2html: `$o' will be ignored since `blockparas' is specified" if $options{$o}; + } + } elsif ($options{blockcode} and $options{blockquotes}) { + carp "text2html: `blockquotes' will be ignored since `blockcode' is specified"; + } + } else { + foreach my $o (qw(bullets numbers blockquotes blockparas blockcode + title headings tables)) { + carp "text2html: `$o' will be ignored since `paras' is not specified" + if $options{$o}; + } + } + } + + # Expand tabs. + $_ = join "\n", expand(split /\r?\n/); + + # PRE: put text in
 element.
+  if ($options{pre}) {
+    string2html($_, \%options);
+    s|^|
|;
+    s|$|
|; + } + + # LINES: preserve line breaks from original text. + elsif ($options{lines}) { + string2html($_, \%options); + s/\n/
\n/gm; + + # SPACES: preserve spaces from original text. + s/ / /g if $options{spaces}; + } + + # PARAS: treat text as sequence of paragraphs. + elsif ($options{paras}) { + my @paras; + + # Remove initial and final blank lines. + s/^(?:\s*?\n)+//; + s/(?:\n\s*?)+$//; + + # Split on a different regexp depending on what kinds of paragraphs + # will be recognised later. The idea is that bulleted lists like + # this: + # + # * item 1 + # * item 2 + # + # will be recognised as multiple paragraphs if the 'bullets' option + # is supplied, but as a single paragraph otherwise. (Similarly for + # numbered lists). + if ($options{bullets} and $options{numbers}) { + @paras = split + /(?:\s*\n)+ # (0 or more blank lines, followed by LF) + (?:\s*\n # Either 1 or more blank lines, or + |(?=\s*[*-]\s+ # bulleted item follows, or + |\s*(?:\d+)[.\)\]]?\s+)) # numbered item follows + /x; + } elsif ($options{bullets}) { + @paras = split + /(?:\s*\n)+ # (0 or more blank lines, followed by LF) + (?:\s*\n # Either 1 or more blank lines, or + |(?=\s*[*-]\s+)) # bulleted item follows. + /x; + } elsif ($options{numbers}) { + @paras = split + /(?:\s*\n)+ # (0 or more blank lines, followed by LF) + (?:\s*\n # Either 1 or more blank lines, or + |(?=\s*(?:\d+)[.\)\]]?\s+)) # numbered item follows. + /x; + } else { + @paras = split + /\s*\n(?:\s*\n)+ # 1 or more blank lines. + /x; + } + + my $last = ''; # List type (OL/UL) of last paragraph + my $this; # List type (OL/UL) of this paragraph + my $first = 1; # True if this is first paragraph + + foreach (@paras) { + my (@rows,@starts,@ends); + $this = ''; + + # TITLE: mark up first paragraph as level-1 heading. + if ($options{title} and $first) { + string2html($_,\%options); + s|^|

|; + s|$|

|; + } + + # HEADINGS: mark up paragraphs with numbers at the start of the + # first line as headings. + elsif ($options{headings} and /^(\d+(\.\d+)*)\.?\s/) { + my $number = $1; + my $level = 1 + ($number =~ tr/././); + $level = 6 if $level > 6; + string2html($_,\%options); + s|^||; + s|$||; + } + + # BULLETS: mark up paragraphs starting with bullets as items in an + # unnumbered list. + elsif ($options{bullets} and /^\s*[*-]\s+/) { + string2html($_,\%options); + s/^\s*[*-]\s+/
  • /; + s|$|

    |; + $this = 'UL'; + } + + # NUMBERS: mark up paragraphs starting with numbers as items in a + # numbered list. + elsif ($options{numbers} and /^\s*(\d+)[.\)\]]?\s+/) { + string2html($_,\%options); + s/^\s*(\d+)[.\)\]]?\s+/
  • /; + s|$|

    |; + $this = 'OL'; + } + + # TABLES: spot and mark up tables. We combine the lines of the + # paragraph using the string bitwise or (|) operator, the result + # being in $spaces. A character in $spaces is a space only if + # there was a space at that position in every line of the + # paragraph. $space can be used to search for contiguous spaces + # that occur on all lines of the paragraph. If this results in at + # least two columns, the paragraph is identified as a table. + # + # Note that this option appears before the various 'blockquotes' + # options because a table may well have whitespace to the left, in + # which case it must not be incorrectly recognised as a + # blockquote. + elsif ($options{tables} and do { + @rows = split /\n/, $_; + my $spaces; + my $max = 0; + my $min = length; + foreach my $row (@rows) { + ($spaces |= $row) =~ tr/ /\xff/c; + $min = length $row if length $row < $min; + $max = length $row if $max < length $row; + } + $spaces = substr $spaces, 0, $min; + push(@starts, 0) unless $spaces =~ /^ /; + while ($spaces =~ /((?:^| ) +)(?=[^ ])/g) { + push @ends, pos($spaces) - length $1; + push @starts, pos($spaces); + } + shift(@ends) if $spaces =~ /^ /; + push(@ends, $max); + + # Two or more rows and two or more columns indicate a table. + 2 <= @rows and 2 <= @starts + }) { + # For each column, guess whether it should be left, centre or + # right aligned by examining all cells in that column for space + # to the left or the right. A simple majority among those cells + # that actually have space to one side or another decides (if no + # alignment gets a majority, left alignment wins by default). + + my @align; + foreach my $col (0 .. $#starts) { + my @count = (0, 0, 0, 0); + foreach my $row (@rows) { + my $width = $ends[$col] - $starts[$col]; + my $cell = substr $row, $starts[$col], $width; + ++ $count[($cell =~ /^ / ? 2 : 0) + + ($cell =~ / $/ || length($cell) < $width ? 1 : 0)]; + } + $align[$col] = 0; + my $population = $count[1] + $count[2] + $count[3]; + foreach (1 .. 3) { + if ($count[$_] * 2 > $population) { + $align[$col] = $_; + last; + } + } + } + + foreach my $row (@rows) { + $row = join '', '', (map { + my $cell = substr $row, $starts[$_], $ends[$_] - $starts[$_]; + $cell =~ s/^ +//; + $cell =~ s/ +$//; + string2html($cell,\%options); + ('', $cell, '') + } 0 .. $#starts), ''; + } + my $tag = $starts[0] == 0 ? 'P' : 'BLOCKQUOTE'; + $_ = join "\n", "<$tag>", @rows, "
    "; + } + + # BLOCKPARAS, BLOCKCODE, BLOCKQUOTES: mark up indented paragraphs + # as block quotes of various kinds. + elsif (($options{blockparas} or $options{blockquotes} + or $options{blockcode}) and /^(\s+).*(?:\n\1.*)*$/) { + string2html($_,\%options); + + # Every line in the paragraph starts with at white space, the common + # whitespace being in $1. Remove the common initial whitespace, + s/^$1//gm; + + # BLOCKPARAS: treat as a paragraph. + if ($options{blockparas}) { + s|^|

    |; + s|$|

    |; + } + + # BLOCKCODE, BLOCKQUOTES: preserve line breaks. + else { + s/\n/
    \n/gm; + + # BLOCKCODE: preserve spaces, use fixed-width font. + if ($options{blockcode}) { + s| | |g; + s|^||; + s|$||; + } + } + s|^|
    |; + s|$|
    |; + } + + # Didn't match any of the above, so just an ordinary paragraph. + else { + string2html($_,\%options); + s|^|

    |; + s|$|

    |; + } + + # Insert
      ,
    ,
      or
    if this paragraph belongs to a + # different list type than the previous one. + if ($this ne $last) { + s|^|<$this>| if ($this ne ''); + s|^|| if ($last ne ''); + } + $last = $this; + $first = 0; + } + if ($this ne '') { + push @paras, ""; + } + $_ = join "\n", @paras; + } + + # None of PRE, LINES, PARAS specified: apply basic transformations. + else { + string2html($_,\%options); + } + return $_; +} + +1; + +__END__ + +=head1 NAME + +HTML::FromText - mark up text as HTML + +=head1 SYNOPSIS + + use HTML::FromText; + print text2html($text, urls => 1, paras => 1, headings => 1); + +=head1 DESCRIPTION + +The C function marks up plain text as HTML. By default it +expands tabs and converts HTML metacharacters into the corresponding +entities. More complicated transformations, such as splitting the text +into paragraphs or marking up bulleted lists, can be carried out by +setting the appropriate options. + +=head1 SUMMARY OF OPTIONS + +These options always apply: + + metachars Convert HTML metacharacters to entity references + urls Convert URLs to links + email Convert email addresses to links + bold Mark up words with *asterisks* in bold + underline Mark up words with _underscores_ as underlined + +You can then choose to treat the text according to one of these options: + + pre Treat text as preformatted + lines Treat text as line-oriented + paras Treat text as paragraph-oriented + +(If more than one of these is specified, C
     takes precedence over
    +C which takes precedence over C.)  The following option
    +applies when the C option is specified:
    +
    +    spaces       Preserve spaces from the original text
    +
    +The following options apply when the C option is specified:
    +
    +    blockparas   Mark up indented paragraphs as block quote
    +    blockquotes  Ditto, also preserve lines from original
    +    blockcode    Ditto, also preserve spaces from original
    +    bullets      Mark up bulleted paragraphs as unordered list
    +    headings     Mark up headings
    +    numbers      Mark up numbered paragraphs as ordered list
    +    tables       Mark up tables
    +    title        Mark up first paragraph as level 1 heading
    +
    +C will issue a warning if it is passed nonsensical options,
    +for example C but not C.  These warnings can be
    +supressed by setting $HTML::FromText::QUIET to true.
    +
    +=head1 OPTIONS
    +
    +=over 4
    +
    +=item blockparas
    +
    +=item blockquotes
    +
    +=item blockcode
    +
    +These options cause to C to spot paragraphs where every line
    +begins with whitespace, and mark them up as block quotes.  If more than
    +one of these options is specified, C takes precedence over
    +C, which takes precedence over C.  All three
    +options are ignored unless the C option is also set.
    +
    +The C option marks up the paragraph as a block quote with no
    +other changes.  For example,
    +
    +    Turing wrote,
    +
    +        I propose to consider the question,
    +        "Can machines think?"
    +
    +becomes
    +
    +    

    Turing wrote,

    +
    I propose to consider the question, + "Can machines think?"
    + +The C option preserves line breaks in the original text. +For example, + + From "The Waste Land": + + Phlebas the Phoenecian, a fortnight dead, + Forgot the cry of gulls, and the deep sea swell + +becomes + +

    From "The Waste Land":

    +
    Phlebas the Phoenecian, a fortnight dead,
    + Forgot the cry of gulls, and the deep sea swell
    + +The C option preserves line breaks and spaces in the original +text and renders the paragraph in a fixed-width font. For example: + + Here's how to output numbers with commas: + + sub commify { + local $_ = shift; + 1 while s/^(-?\d+)(\d{3})/$1,$2/; + $_; + } + +becomes + +

    Here's how to output numbers with commas:

    +
    sub commify {
    +   local $_ = shift;
    +   1 while s/^(-?\d+)(\d{3})/$1,$2/;
    +   $_;
    + }
    + +=item bold + +Words surrounded with asterisks are marked up in bold, so C<*abc*> +becomes CBEabcE/BE>. + +=item bullets + +Spots bulleted paragraphs (beginning with optional whitespace, an +asterisk or hyphen, and whitespace) and marks them up as an unordered +list. Bulleted paragraphs don't have to be separated by blank lines. +For example, + + Shopping list: + + * apples + * pears + +becomes + +

    Shopping list:

    +
    • apples

      +
    • pears

      +
    + +This option is ignored unless the C option is set. + +=item email + +Spots email addresses in the text and converts them to links. For example + + Mail me at web@perl.com. + +becomes + + Mail me at web@perl.com. + +=item headings + +Spots headings (paragraphs starting with numbers) and marks them up as +headings of the appropriate level. For example, + + 1. Introduction + + 1.1 Background + + 1.1.1 Previous work + + 2. Conclusion + +becomes + +

    1. Introduction

    +

    1.1 Background

    +

    1.1.1 Previous work

    +

    2. Conclusion

    + +This option is ignored unless the C option is set. + +=item lines + +Formats the text so as to preserve line breaks. For example, + + Line 1 + Line 2 + +becomes + + Line 1
    + Line 2 + +If two or more of the options C
    , C and C are set,
    +then C
     takes precedence over C, which takes precedence over
    +C.
    +
    +=item metachars
    +
    +Converts HTML metacharacters into their corresponding entity references.
    +Ampersand (C>) becomes Camp;>, less than (C>)
    +becomes Clt;>, greater than (C>) becomes Cgt;>, and
    +quote (") becomes Cquot;>.  This option is 1 by default.
    +
    +=item numbers
    +
    +Spots numbered paragraphs (beginning with whitespace, digits, an
    +optional period/parenthesis/bracket, and whitespace) and marks them up
    +as an ordered list.  Numbered paragraphs don't have to be separated by
    +blank lines.  For example,
    +
    +    To do:
    +
    +       1. Write thesis
    +       2. Submit it
    +       3. Celebrate
    +
    +becomes
    +
    +    

    To do:

    +
    1. Write thesis

      +
    2. Submit it

      +
    3. Celebrate

      +
    + +This option is ignored unless the C option is set. + +=item paras + +Format the text into paragraphs. Paragraphs are separated by one or +more blank lines. For example, + + Paragraph 1 + + Paragraph 2 + +becomes + +

    Paragraph 1

    +

    Paragraph 2

    + +If two or more of the options C
    , C and C are set,
    +then C
     takes precedence over C, which takes precedence over
    +C.
    +
    +=item pre
    +
    +Wrap the whole input in a CPREE> element.  For example,
    +
    +    preformatted
    +    text
    +
    +becomes
    +
    +    
    preformatted
    +    text
    + +If two or more of the options C
    , C and C are set,
    +then C
     takes precedence over C, which takes precedence over
    +C.
    +
    +=item spaces
    +
    +Preserves spaces throughout the text.  For example,
    +
    +    Line 1
    +     Line  2
    +      Line   3
    +
    +becomes
    +
    +    Line 1
    +  Line  2
    +   Line   3 + +This option is ignored unless the C option is set. + +=item tables + +Spots tables and marks them up appropriately. Columns must be separated +by two or more spaces (this prevents accidental incorrect recognition of +a paragraph where interword spaces happen to line up). If there are two +or more rows in a paragraph and all rows share the same set of (two or +more) columns, the paragraph is assumed to be a table. For example + + -e File exists. + -z File has zero size. + -s File has nonzero size (returns size). + +becomes + +

    + + + +
    -eFile exists.
    -zFile has zero size.
    -sFile has nonzero size (returns size).

    + +C guesses for each column whether it is intended to be left, +centre or right aligned. + +This option is ignored unless the C option is set. + +=item title + +Formats the first paragraph of the text as a first-level heading. +For example, + + Paragraph 1 + + Paragraph 2 + +becomes + +

    Paragraph 1

    +

    Paragraph 2

    + +This option is ignored unless the C option is set. + +=item underline + +Words surrounded with underscores are marked up with underline, so C<_abc_> +becomes CUEabcE/UE>. + +=item urls + +Spots Uniform Resource Locators (URLs) in the text and converts them +to links. For example + + See https://perl.com/. + +becomes + + See https://perl.com/. + +=back + +=head1 SEE ALSO + +The C module (part of the LWP package) provides +functions for encoding and decoding HTML entities. + +Tom Christiansen has a complete implementation of RFC 822 structured +field bodies. See +C. + +Seth Golub's C utility does everything that C +does, and a few things that it would like to do. See +C. + +RFC 822: "Standard for the Format of ARPA Internet Text Messages" +describes the syntax of email addresses (the more esoteric features of +structured field bodies, in particular quoted-strings, domain literals +and comments, are not recognized by C). See +C. + +RFC 1630: "Universal Resource Identifiers in WWW" lists the protocols +that may appear in URLs. C also recognizes "https:", +but ignores "file:" because experience suggests that it results in too +many false positives. See C. + +=head1 AUTHOR + +Gareth Rees Cgarethr@cre.canon.co.ukE>. + +=head1 COPYRIGHT + +Copyright (c) 1999 Canon Research Centre Europe. All rights reserved. +This module is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=cut diff --git a/cpan/dist/HTML-FromText/MANIFEST b/cpan/dist/HTML-FromText/MANIFEST new file mode 100644 index 00000000..1d625b62 --- /dev/null +++ b/cpan/dist/HTML-FromText/MANIFEST @@ -0,0 +1,6 @@ +FromText.pm +MANIFEST +Makefile.PL +README +TODO +t/text2html.t diff --git a/cpan/dist/HTML-FromText/Makefile.PL b/cpan/dist/HTML-FromText/Makefile.PL new file mode 100644 index 00000000..e73edc44 --- /dev/null +++ b/cpan/dist/HTML-FromText/Makefile.PL @@ -0,0 +1,5 @@ +use ExtUtils::MakeMaker; +WriteMakefile( NAME => 'HTML::FromText', + VERSION_FROM => 'FromText.pm', + dist => { COMPRESS => 'gzip', SUFFIX => 'gz' }, + ); diff --git a/cpan/dist/HTML-FromText/README b/cpan/dist/HTML-FromText/README new file mode 100644 index 00000000..cf740136 --- /dev/null +++ b/cpan/dist/HTML-FromText/README @@ -0,0 +1,58 @@ +NAME + HTML::FromText - mark up text as HTML + +SYNOPSIS + use HTML::FromText; + print text2html($text, urls => 1, paras => 1, headings => 1); + +DESCRIPTION + The text2html function marks up plain text as HTML. By + default it converts HTML metacharacters into the + corresponding entities. More sophisticated transformations, + such as splitting the text into paragraphs or marking up + bulleted lists, can be carried out by setting the + appropriate options. + +INSTALLATION + perl Makefile.PL && make && make test && make install + +HISTORY + 1.005 Options 'bold' and 'underline' are more aggressive in + recognising markup. + + 1.004 New options 'blockparas' (mark up block quotes as ordinary + paragraphs) and 'blockcode' (mark up block quotes in + fixed-width font while preserving line breaks and spaces). + + Tabs are expanded throughout the text (it was a bug not to + do so in earlier versions because alignment could be lost, + block quotes not recognised, etc). + + New option 'tables'. + + 1.003 Recognize '&' in email addresses, as specified by RFC822. + + 1.002 Much improved recognition of e-mail addresses with special + characters, as specified by RFC822. + + When 'urls' is supplied, the prefix mailto: on email + addresses is preserved. + + New option 'pre' wraps text in
    ...
    . + + When anchor text is in fixed-width font, the element is + inside the element, as required by the HTML DTD. + + 1.001 Original CPAN release. + +BUGS + There are transformations it doesn't do. + +AUTHOR + Gareth Rees . + +COPYRIGHT + Copyright (c) 1999 Canon Research Centre Europe. All rights + reserved. This module is free software; you can + redistribute it and/or modify it under the same terms as + Perl itself. diff --git a/cpan/dist/HTML-FromText/TODO b/cpan/dist/HTML-FromText/TODO new file mode 100644 index 00000000..6ebf6838 --- /dev/null +++ b/cpan/dist/HTML-FromText/TODO @@ -0,0 +1,33 @@ +---------------------------------IDEAS---------------------------------- + +1. Have a more general means of representing paragraph transformations + and applying them so that text2html can be extended. Each + transformation would have (a) an option name, (b) a sub for testing + whether the transformation is applicable to the paragraph and (c) a + sub for applying the option. (There must be a means of passing + information from step (b) to step (c) as for the table + transformation.) + + (But are there that many other transformations that can be applied on + a paragraph basis? Other kinds of transformations would be harder to + generalise like this. Think about the need to have a different idea + about where paragraph boundaries are depending on the options.) + +2. The current approach is to test the transformations for applicability + one by one and apply the first one that matches. It might be better + to test all the transformations and score them, then apply the + best scoring. This would allow heuristics to be applied. + +3. The current approach goes through the paragraphs one by one with no + lookahead. Multiple passes through the paragraphs could allow + heuristics to be applied, e.g., to distinguish nested lists from + adjacent lists. + +4. These transformations could be implemented: + + * lettered paragraphs a) b) c) etc + + * underlined headings + + * quoted text in e-mail message (impossible to accurately given the + enormous diversity of quoting styles -- would 60% be good enough?) diff --git a/cpan/dist/HTML-FromText/t/text2html.t b/cpan/dist/HTML-FromText/t/text2html.t new file mode 100644 index 00000000..0e78a21c --- /dev/null +++ b/cpan/dist/HTML-FromText/t/text2html.t @@ -0,0 +1,698 @@ +# HTML::FromText test suite (-*- cperl -*-) + +use strict; +use HTML::FromText; +$^W = 1; + +# Each test is represented by three data chunks, separated by a line +# containing only a form-feed character (0x0c). The first chunk is +# the options to pass to text2html(), the second is the input, and the +# third the expected output. + +$/ = "\n\f\n"; +my @tests = (); +while () { + chomp; + push @tests, $_; +} +my $n = @tests / 3; +print "1..$n\n"; +foreach my $i (1..$n) { + my $j = 3 * ($i - 1); + my $input = $tests[$j + 1]; + my $expected = $tests[$j + 2]; + my @options = eval $tests[$j]; + my $output = text2html($input, @options); + unless ($output eq $expected) { + print STDERR + "\n",'--expected','-'x60, + "\n",$expected, + "\n",'--but-found','-'x59, + "\n",$output, + "\n",'-'x70, + "\n"; + print "not "; + } + print "ok $i\n"; +} + +__DATA__ + +() + +<&> + +<B>&lt;&amp;&gt;</B> + + +(metachars => 0) + +<&> + +<&> + + +(email => 1) + +real@email.address, real2@email.addresss. +fake@:email.address, another@[fake].address +mailto:me@foo.bar.com + +#$%=strange!?@characters.=+=in=+=_.address + +real@email.address, real2@email.addresss. +fake@:email.address, another@[fake].address +mailto:me@foo.bar.com +<tricky@subdomain.domain> +#$%=strange!?@characters.=+=in=+=_.address + + +(metachars => 1, email => 1) + +An email address with an & in it: fred&barney@stonehenge.com. + +An email address with an & in it: fred&barney@stonehenge.com. + + +(metachars => 0, email => 1) + +An email address with an & in it: fred&barney@stonehenge.com. Generates +non-legal HTML, but that was what was asked for! + +An email address with an & in it: fred&barney@stonehenge.com. Generates +non-legal HTML, but that was what was asked for! + + +(urls => 1) + +See http://foo.bar.com. +What about http://foo.com/bar/baz? +http://foo.com/bar/baz?quux. +ftp://spong.gov/a/b/c/d.e/f.g/h/ should have trailing / +...gopher://x.y.z/foo... +mailto:mail@address.com is translated +but mail@address.com on its own is not + +See http://foo.bar.com. +What about http://foo.com/bar/baz? +http://foo.com/bar/baz?quux. +ftp://spong.gov/a/b/c/d.e/f.g/h/ should have trailing / +...gopher://x.y.z/foo... +mailto:mail@address.com is translated +but mail@address.com on its own is not + + +(bold => 1, underline => 1) + +*Words* in *bold* _underline_ and *bold* again, but 5*4, 3_1 unaffected; +_underline_ *more* *bold* +_more_ _underline_ +Now *several words in bold* and _several in underline_ but +equations like 5*x + 5*y or zeta_i + phi_i are not marked up. +Here's a *phrase in bold +crossing a newline* and an _underlined phrase +crossing a newline_ +Single letter words: *a* _b_ *c* _d_ + +Words in bold underline and bold again, but 5*4, 3_1 unaffected; +underline more bold +more underline +Now several words in bold and several in underline but +equations like 5*x + 5*y or zeta_i + phi_i are not marked up. +Here's a phrase in bold +crossing a newline and an underlined phrase +crossing a newline +Single letter words: a b c d + + +(paras => 1, bold => 1, underline => 1) + +*Bold* works OK in a paragraph context +and so does _underline_ + +_Underline works OK_ in a paragraph context +and *so does bold* + +

    Bold works OK in a paragraph context +and so does underline

    +

    Underline works OK in a paragraph context +and so does bold

    + + +(lines => 1) + +line 1 +line 2 +line 3 +line 4 + +line 1
    +line 2
    +line 3
    +line 4 + + +(lines => 1, spaces => 1) + +line 1 + line 2 + line 3 + line 4 + tab 1 + tab 2 + +line 1
    + line  2
    +  line   3
    +   line    4
    +        tab     1
    +                tab     2 + + +(paras => 1) + +paragraph +one + +paragraph +two + +a +long +paragraph +three + +

    paragraph +one

    +

    paragraph +two

    +

    a +long +paragraph +three

    + + +(paras => 1, title => 1) + +this +is the +title + +and this +the text + +

    this +is the +title

    +

    and this +the text

    + + +(paras => 1, headings => 1) + +1. Chapter one + +2. Chapter two + +2.1 Section two point one + +2.1.1 Subsection two point one point one + +2.1.1.3 Subsubsection two point one point one point three + +2.1.1.3.7 Heading level 5 + +2.1.1.3.7.1 Heading level 6 (a long heading across +two lines) + +paragraph text + +2.1.1.3.7.1.2 There are no more than 6 heading levels. + +paragraph text + +3. Chapter three + +

    1. Chapter one

    +

    2. Chapter two

    +

    2.1 Section two point one

    +

    2.1.1 Subsection two point one point one

    +

    2.1.1.3 Subsubsection two point one point one point three

    +
    2.1.1.3.7 Heading level 5
    +
    2.1.1.3.7.1 Heading level 6 (a long heading across +two lines)
    +

    paragraph text

    +
    2.1.1.3.7.1.2 There are no more than 6 heading levels.
    +

    paragraph text

    +

    3. Chapter three

    + + +(paras => 1, bullets => 1) + +Ordinary text + + * bulleted paragraph + + * another bulleted paragarph + with two lines + +ordinary text + +* bullet flush left + + * bullet with tabs + + - bullet with hyphen + +

    Ordinary text

    +
    • bulleted paragraph

      +
    • another bulleted paragarph + with two lines

      +

    ordinary text

    +
    • bullet flush left

      +
    • bullet with tabs

      +
    • bullet with hyphen

      +
    + + +(paras => 1, headings => 1, numbers => 1) + +1. This is a heading, not a numbered paragraph + + 1. number one + + 2. number two + + 31. number thirty-one + +ordinary text + + 1. another number one + + * bulleted paragraph not recognised + + 3. number three + +

    1. This is a heading, not a numbered paragraph

    +
    1. number one

      +
    2. number two

      +
    3. number thirty-one

      +

    ordinary text

    +
    1. another number one

      +

    * bulleted paragraph not recognised

    +
    1. number three

      +
    + + +(paras => 1, numbers => 1, bullets => 1) + + 1. a numbered item + + 2. and another + + * switching to bullets starts a new list + + 3. as does switching back + +
    1. a numbered item

      +
    2. and another

      +
    • switching to bullets starts a new list

      +
    1. as does switching back

      +
    + + +(paras => 1, numbers => 1, bullets => 1) + +* a bulleted list +* with all the bullets next to each other +* blah +* blah + +
    • a bulleted list

      +
    • with all the bullets next to each other

      +
    • blah

      +
    • blah

      +
    + + +(paras => 1, numbers => 1, bullets => 1) + +1. a numbered list +2. with all the numbers next to each other +3. blah +4. blah + +
    1. a numbered list

      +
    2. with all the numbers next to each other

      +
    3. blah

      +
    4. blah

      +
    + + +(paras => 1, numbers => 1, bullets => 1) + +* switching between +111 numbers +* and +222 bullets + +
    • switching between

      +
    1. numbers

      +
    • and

      +
    1. bullets

      +
    + + +(paras => 1, numbers => 1, bullets => 1) + +Ordinary paragraphs +* mixed up with +numbers +789 and +bullets + +

    Ordinary paragraphs

    +
    • mixed up with +numbers

      +
    1. and +bullets

      +
    + + +(paras => 1, numbers => 1, bullets => 1) + +000 different +002. kinds +003) of +004] numbered +001 list + +
    1. different

      +
    2. kinds

      +
    3. of

      +
    4. numbered

      +
    5. list

      +
    + + +(paras => 1, blockquotes => 1) + +Here's a block quote: + + line 1 + line 2 + line 3 + line 4 + +end of block quote + +

    Here's a block quote:

    +
    line 1
    +line 2
    +line 3
    +line 4
    +

    end of block quote

    + + +(paras => 1, blockquotes => 1) + +A block quote with variable spacing: + + line 1 + line 2 + line 3 + +end of block quote + +

    A block quote with variable spacing:

    +
    line 1
    + line 2
    + line 3
    +

    end of block quote

    + + +(paras => 1, blockquotes => 1) + +Ditto, spacing goes the other way: + + line 1 + line 2 + line 3 + +end of block quote + +

    Ditto, spacing goes the other way:

    +
    line 1
    + line 2
    +line 3
    +

    end of block quote

    + + +(paras => 1, blockquotes => 1) + +This shouldn't be recognized as blockquote: + + despite the spaces on this line, + and this one, +this is just an ordinary paragraph? + +

    This shouldn't be recognized as blockquote:

    +

    despite the spaces on this line, + and this one, +this is just an ordinary paragraph?

    + + +(paras => 1, bullets => 1, numbers => 1, blockquotes => 1) + + +This is not a blockquote, despite initial and final blank lines. + + +

    This is not a blockquote, despite initial and final blank lines.

    + + +(pre => 1) + +preformatted +text + +
    preformatted
    +text
    + + +(paras => 1, blockparas => 1) + +Turing wrote, + + I propose to consider the question, "Can machines think?" + This should begin with definitions of the meaning of the + terms "machine" and "think". + +

    Turing wrote,

    +

    I propose to consider the question, "Can machines think?" +This should begin with definitions of the meaning of the +terms "machine" and "think".

    + + +(paras => 1, blockquotes => 1) + +From "The Waste Land": + + Phlebas the Phoenecian, a fortnight dead, + Forgot the cry of gulls, and the deep sea swell + +

    From "The Waste Land":

    +
    Phlebas the Phoenecian, a fortnight dead,
    +Forgot the cry of gulls, and the deep sea swell
    + + +(paras => 1, blockcode => 1) + +Here's how to output numbers with commas (from perlfaq4): + + sub commify { + local $_ = shift; + 1 while s/^(-?\d+)(\d{3})/$1,$2/; + $_; + } + +

    Here's how to output numbers with commas (from perlfaq4):

    +
    sub commify {
    +  local $_ = shift;
    +  1 while s/^(-?\d+)(\d{3})/$1,$2/;
    +  $_;
    +}
    + + +() + +Line mixing tabs and metachars: + &&& <> + +Line mixing tabs and metachars: + &&& <> + + +(paras => 1, tables => 1) + + 1, 1 1, 2 1, 3 + 2, 1 2, 2 2, 3 + 3, 1 3, 2 3, 3 + +
    + + + +
    1, 11, 21, 3
    2, 12, 22, 3
    3, 13, 23, 3
    + + +(paras => 1, tables => 1) + +Tables can be left-aligned: + +1, 1 1, 2 1, 3 +2, 1 2, 2 2, 3 +3, 1 3, 2 3, 3 + +

    Tables can be left-aligned:

    +

    + + + +
    1, 11, 21, 3
    2, 12, 22, 3
    3, 13, 23, 3

    + + +(paras => 1, tables => 1) + + despite its appearance + this table has + only two columns + +
    + + + +
    despite itsappearance
    this tablehas
    only twocolumns
    + + +(paras => 1, tables => 1) + + tables + must + have + two + columns + +

    tables + must + have + two + columns

    + + +(paras => 1, tables => 1) + + tables can + have only + one space + at the left + +
    + + + + +
    tablescan
    haveonly
    onespace
    at theleft
    + + +(paras => 1, tables => 1) + + tables must have two rows + +

    tables must have two rows

    + + +(paras => 1, tables => 1) + + this table has varying lengths of column + at the right + +
    + + +
    thistablehas varying lengths of column
    attheright
    + + +(paras => 1, tables => 1) + +This table contains right-aligned cells: + + p p^2 p^3 p^4 + 2 4 8 16 + 3 9 27 81 + 5 25 125 625 + 7 49 343 2401 + +

    This table contains right-aligned cells:

    +
    + + + + + +
    pp^2p^3p^4
    24816
    392781
    525125625
    7493432401
    + + +(paras => 1, tables => 1) + +This table contains metacharacters: + + & & + < < + > > + +

    This table contains metacharacters:

    +
    + + + +
    &&amp;
    <&lt;
    >&gt;
    + + +(paras => 1, tables => 1) + +Here's a table with centre-aligned columns: + +1 1 +2 1 1 +3 1 2 1 +4 1 3 3 1 +5 1 4 6 4 1 + +

    Here's a table with centre-aligned columns:

    +

    + + + + + +
    11
    21 1
    31 2 1
    41 3 3 1
    51 4 6 4 1

    + + +(paras => 1, blockparas => 1, tables => 1) + + This should get recognised + as a blockquote despite + the unorthodox spacing. + + But this is a table + XXX XXXX XX X XXXXX + +

    This should get recognised +as a blockquote despite +the unorthodox spacing.

    +
    + + +
    Butthisisatable
    XXXXXXXXXXXXXXX
    + -- cgit v1.2.1