| Text-Xatena documentation | Contained in the Text-Xatena distribution. |
Text::Xatena - Text-to-HTML converter with Xatena syntax.
use Text::Xatena;
my $thx = Text::Xatena->new;
$thx->format($string);
# with some aggressive functions
$thx->format($string,
inline => Text::Xatena::Inline::Aggressive->new(cache => Cache::MemoryCache->new)
);
Customizing inline formatting rule
Text::Xatena->new->format($string,
inline => MyInline->new
);
package MyInline;
use strict;
use warnings;
use Text::Xatena::Inline::Base -Base;
match qr{\@([a-z0-9]+)} => sub {
my ($self, $twitter_id) = @_;
sprintf('<a href="http://twitter.com/%s">@%s</a>',
$twitter_id,
$twitter_id,
);
};
1;
Text::Xatena is a text-to-html converter.
Text::Xatena is comfortably to writing usual diary and blog, especially for programmers, writers treating long text.
Xatena syntax is similar to Hatena syntax (implemented as Text::Hatena), but is independent from Hatena services and has more expandability.
Most block level syntax notations are supported and more compatibility with Hatena::Diary than Text::Hatena 0.20.
And don't support rare syntax or what isn't to be done of syntax formatter. (for example, linking keywords)
Basically, Xatena convert single line breaks to <br/> and
double line breaks to <p> element except "Stop P" syntax.
fooo bar baz
is converted to following:
<p>fooo<br/>bar</p> <p>baz</p>
>> quoted text foobar <<
is converted to following:
<blockquote> <p>quoted text</p> <p>foobar</p> </blockquote>
>http://example.com/> foobar <<
is converted to following:
<blockquote cite="http://example.com/">
<p>quote</p>
<cite><a href="http://example.com/">http://example.com/</a></cite>
</blockquote>
>| pre <a href="">formatted</a> |<
is converted to following:
<pre> pre <a href="">formatted</a> </pre>
>|| super pre <a> ||<
is converted to following:
<pre> super pre <a> </pre>
>|perl| use Text::Xatena; ||<
is converted to following:
<pre class="code lang-perl"> use Text::Xatena; </pre>
Stop insert p or br.
><blockquote> <p> hogehoge br </p> </blockquote><
is converted to following:
<blockquote> <p> hogehoge br </p> </blockquote><
><ins>< foobar ></ins><
is convert with auto inserting p to
<ins> <p>foobar</p> </ins>
Create structured sections by * following heading.
* head1 foobar ** head2 *** head3
is converted to following:
<div class="section">
<h3>head1</h3>
<p>foobar</p>
<div class="section">
<h4>head2</h4>
<div class="section">
<h5>head3</h5>
</div>
</div>
</div>
- ul - ul -- ul -- ul --- ul - ul
is converted to following:
<ul>
<li>ul</li>
<li>ul</li>
<li>
<ul>
<li>ul</li>
<li>ul</li>
<li>
<ul>
<li>ul</li>
</ul>
</li>
</ul>
</li>
<li>ul</li>
</ul>
+ ol + ol ++ ol ++ ol +++ ol + ol
is converted to following:
<ol>
<li>ol</li>
<li>ol</li>
<li>
<ol>
<li>ol</li>
<li>ol</li>
<li>
<ol>
<li>ol</li>
</ol>
</li>
</ol>
</li>
<li>ol</li>
</ol>
- ul - ul -+ ol -+ ol -+ ol - ul
:definition:description :definition:description
is converted to following:
<dl>
<dt>definition</dt>
<dd>description</dd>
<dt>definition</dt>
<dd>description</dd>
</dl>
This is incompatible syntax with Hatena::Diary
:definition: :: description :definition: :: description
|*foo|*bar|*baz| |test|test|test| |test|test|test|
is converted to following:
<table>
<tr>
<th>foo</th>
<th>bar</th>
<th>baz</th>
</tr>
<tr>
<td>test</td>
<td>test</td>
<td>test</td>
</tr>
<tr>
<td>test</td>
<td>test</td>
<td>test</td>
</tr>
</table>
http://example.com/ ftp://example.com/ mailto:cho45@lowreal.net [http://example.com/] # using Xatena::Inline::Aggressive [http://example.com/] [http://example.com/:title] # auto retrieving from url [http://example.com/:title=Foobar] [http://example.com/:barcode] # show qrcode with google chart API
[]http://example.com/[]
Perl((most famous light weight language))
is converted to
Perl<a href="#fn1">*1</a>
and footnote object is available in inline object, so you will do expand it like following:
my $thx = Text::Xatena->new;
my $inline = Text::Xatena::Inline->new;
my $formatted = $thx->format('aaa((foobar)) bbb((barbaz))', inline => $inline);
my $out = '';
$out .= '<div class="body">';
$out .= $formatted;
$out .= '</div>';
$out .= '<div class="notes">';
for my $footnote (@{ $inline->footnotes }) {
$out .= sprintf('<div class="footnote" id="#fn%d">*%d: %s</div>',
$footnote->{number},
$footnote->{number},
$footnote->{note},
);
}
$out .= '</div>';
Some default behaviors of Xatena syntax are different from Hatena::Diary syntax.
Big differences:
<p> block but Xatena converts it to <br/>.<hn> element but Xatena converts it to <div class="section">But Xatena supports Hatena::Diary compatible mode, you can change the behavior with a option.
my $thx = Text::Xatena->new(hatena_compatible => 1);
cho45 <cho45@lowreal.net>
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
| Text-Xatena documentation | Contained in the Text-Xatena distribution. |
package Text::Xatena; use strict; use warnings; use UNIVERSAL::require; use Text::Xatena::LineScanner; use Text::Xatena::Node; use Text::Xatena::Node::Root; use Text::Xatena::Inline; our $VERSION = '0.10'; our $SYNTAXES = [ 'Text::Xatena::Node::SeeMore', 'Text::Xatena::Node::SuperPre', 'Text::Xatena::Node::StopP', 'Text::Xatena::Node::Blockquote', 'Text::Xatena::Node::Pre', 'Text::Xatena::Node::List', 'Text::Xatena::Node::DefinitionList', 'Text::Xatena::Node::Table', 'Text::Xatena::Node::Section', 'Text::Xatena::Node::Comment', ]; sub new { my ($class, %opts) = @_; $opts{syntaxes} ||= $SYNTAXES; my $self = bless { %opts }, $class; for my $pkg (@{ $self->{syntaxes} }) { $pkg->use or die $@; } $self; } sub format { my ($self, $string, %opts) = @_; $string =~ s{\r\n?|\n}{\n}g; if ($opts{hatena_compatible} || $self->{hatena_compatible}) { $self->_format_hatena_compat($string, %opts); } else { $self->_format($string, %opts); } } sub inline { my ($self, $new) = @_; if (@_ > 1) { $self->{inline} = $new; } else { $self->{inline}; } } sub _format { my ($self, $string, %opts) = @_; $opts{inline} ||= do { $self->{inline} ||= Text::Xatena::Inline->new; }; $self->_parse($string)->as_html( %opts ); } sub _format_hatena_compat { my ($self, $string, %opts) = @_; no warnings "once", "redefine"; local $Text::Xatena::Node::Section::BEGINNING = ""; local $Text::Xatena::Node::Section::ENDOFNODE = ""; local *Text::Xatena::Node::as_html_paragraph = sub { my ($self, $text, %opts) = @_; $text = $self->inline($text, %opts); $text =~ s{\n$}{}g; if ($opts{stopp}) { $text; } else { "<p>" . join("", map { if (/^(\n+)$/) { "</p>" . ("<br />\n" x (length($1) - 2)) . "<p>"; } else { $_; } } split(/(\n+)/, $text) ) . "</p>\n"; } }; $opts{inline} ||= do { $self->{inline} ||= Text::Xatena::Inline->new; }; $self->_parse($string)->as_html( %opts ); } sub _parse { my ($self, $string) = @_; my @syntaxes = @{ $self->{syntaxes} }; my $s = Text::Xatena::LineScanner->new($string); my $root = Text::Xatena::Node::Root->new ; my $stack = [ $root ]; loop: until ($s->eos) { my $parent = $stack->[-1]; for my $pkg (@syntaxes) { $pkg->parse($s, $parent, $stack) and next loop; } # plain lines push @$parent, $s->next; } $root; } 1; __END__