Skip to content

Commit

Permalink
Implement templates.
Browse files Browse the repository at this point in the history
  • Loading branch information
cho45 committed Nov 17, 2011
1 parent c7c8560 commit 843ac93
Show file tree
Hide file tree
Showing 22 changed files with 325 additions and 159 deletions.
13 changes: 13 additions & 0 deletions Changes
@@ -1,3 +1,16 @@
2011-11-17 SATOH Hiroh <cho45@lowreal.net>

* Enable use templates:
You can specify templates in Text::Xatena#new(templates => {}).

* Imcompatible changes:
Text::Xatena#format does not take 'inline' option any more, so you
must specify it in Text::Xatena#new.

Removed Text::Xatena::Node::Section::BASE.
Removed Text::Xatena::Node::Section::BEGINNING.
Removed Text::Xatena::Node::Section::ENDOFNODE.

2011-11-16 SATOH Hiroh <cho45@lowreal.net>

* 0.13:
Expand Down
1 change: 1 addition & 0 deletions MANIFEST
Expand Up @@ -65,6 +65,7 @@ t/10_api.t
t/20_hatena_compat.t
t/30_superpre.t
t/31_superpre_attr.t
t/50_templates.t
t/80_internal.t
t/lib/Text/Xatena/Test.pm
t/lib/Text/Xatena/Test/MyInline.pm
Expand Down
1 change: 1 addition & 0 deletions Makefile.PL
Expand Up @@ -28,6 +28,7 @@ requires 'HTML::Entities';
requires 'LWP::Simple';
requires 'UNIVERSAL::require';
requires 'List::MoreUtils';
requires 'Text::MicroTemplate';

test_requires 'Encode';
test_requires 'LWP::UserAgent';
Expand Down
17 changes: 17 additions & 0 deletions README
Expand Up @@ -343,6 +343,23 @@ SYNTAX

my $thx = Text::Xatena->new(hatena_compatible => 1);

Customize templates in formatting
If you want to customize HTML, you can specify templates in
Text::Xatena#new. This is interpreted as Text::MicroTemplate.

You should reuse Text::Xatena object for performance.

my $thx = Text::Xatena->new(
templates => {
'Text::Xatena::Node::Section' => q[
<section class="level-{{= $level }}">
<h1>{{= $title }}</h1>
{{= $content }}
</section>
],
}
);

AUTHOR
cho45 <cho45@lowreal.net>

Expand Down
118 changes: 64 additions & 54 deletions lib/Text/Xatena.pm
Expand Up @@ -8,6 +8,7 @@ use Text::Xatena::LineScanner;
use Text::Xatena::Node;
use Text::Xatena::Node::Root;
use Text::Xatena::Inline;
use Text::Xatena::Util;

our $VERSION = '0.13';

