Text-Hatena
view release on metacpan or search on metacpan
lib/Text/Hatena.pm view on Meta::CPAN
package Text::Hatena;
use strict;
use warnings;
use Carp;
use base qw(Class::Data::Inheritable);
use vars qw($VERSION);
use Parse::RecDescent;
use Text::Hatena::AutoLink;
$VERSION = '0.20';
my ($parser, $syntax);
__PACKAGE__->mk_classdata('syntax');
#$::RD_HINT = 1;
#$::RD_TRACE = 1;
#$::RD_WARN = undef;
$Parse::RecDescent::skip = '';
$syntax = q(
body : section(s)
section : h3(?) block(s?)
# Block Elements
block : h5
| h4
| blockquote
| dl
| list
| super_pre
| pre
| table
| cdata
| p
h3 : "\n*" inline(s)
h4 : "\n**" inline(s)
h5 : "\n***" inline(s)
blockquote : "\n>" http(?) ">" block(s) "\n<<" ..."\n"
dl : dl_item(s)
dl_item : "\n:" inline[term => ':'](s) ':' inline(s)
list : list_item[level => $arg{level} || 1](s)
list_item : "\n" /[+-]{$arg{level}}/ inline(s) list[level => $arg{level} + 1](?)
super_pre : /\n>\|(\w*)\|/o text_line(s) "\n||<" ..."\n"
text_line : ...!"\n||<\n" "\n" /[^\n]*/o
pre : "\n>|" pre_line(s) "\n|<" ..."\n"
pre_line : ...!"\n|<" "\n" inline(s?)
table : table_row(s)
table_row : "\n|" td(s /\|/) '|'
td : /\*?/o inline[term => '\|'](s)
cdata : "\n><" /.+?(?=><\n)/so "><" ..."\n"
p : ...!p_terminal "\n" inline(s?)
p_terminal : h3 | "\n<<\n"
# Inline Elements
inline : /[^\n$arg{term}]+/
http : /https?:\/\/[A-Za-z0-9~\/._\?\&=\-%#\+:\;,\@\']+(?::title=[^\]]+)?/
);
sub parse {
my $class = shift;
my $text = shift or return;
$text =~ s/\r//g;
$text = "\n" . $text unless $text =~ /^\n/;
$text .= "\n" unless $text =~ /\n$/;
my $node = shift || 'body';
my $html = $class->parser->$node($text);
# warn $html;
return $html;
}
sub parser {
my $class = shift;
unless (defined $parser) {
$::RD_AUTOACTION = q|my $method = shift @item;| .
$class . q|->$method({items => \@item});|;
$parser = Parse::RecDescent->new($syntax);
if ($class->syntax) {
$parser->Replace($class->syntax);
}
}
return $parser;
}
sub expand {
my $class = shift;
my $array = shift or return;
ref($array) eq 'ARRAY' or return;
my $ret = '';
while (my $item = shift @$array) {
if (ref($item) eq 'ARRAY') {
my $c = $class->expand($item);
$ret .= $c if $c;
} else {
$ret .= $item if $item;
}
}
return $ret;
}
# Nodes
# Block Nodes
sub abstract {
my $class = shift;
my $items = shift->{items};
return $class->expand($items);
}
*body = \&abstract;
*block = \&abstract;
*line = \&abstract;
lib/Text/Hatena.pm view on Meta::CPAN
$tag ||= $li =~ /^\-/ ? 'ul' : 'ol';
$li =~ s/^[+-]+//;
$list .= $li;
}
return "<$tag>\n$list</$tag>\n";
}
sub list_item {
my $class = shift;
my $items = shift->{items};
my $li = $class->expand($items->[2]);
my $sl = $class->expand($items->[3]) || '';
$sl = "\n" . $sl if $sl;
return $items->[1] . "<li>$li$sl</li>\n";
}
sub super_pre {
my $class = shift;
my $items = shift->{items};
my $filter = $1 || ''; # todo
my $texts = $class->expand($items->[1]);
return "<pre>\n$texts</pre>\n";
}
sub pre {
my $class = shift;
my $items = shift->{items};
my $lines = $class->expand($items->[1]);
return "<pre>\n$lines</pre>\n";
}
sub pre_line {
my $class = shift;
my $items = shift->{items};
my $inlines = $class->expand($items->[2]);
return "$inlines\n";
}
sub table {
my $class = shift;
my $items = shift->{items};
my $trs = $class->expand($items->[0]);
return "<table>\n$trs</table>\n";
}
sub table_row { # we can't use tr!
my $class = shift;
my $items = shift->{items};
my $tds = $class->expand($items->[1]);
return "<tr>\n$tds</tr>\n";
}
sub td {
my $class = shift;
my $items = shift->{items};
my $tag = $items->[0] ? 'th' : 'td';
my $inlines = $class->expand($items->[1]);
return "<$tag>$inlines</$tag>\n";
}
sub cdata {
my $class = shift;
my $items = shift->{items};
my $data = $items->[1];
return "<$data>\n";
}
sub p {
my $class = shift;
my $items = shift->{items};
my $inlines = $class->expand($items->[2]);
return $inlines ? "<p>$inlines</p>\n" : "\n";
}
sub text_line {
my $class = shift;
my $text = shift->{items}->[2];
return "$text\n";
}
# Inline Nodes
sub inline {
my $class = shift;
my $items = shift->{items};
my $item = $items->[0] or return;
$item = Text::Hatena::AutoLink->parse($item);
return $item;
}
sub http {
my $class = shift;
my $items = shift->{items};
my $item = $items->[0] or return;
$item =~ s/:title=([^\]]+)$//;
my $title = $1 || $item;
return {
cite => $item,
title => $title,
}
}
1;
__END__
=head1 NAME
Text::Hatena - Perl extension for formatting text with Hatena Style.
=head1 SYNOPSIS
use Text::Hatena;
my $html = Text::Hatena->parse($text);
=head1 DESCRIPTION
Text::Hatena parses text with Hatena Style and generates html string.
Hatena Style is a set of text syntax which is originally used in
Hatena Diary (http://d.hatena.ne.jp/).
( run in 1.450 second using v1.01-cache-2.11-cpan-6aa56a78535 )