| blib/lib/Text/Xatena.pm | |||
|---|---|---|---|
| Criterion | Covered | Total | % |
| statement | 78 | 79 | 98.7 |
| branch | 19 | 22 | 86.3 |
| condition | 6 | 8 | 75.0 |
| subroutine | 15 | 15 | 100.0 |
| pod | 1 | 3 | 33.3 |
| total | 119 | 127 | 93.7 |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 1 | package Text::Xatena; | ||||||
| 2 | |||||||
| 3 | 20 | 20 | 808703 | use strict; | |||
| 20 | 50 | ||||||
| 20 | 717 | ||||||
| 4 | 20 | 20 | 102 | use warnings; | |||
| 20 | 38 | ||||||
| 20 | 529 | ||||||
| 5 | 20 | 20 | 3495 | use UNIVERSAL::require; | |||
| 20 | 6744 | ||||||
| 20 | 191 | ||||||
| 6 | |||||||
| 7 | 20 | 20 | 8630 | use Text::Xatena::LineScanner; | |||
| 20 | 59 | ||||||
| 20 | 223 | ||||||
| 8 | 20 | 20 | 8086 | use Text::Xatena::Node; | |||
| 20 | 67 | ||||||
| 20 | 265 | ||||||
| 9 | 20 | 20 | 10640 | use Text::Xatena::Node::Root; | |||
| 20 | 53 | ||||||
| 20 | 161 | ||||||
| 10 | 20 | 20 | 7915 | use Text::Xatena::Inline; | |||
| 20 | 61 | ||||||
| 20 | 157 | ||||||
| 11 | 20 | 20 | 150 | use Text::Xatena::Util; | |||
| 20 | 41 | ||||||
| 20 | 172 | ||||||
| 12 | |||||||
| 13 | our $VERSION = '0.18'; | ||||||
| 14 | |||||||
| 15 | our $SYNTAXES = [ | ||||||
| 16 | 'Text::Xatena::Node::SeeMore', | ||||||
| 17 | 'Text::Xatena::Node::SuperPre', | ||||||
| 18 | 'Text::Xatena::Node::StopP', | ||||||
| 19 | 'Text::Xatena::Node::Blockquote', | ||||||
| 20 | 'Text::Xatena::Node::Pre', | ||||||
| 21 | 'Text::Xatena::Node::List', | ||||||
| 22 | 'Text::Xatena::Node::DefinitionList', | ||||||
| 23 | 'Text::Xatena::Node::Table', | ||||||
| 24 | 'Text::Xatena::Node::Section', | ||||||
| 25 | 'Text::Xatena::Node::Comment', | ||||||
| 26 | ]; | ||||||
| 27 | |||||||
| 28 | sub new { | ||||||
| 29 | 103 | 103 | 0 | 1655 | my ($class, %opts) = @_; | ||
| 30 | |||||||
| 31 | 103 | 410 | my $self = bless { %opts }, $class; | ||||
| 32 | |||||||
| 33 | 103 | 100 | 658 | $self->{templates} ||= {}; | |||
| 34 | 2 | 50 | 9 | $self->{templates} = { | |||
| 35 | map { | ||||||
| 36 | 103 | 360 | my $pkg = $_ =~ /::/ ? $_ : "Text::Xatena::Node::$_"; | ||||
| 37 | 2 | 9 | $pkg => $self->{templates}->{$_}; | ||||
| 38 | } | ||||||
| 39 | 103 | 161 | keys %{ $self->{templates} } | ||||
| 40 | }; | ||||||
| 41 | |||||||
| 42 | 1011 | 100 | 3080 | $self->{syntaxes} = [ | |||
| 43 | map { | ||||||
| 44 | 103 | 100 | 504 | my $pkg = $_ =~ /::/ ? $_ : "Text::Xatena::Node::$_"; | |||
| 45 | 1011 | 50 | 6119 | $pkg->use or die $@; | |||
| 46 | 1011 | 7604 | $pkg; | ||||
| 47 | } | ||||||
| 48 | 103 | 227 | @{ $opts{syntaxes} || $SYNTAXES } | ||||
| 49 | ]; | ||||||
| 50 | |||||||
| 51 | 103 | 66 | 1298 | $self->{inline} ||= Text::Xatena::Inline->new; | |||
| 52 | |||||||
| 53 | 103 | 376 | $self; | ||||
| 54 | } | ||||||
| 55 | |||||||
| 56 | sub format { | ||||||
| 57 | 107 | 107 | 0 | 601 | my ($self, $string, %opts) = @_; | ||
| 58 | 107 | 1003 | $string =~ s{\r\n?|\n}{\n}g; | ||||
| 59 | |||||||
| 60 | 107 | 100 | 337 | $self->inline($opts{inline}) if $opts{inline}; | |||
| 61 | |||||||
| 62 | 107 | 100 | 309 | if ($self->{hatena_compatible}) { | |||
| 63 | 9 | 28 | $self->{templates}->{'Text::Xatena::Node::Section'} = q[ | ||||
| 64 | |
||||||
| 65 | {{= $content }} | ||||||
| 66 | ]; | ||||||
| 67 | |||||||
| 68 | 20 | 20 | 9128 | no warnings "once", "redefine"; | |||
| 20 | 47 | ||||||
| 20 | 11140 | ||||||
| 69 | local *Text::Xatena::Node::as_html_paragraph = sub { | ||||||
| 70 | 14 | 14 | 33 | my ($self, $context, $text, %opts) = @_; | |||
| 71 | 14 | 33 | $text = $context->inline->format($text, %opts); | ||||
| 72 | |||||||
| 73 | 14 | 38 | $text =~ s{\n$}{}g; | ||||
| 74 | 14 | 50 | 101 | if ($opts{stopp}) { | |||
| 75 | 0 | 0 | $text; | ||||
| 76 | } else { | ||||||
| 77 | " " . join("", |
||||||
| 78 | map { | ||||||
| 79 | 14 | 100 | 47 | if (/^(\n+)$/) { | |||
| 26 | 61 | ||||||
| 80 | 6 | 29 | "" . (" \n" x (length($1) - 2)) . " "; |
||||
| 81 | } else { | ||||||
| 82 | 20 | 94 | $_; | ||||
| 83 | } | ||||||
| 84 | } | ||||||
| 85 | split(/(\n+)/, $text) | ||||||
| 86 | ) . "\n"; | ||||||
| 87 | } | ||||||
| 88 | 9 | 71 | }; | ||||
| 89 | |||||||
| 90 | 9 | 31 | $self->_parse($string)->as_html($self); | ||||
| 91 | } else { | ||||||
| 92 | 98 | 306 | $self->_parse($string)->as_html($self); | ||||
| 93 | } | ||||||
| 94 | } | ||||||
| 95 | |||||||
| 96 | sub inline { | ||||||
| 97 | 250 | 250 | 1 | 343 | my ($self, $new) = @_; | ||
| 98 | 250 | 100 | 567 | if (@_ > 1) { | |||
| 99 | 1 | 4 | $self->{inline} = $new; | ||||
| 100 | } else { | ||||||
| 101 | 249 | 2189 | $self->{inline}; | ||||
| 102 | } | ||||||
| 103 | } | ||||||
| 104 | |||||||
| 105 | sub _parse { | ||||||
| 106 | 120 | 120 | 367 | my ($self, $string) = @_; | |||
| 107 | |||||||
| 108 | 120 | 177 | my @syntaxes = @{ $self->{syntaxes} }; | ||||
| 120 | 599 | ||||||
| 109 | 120 | 817 | my $s = Text::Xatena::LineScanner->new($string); | ||||
| 110 | 120 | 800 | my $root = Text::Xatena::Node::Root->new ; | ||||
| 111 | 120 | 284 | my $stack = [ $root ]; | ||||
| 112 | 120 | 450 | loop: until ($s->eos) { | ||||
| 113 | 388 | 662 | my $parent = $stack->[-1]; | ||||
| 114 | |||||||
| 115 | 388 | 634 | for my $pkg (@syntaxes) { | ||||
| 116 | 3286 | 100 | 14806 | $pkg->parse($s, $parent, $stack) and next loop; | |||
| 117 | } | ||||||
| 118 | |||||||
| 119 | # plain lines | ||||||
| 120 | 250 | 7957 | push @$parent, $s->next; | ||||
| 121 | } | ||||||
| 122 | |||||||
| 123 | 120 | 1424 | $root; | ||||
| 124 | } | ||||||
| 125 | |||||||
| 126 | sub _tmpl { | ||||||
| 127 | 100 | 100 | 223 | my ($self, $pkg, $default, $stash) = @_; | |||
| 128 | 100 | 207 | my $tmpl = $self->{templates}->{$pkg}; | ||||
| 129 | 100 | 100 | 66 | 749 | my $sub = ref($tmpl) eq 'CODE' ? $tmpl : template($tmpl || $default, [ keys %$stash ]); | ||
| 130 | 100 | 342 | $self->{templates}->{$pkg} = $sub; | ||||
| 131 | 100 | 1811 | $sub->($stash); | ||||
| 132 | } | ||||||
| 133 | |||||||
| 134 | 1; | ||||||
| 135 | __END__ |