File Coverage

blib/lib/Text/Md2Inao/Builder/Inao.pm
Criterion Covered Total %
statement 42 42 100.0
branch 6 8 75.0
condition n/a
subroutine 11 11 100.0
pod 0 2 0.0
total 59 63 93.6


line stmt bran cond sub pod time code
1             package Text::Md2Inao::Builder::Inao;
2 29     29   164 use utf8;
  29         56  
  29         243  
3 29     29   828 use strict;
  29         195  
  29         7375  
4 29     29   137 use warnings;
  29         46  
  29         1105  
5              
6 29     29   163 use List::Util qw/max/;
  29         50  
  29         4123  
7 29     29   28688 use Tie::IxHash;
  29         2538523  
  29         885  
8              
9 29     29   18031 use Text::Md2Inao::Logger;
  29         450  
  29         1920  
10 29     29   20293 use Text::Md2Inao::Util;
  29         116  
  29         403  
11              
12 29     29   3791 use parent qw/Text::Md2Inao::Builder/;
  29         68  
  29         267  
13              
14 29     29   20271 use Text::Md2Inao::Builder::DSL;
  29         85  
  29         107005  
15              
16             tie my %meta2label, "Tie::IxHash",
17                 title => 'タイトル',
18                 subtitle => 'キャッチ',
19                 author => '著者',
20                 'author(romaji)' => '著者(ローマ字)',
21                 supervisor => '監修',
22                 'supervisor(romaji)' => '監修(ローマ字)',
23                 url => 'URL',
24                 mail => 'mail',
25                 github => 'Github',
26                 twitter => 'Twitter',
27             ;
28              
29             sub prepend_metadata {
30 94     94 0 335     my ($self, $c, $text) = @_;
31 94 100       340     if ($c->metadata) {
32 1         7         my @lines;
33 1 50       4         if (my $chapter = $c->metadata->{chapter}) {
34 1         12             push @lines, sprintf "章番号:第%d章", $chapter;
35                     }
36              
37 1 50       4         if (my $serial = $c->metadata->{serial}) {
38 1         19             push @lines, sprintf "連載回数:第%d回", $serial;
39                     }
40              
41 1         10         for (keys %meta2label) {
42 10 100       152             if (my $value = $c->metadata->{$_}) {
43 8         75                 push @lines, sprintf "%s:%s", $meta2label{$_}, $value;
44                         }
45                     }
46 1         17         $text = join "\n", @lines, $text;
47                 }
48 94         1723     return $text;
49             }
50              
51             sub after_filter {
52 94     94 0 581     my ($self, $c, $text) = @_;
53 94         320     $text = $self->prepend_metadata($c, $text);
54 94         494     return $self->SUPER::after_filter($c, $text);
55             }
56              
57             case default => sub {
58                 my ($c, $h) = @_;
59                 fallback_to_html($h);
60             };
61              
62             case text => sub {
63                 my ($c, $text) = @_;
64                 if ($text =~ m!\(注:! or $c->in_footnote) {
65                     $text = replace_note_parenthesis($c, $text, '注');
66                 }
67              
68             # 各行の余計な先頭空白を取り除く (全角は字下げ指定なので残す)
69                 $text =~ s/^[ ]+//mg;
70              
71             # 改行を取り除く
72                 $text =~ s/(\n|\r)//g;
73             # キャプション
74                 if ($text =~ s!^●(.+?)::(.+)!●$1\t$2!) {
75                     $text =~ s!\[(.+)\]$!\n$1!;
76                 }
77             # リストスタイル文字の変換
78                 $text = to_list_style($text);
79                 return $text;
80             };
81              
82             case a => sub {
83                 my ($c, $h) = @_;
84                 my $url = $h->attr('href');
85                 my $title = $h->as_trimmed_text;
86                 if ($url and $title) {
87                     return sprintf "%s◆注/◆%s◆/注◆", $title, $url;
88                 } else {
89                     return fallback_to_html($h);
90                 }
91             };
92              
93             case blockquote => sub {
94                 my ($c, $h) = @_;
95              
96                 $c->in_quote_block(1);
97                 my $blockquote = $c->parse_element($h);
98                 $c->in_quote_block(0);
99              
100                 chomp $blockquote;
101              
102                 return <<EOF;
103             ◆quote/◆
104             $blockquote
105             ◆/quote◆
106             EOF
107             };
108              
109             case code => sub {
110                 my ($c, $h) = @_;
111                 sprintf(
112                     "◆cmd/◆%s◆/cmd◆" ,
113                     $h->as_trimmed_text
114                 );
115             };
116              
117             case div => sub {
118                 my ($c, $h) = @_;
119                 my $out = '';
120              
121                 if ($h->attr('class') eq 'column') {
122                     $c->in_column(1);
123              
124             # HTMLとして取得してcolumn自信のdivタグを削除
125                     my $html = $h->as_HTML('');
126                     $html =~ s/^<div.+?>//;
127                     $html =~ s/<\/div>$//;
128              
129                     $out .= "◆column/◆\n";
130                     $out .= $c->parse_markdown($html);
131                     $out .= "◆/column◆\n";
132              
133                     $c->in_column(0);
134                 } else {
135                     $out .= fallback_to_html($h);
136                 }
137              
138                 return $out;
139             };
140              
141             case dl => sub {
142                 my ($c, $h) = @_;
143                 my $out = '';
144                 for ($h->descendants) {
145                     if ($_->tag eq 'dt') {
146                         $out .= sprintf "・%s\n", $c->parse_element($_);
147                     } elsif ($_->tag eq 'dd') {
148                         $out .= sprintf "・・%s\n", $c->parse_element($_);
149                     }
150                 }
151                 return $out;
152             };
153              
154             case em => sub {
155                 my ($c, $h) = @_;
156                 my $ret;
157                 $ret .= $c->use_special_italic ? '◆i-j/◆' : '◆i/◆';
158                 $ret .= $h->as_trimmed_text;
159                 $ret .= $c->use_special_italic ? '◆/i-j◆' : '◆/i◆';
160                 return $ret;
161             };
162              
163             case "h1, h2, h3, h4, h5" => sub {
164                 my ($c, $h) = @_;
165                 my $out = '';
166                 if ($h->tag =~ /^h(\d+)$/) {
167                     my $level = $1;
168                     $out .= '■' x $level;
169                     $out .= $h->as_trimmed_text;
170                     $out .= "\n";
171                 }
172                 return $out;
173             };
174              
175             case img => sub {
176                 my ($c, $h) = @_;
177                 $c->{img_number} += 1;
178                 return sprintf (
179                     "●図%d\t%s\n%s\n",
180                     $c->{img_number},
181                     $h->attr('alt') || $h->attr('title'),
182                     $h->attr('src')
183                 );
184             };
185              
186             case kbd => sub {
187                 my ($c, $h) = @_;
188                 sprintf "%s▲" ,$h->as_trimmed_text;
189             };
190              
191             case ol => sub {
192                 my ($c, $h) = @_;
193                 my $out = '';
194                 my $list_style = $h->attr('class') || $c->default_list;
195                 my $s = substr $list_style, 0, 1;
196                 my $i = 0;
197                 for my $list ($h->find('li')) {
198                     $out .= to_list_style((sprintf '(%s%d)', $s, ++$i) . $c->parse_element($list)) . "\n";
199                 }
200                 return $out;
201             };
202              
203             case p => sub {
204                 my ($c, $h) = @_;
205                 my $p = $c->parse_element($h);
206                 if ($p !~ /^[\s ]+$/) {
207                     return "$p\n";
208                 }
209             };
210              
211             case pre => sub {
212                 my ($c, $h) = @_;
213                 $c->in_code_block(1);
214              
215                 my $code = $h->find('code');
216                 my $text = $code ? $code->as_text : '';
217              
218                 my $list_label = 'list';
219                 my $comment_label = 'comment';
220              
221             # キャプション
222                 $text =~ s!●(.+?)::(.+)!●$1\t$2!g;
223              
224             # 「!!! cmd」で始まるコードブロックはコマンドライン(黒背景)
225                 if ($text =~ /!!!(\s+)?cmd/) {
226                     $text =~ s/.+?\n//;
227                     $list_label .= '-white';
228                     $comment_label .= '-white';
229                 }
230              
231             # リストスタイル
232                 $text = to_list_style($text);
233              
234             # 文字数カウント
235                 my $max = max(map { visual_length($_) } split /\r?\n/, $text);
236                 if ($text =~ /^●/) {
237                     if ($max > $c->max_list_length) {
238                         log warn => "リストは" . $c->max_list_length . "文字まで!(現在${max}使用):\n$text\n\n";
239                     }
240                 }
241                 else {
242                     if ($max > $c->max_inline_list_length) {
243                         log warn => "本文埋め込みリストは" . $c->max_inline_list_length . "文字まで!(現在${max}使用):\n$text\n\n";
244                     }
245                 }
246              
247             # コード内コメント
248             # my $in_footnote;
249                 if ($text =~ m!\(注:! or $c->in_footnote) {
250                     $text = replace_note_parenthesis($c, $text, $comment_label);
251                 }
252              
253             # コード内強調
254                 $text =~ s!\*\*(.+?)\*\*!◆cmd-b/◆$1◆/cmd-b◆!g;
255              
256             # コード内イタリック
257                 $text =~ s!\___(.+?)\___!◆i-j/◆$1◆/i-j◆!g;
258                 chomp $text;
259              
260                 $c->in_code_block(0);
261              
262                 return <<EOF;
263             ◆$list_label/◆
264             $text
265             ◆/$list_label◆
266             EOF
267             };
268              
269             case span => sub {
270                 my ($c, $h) = @_;
271                 if ($h->attr('class') eq 'red') {
272                     return sprintf "◆red/◆%s◆/red◆", $h->as_trimmed_text;
273                 }
274                 elsif ($h->attr('class') eq 'ruby') {
275                     my $ruby = $h->as_trimmed_text;
276                     $ruby =~ s!(.+)\((.+)\)!◆ルビ/◆$1◆$2◆/ルビ◆!;
277                     return $ruby;
278                 }
279                 elsif ($h->attr('class') eq 'symbol') {
280                     return sprintf "◆%s◆",$h->as_trimmed_text;
281                 }
282                 else {
283                     return fallback_to_html($h);
284                 }
285             };
286              
287             case table => sub {
288                 my ($c, $h) = @_;
289                 my $out = '';
290                 my $summary = $h->attr('summary') || '';
291                 $summary =~ s!(.+?)::(.+)!●$1\t$2\n!;
292                 $out .= "◆table/◆\n";
293                 $out .= $summary;
294                 $out .= "◆table-title◆";
295                 for my $table ($h->find('tr')) {
296                     for my $item ($table->find('th')) {
297                         $out .= $item->as_trimmed_text;
298                         $out .= "\t";
299                     }
300                     for my $item ($table->find('td')) {
301                         $out .= $item->as_trimmed_text;
302                         $out .= "\t";
303                     }
304                     chop($out);
305                     $out .= "\n"
306                 }
307                 $out .= "◆/table◆\n";
308                 return $out;
309             };
310              
311             case strong => sub {
312                 my ($c, $h) = @_;
313                 return sprintf(
314                     "◆b/◆%s◆/b◆",
315                     $h->as_trimmed_text
316                 );
317             };
318              
319             case ul => sub {
320                 my ($c, $h) = @_;
321                 if ($c->in_list) {
322                     my $ret = "\n";
323                     for ($h->content_list) {
324                         if ($_->tag eq 'li') {
325                             $ret .= sprintf "*・%s\n", $c->parse_element($_);
326                         }
327                     }
328                     chomp $ret;
329                     return $ret;
330                 } else {
331                     my $ret;
332                     for my $list ($h->content_list) {
333                         $c->in_list(1);
334                         $ret .= '・' . $c->parse_element($list) . "\n";
335                         $c->in_list(0);
336                     }
337                     return $ret;
338                 }
339             };
340              
341             case hr => sub {
342                 my ($c, $h) = @_;
343                 return "=-=-=\n";
344             };
345              
346             1;
347