Expand All @@ -27,12 +28,20 @@ our $SYNTAXES = [
sub new {
my ($class, %opts) = @_;

$opts{syntaxes} ||= $SYNTAXES;

my $self = bless {
%opts
}, $class;

$self->{syntaxes} ||= $SYNTAXES;
$self->{inline} ||= Text::Xatena::Inline->new;

if ($self->{hatena_compatible}) {
$self->{templates}->{'Text::Xatena::Node::Section'} = q[
<h{{= $level + 2 }}>{{= $title }}</h{{= $level + 2 }}>
{{= $content }}
];
}

for my $pkg (@{ $self->{syntaxes} }) {
$pkg->use or die $@;
}
Expand All @@ -41,12 +50,35 @@ sub new {
}

sub format {
my ($self, $string, %opts) = @_;
my ($self, $string) = @_;
$string =~ s{\r\n?|\n}{\n}g;
if ($opts{hatena_compatible} || $self->{hatena_compatible}) {
$self->_format_hatena_compat($string, %opts);

if ($self->{hatena_compatible}) {
no warnings "once", "redefine";
local *Text::Xatena::Node::as_html_paragraph = sub {
my ($self, $context, $text, %opts) = @_;
$text = $context->inline->format($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";
}
};

$self->_parse($string)->as_html($self);
} else {
$self->_format($string, %opts);
$self->_parse($string)->as_html($self);
}
}

Expand All @@ -59,54 +91,6 @@ sub 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) = @_;

Expand All @@ -128,6 +112,14 @@ sub _parse {
$root;
}

sub _tmpl {
my ($self, $pkg, $default, $stash) = @_;
my $tmpl = $self->{templates}->{$pkg};
my $sub = ref($tmpl) eq 'CODE' ? $tmpl : template($tmpl || $default, [ keys %$stash ]);
$self->{templates}->{$pkg} = $sub;
$sub->($stash);
}

1;
__END__
Expand Down Expand Up @@ -505,6 +497,24 @@ But Xatena supports Hatena::Diary compatible mode, you can change the behavior w
my $thx = Text::Xatena->new(hatena_compatible => 1);
=head2 Customize templates in formatting
If you want to customize HTML, you can specify templates in Text::Xatena#new.
This is interpreted as L<Text::MicroTemplate>.
You should reuse Text::Xatena object for performance.
my $thx = Text::Xatena->new(
templates => {
'Text::Xatena::Node::Section' => q[
<section class="level-{{= $level }}">
<h1>{{= $title }}</h1>
{{= $content }}
</section>
],
}
);
=head1 AUTHOR
cho45 E<lt>cho45@lowreal.netE<gt>
Expand Down
1 change: 1 addition & 0 deletions lib/Text/Xatena/Inline/Base.pm
Expand Up @@ -47,6 +47,7 @@ sub new {

sub format {
my ($self, $text) = @_;
$text =~ s{^\n}{}g;
my $re = join("|", map { $_->{regexp} } @{ $self->inlines });
$text =~ s{($re)}{$self->_format($1)}eg;
$text;
Expand Down
21 changes: 8 additions & 13 deletions lib/Text/Xatena/Node.pm
Expand Up @@ -6,6 +6,8 @@ use overload
'@{}' => \&children,
fallback => 1;

use Text::Xatena::Util;

sub new {
my ($class, $children) = @_;
bless {
Expand All @@ -15,36 +17,30 @@ sub new {

sub children { $_[0]->{children} };

sub inline {
my ($self, $text, %opts) = @_;
$text =~ s{^\n}{}g;
$text = $opts{inline}->format($text);
}

sub as_html {
my ($self, %opts) = @_;
my ($self, $context, %opts) = @_;
my $ret = "";

my $children = $_[0]->{children};
my @texts;
for my $child (@$children) {
if (ref($child)) {
$ret .= $self->as_html_paragraph(join("\n", @texts), %opts) if join '', @texts;
$ret .= $self->as_html_paragraph($context, join("\n", @texts), %opts) if join '', @texts;
@texts = ();
$ret .= $child->as_html(%opts);
$ret .= $child->as_html($context, %opts);
} else {
push @texts, $child;
}
}
$ret .= $self->as_html_paragraph(join("\n", @texts), %opts) if join '', @texts;
$ret .= $self->as_html_paragraph($context, join("\n", @texts), %opts) if join '', @texts;

$ret;
}

## NOT COMPATIBLE WITH Hatena Syntax: Auto br insertation as \n
sub as_html_paragraph {
my ($self, $text, %opts) = @_;
$text = $self->inline($text, %opts);
my ($self, $context, $text, %opts) = @_;
$text = $context->inline->format($text, $context);

if ($opts{stopp}) {
$text;
Expand All @@ -62,7 +58,6 @@ sub as_html_paragraph {
}
}


1;
__END__
Expand Down
29 changes: 17 additions & 12 deletions lib/Text/Xatena/Node/Blockquote.pm
Expand Up @@ -27,18 +27,23 @@ sub parse {
}

sub as_html {
my ($self, %opts) = @_;
if ($self->{beginning}->[1]) {
my $url = $self->{beginning}->[1];
sprintf("<blockquote cite=\"%s\">\n%s\n<cite><a href=\"%s\">%s</a></cite>\n</blockquote>\n",
$url,
$self->SUPER::as_html(%opts),
$url,
$url,
);
} else {
"<blockquote>\n" . $self->SUPER::as_html(%opts) . "</blockquote>\n";
}
my ($self, $context, %opts) = @_;

$context->_tmpl(__PACKAGE__, q[
? if ($cite) {
<blockquote cite="{{= $cite }}">
{{= $content }}
<cite><a href="{{= $cite }}">{{= $cite }}</a></cite>
</blockquote>
? } else {
<blockquote>
{{= $content }}
</blockquote>
? }
], {
cite => $self->{beginning}->[1],
content => $self->SUPER::as_html($context, %opts),
});
}

1;
Expand Down
2 changes: 1 addition & 1 deletion lib/Text/Xatena/Node/Comment.pm
Expand Up @@ -24,7 +24,7 @@ sub parse {
}

sub as_html {
my ($self, %opts) = @_;
my ($self, $context, %opts) = @_;
'<!-- -->';
}

Expand Down
31 changes: 15 additions & 16 deletions lib/Text/Xatena/Node/DefinitionList.pm
Expand Up @@ -24,26 +24,26 @@ sub parse {

## NOT COMPATIBLE WITH Hatena Syntax
sub as_struct {
my ($self) = @_;
my ($self, $context) = @_;
my $ret = [];

my $children = $self->children;

for my $line (@$children) {
if (my ($description) = ($line =~ /^::(.+)/)) {
push @$ret, +{
name => 'dd',
children => [ $description ],
name => 'dd',
content => $context->inline->format($description),
};
} else {
my ($title, $description) = ($line =~ /^:([^:]+)(?::(.*))?$/);
push @$ret, +{
name => 'dt',
children => [ $title ],
content => $context->inline->format($title),
};
push @$ret, +{
name => 'dd',
children => [ $description ],
content => $context->inline->format($description),
} if $description;
}
}
Expand All @@ -52,18 +52,17 @@ sub as_struct {
}

sub as_html {
my ($self, %opts) = @_;
my ($self, $context, %opts) = @_;

my $ret = "<dl>\n";
for my $e (@{ $self->as_struct }) {
$ret .= sprintf("<%s>%s</%s>\n",
$e->{name},
$self->inline(join("", @{ $e->{children} }), %opts),
$e->{name}
);
}
$ret .= "</dl>\n";
$ret;
$context->_tmpl(__PACKAGE__, q[
<dl>
? for (@$items) {
<{{= $_->{name} }}>{{= $_->{content} }}</{{= $_->{name} }}>
? }
</dl>
], {
items => $self->as_struct($context),
});
}


Expand Down

0 comments on commit 843ac93

Please sign in to comment.