Text::Hatena::Escaped

というわけで、Text::Hatenaに渡したらHTMLエスケープした上で整形するように継承してみた。

#!/usr/bin/perl

use strict;
use warnings;

{
    package Text::Hatena::Escaped;
    use base qw(Text::Hatena);

    sub text_line {
        my $class = shift;
        my $text  = shift->{items}->[2];
        return $class->escape("$text\n");
    }

    sub cdata {
        my $class = shift;
        my $items = shift->{items};
        my $data  = $items->[1];
        $data = $class->escape($data);
        return "<$data>\n";
    }

    sub pre_line {
        my $class   = shift;
        my $items   = shift->{items};
        my $inlines = $class->expand($items->[2]);
        return $class->escape("$inlines\n");
    }

    sub inline {
        my $class = shift;
        my $items = shift->{items};
        my $item  = $items->[0] or return;
        $item = $class->escape($item);
        $item = Text::Hatena::AutoLink->parse($item);
        return $item;
    }

    sub escape {
        my ($self, $text) = @_;
        return $text unless $text;
        for ($text) {
            s/&/&amp;/g;
            s/</&lt;/g;
            s/>/&gt;/g;
            s/"/&quot;/g;
        }
        $text;
    }

}

warn Text::Hatena::Escaped->parse(<<EOL);
 >||
 sub test {
     <script>alert('hoge')</script>
 }
 ||<
 * <h1>test</h1>
 - <h3>foo</h3>
 - <h3>bar</h3>
 |*<h1>名前</h1>|*<h1>色</h1>|*<h1>個数</h1>|
 |<b>りんご</b>|<b>赤</b>|<b>1</b>|
 <script>alert('hoge')</script
 [http://www.hatena.ne.jp/:title=Hatena]
EOL

結果は

<div class="section">
<pre>
sub test {
    &lt;script&gt;alert('hoge')&lt;/script&gt;
}
</pre>
</div>
<div class="section">
<h3> &lt;h1&gt;test&lt;/h1&gt;</h3>
<ul>
<li> &lt;h3&gt;foo&lt;/h3&gt;</li>
<li> &lt;h3&gt;bar&lt;/h3&gt;</li>
</ul>
<table>
<tr>
<th>&lt;h1&gt;名前&lt;/h1&gt;</th>
<th>&lt;h1&gt;色&lt;/h1&gt;</th>
<th>&lt;h1&gt;個数&lt;/h1&gt;</th>
</tr>
<tr>
<td>&lt;b&gt;りんご&lt;/b&gt;</td>
<td>&lt;b&gt;赤&lt;/b&gt;</td>
<td>&lt;b&gt;1&lt;/b&gt;</td>
</tr>
</table>
<p>&lt;script&gt;alert('hoge')&lt;/script&gt;</p>
<p><a href="http://www.hatena.ne.jp/">Hatena</a></p>
</div>

こんな感じ。