File Coverage

lib/Acme/Nyaa/Ja.pm
Criterion Covered Total %
statement 171 190 90.0
branch 80 118 67.8
condition 12 21 57.1
subroutine 14 14 100.0
pod 5 8 62.5
total 282 351 80.3


line stmt bran cond sub pod time code
1             package Acme::Nyaa::Ja;
2 2     2   6574 use parent 'Acme::Nyaa';
  2         671  
  2         13  
3 2     2   117 use strict;
  2         4  
  2         48  
4 2     2   11 use warnings;
  2         4  
  2         52  
5 2     2   11 use utf8;
  2         2  
  2         14  
6              
7             my $RxComma = qr/[、(?:, )]/;
8             my $RxPeriod = qr/[。!]/;
9             my $RxEndOfList = qr#[))-=+|}>>/:;"'`\]]#;
10             my $RxConversation = qr/[「『].+[」』]/;
11             my $RxEndOfSentence = qr/(?:[!!??…]+|[.]{2,}|[。]{2,}|[、]{2,}|[,]{2,})/;
12              
13             my $Cats = [ '猫', 'ネコ', 'ねこ' ];
14             my $Separator = qq(\x1f\x1f\x1f);
15             my $HiraganaNya = 'にゃ';
16             my $KatakanaNya = 'ニャ';
17             my $FightingCats = [
18             '「マーオ」',
19             '「マーオ!」',
20             '「マーーオ」',
21             '「マーーオ!」',
22             '「マーーーオ!!」',
23             '「マーーーーオ!!!」',
24             ];
25             my $Copulae = [ 'だ', 'です', 'である', 'どす', 'かもしれない', 'らしい', 'ようです' ];
26             my $HiraganaTails = [
27             'にゃ', 'にゃー', 'にゃ〜', 'にゃーーーー!', 'にゃん', 'にゃーん', 'にゃ〜ん',
28             'にゃー!', 'にゃーーー!!', 'にゃーー!',
29             ];
30             my $KatakanaTails = [
31             'ニャ', 'ニャー', 'ニャ〜', 'ニャーーーー!', 'ニャん', 'ニャーん', 'ニャ〜ん',
32             'ニャー!', 'ニャーーー!!', 'ニャーー!',
33             ];
34             my $DoNotBecomeCat = [
35             # See http://ja.wikipedia.org/wiki/モーニング娘。
36             'モーニング娘。',
37             'カントリー娘。',
38             'ココナッツ娘。',
39             'ミニモニ。',
40             'エコモニ。',
41             'ハロー!モーニング。',
42             'エアモニ。',
43             'モーニング刑事。',
44             'モー娘。',
45             ];
46              
47             sub new {
48             # Constructor
49 5     5 1 499 my $class = shift;
50 5         10 my $argvs = { @_ };
51              
52 5 100       22 return $class if ref $class eq __PACKAGE__;
53 4         11 $argvs->{'language'} = 'ja';
54 4         20 return bless $argvs, __PACKAGE__;
55             }
56              
57             sub language {
58             # Set language to use
59 1     1 0 3 my $self = shift;
60              
61 1   50     10 $self->{'language'} ||= 'ja';
62 1         5 return $self->{'language'};
63             }
64              
65             sub object {
66             # Wrapper method for new()
67 3     3 0 5 my $self = shift;
68 3 50       9 return __PACKAGE__->new unless ref $self;
69 3         12 return $self;
70             }
71             *objects = *object;
72             *findobject = *object;
73              
74             sub cat {
75 304     304 1 212168 my $self = shift;
76 304         524 my $argv = shift;
77 304   100     1254 my $flag = shift // 0;
78              
79 304         530 my $ref1 = ref $argv;
80 304         479 my $text = undef;
81 304         344 my $neko = undef;
82 304         326 my $nyaa = undef;
83              
84 304 50 33     1522 return q() if( $ref1 ne '' && $ref1 ne 'SCALAR' );
85 304 50       728 $text = $ref1 eq 'SCALAR' ? $$argv: $argv;
86 304 50       810 return q() unless length $text;
87              
88 304         375 eval {
89 304         742 $self->reckon( \$text );
90 304         952 $neko = $self->toutf8( $text );
91             };
92 304 50       674 return $text if $@;
93              
94 304         3614 $neko =~ s{($RxPeriod)}{$1$Separator}g;
95 304 100       1369 $neko .= $Separator unless $neko =~ m{$Separator};
96              
97 304         528 my $hiralength = scalar @$HiraganaTails;
98 304         349 my $katalength = scalar @$KatakanaTails;
99 304         1342 my $writingset = [ split( $Separator, $neko ) ];
100 304         408 my $haschomped = 0;
101 304         408 my ( $r1,$r2 ) = 0;
102              
103 304         492 for my $e ( @$writingset ) {
104              
105 360 50       2780 next if $e =~ m/\A$RxPeriod\s*\z/;
106 360 50       2684 next if $e =~ m/$RxEndOfList\s*\z/;
107 360 100       618 next if grep { $e =~ m/\A$_\s*/ } @$DoNotBecomeCat;
  3240         41530  
108 356 100       792 next if grep { $e =~ m/$_$RxPeriod?\z/ } @$HiraganaTails;
  3560         64701  
109 354 100       606 next if grep { $e =~ m/$_$RxPeriod?\z/ } @$KatakanaTails;
  3540         56760  
110 282 50       466 next if grep { $e =~ m/$_$RxEndOfSentence?\s*\z/ } @$HiraganaTails;
  2820         97648  
111 282 100       501 next if grep { $e =~ m/$_$RxEndOfSentence?\s*\z/ } @$KatakanaTails;
  2820         82297  
112 251 100       602 next if grep { $e =~ m/$_\s*\z/ } @$FightingCats;
  1506         19266  
113              
114             # Do not convert if the string contain only ASCII characters.
115             # ASCII文字しか入ってない時は何もしない
116 247 50       1031 next if $e =~ m{\A[\x20-\x7E]+\z};
117              
118             # ひらがな、またはカタカナが入ってないなら次へ
119 2 100   2   2120 next unless $e =~ m{[\p{InHiragana}\p{InKatakana}]+};
  2         4  
  2         46  
  247         1874  
120              
121             # Cats may be hard to speak a word which ends with a character 'ね'.
122             # 「ね」の後ろにニャーがあると猫が喋りにくそう
123 174 50       1364 next if $e =~ m{[ねネ]$RxPeriod?\s*\z};
124              
125 174         394 $haschomped = chomp $e;
126              
127 174 100       4411 if( $e =~ m/な$RxPeriod?\s*\z/ ) {
    50          
    100          
    50          
    50          
128             # な => にゃー
129 2         42 $e =~ s/な($RxPeriod?)(\s*)\z/$HiraganaNya$1$2/;
130              
131             } elsif( $e =~ m/ナ$RxPeriod?\s*\z/ ) {
132             # ナ => ニャー
133 0         0 $e =~ s/ナ($RxPeriod?)(\s*)\z/$HiraganaNya$1$2/;
134              
135             } elsif( $e =~ m/\p{InHiragana}$RxPeriod\s*\z/ ) {
136              
137 106         406 $r1 = int rand $katalength;
138 106         1927 $e =~ s/($RxPeriod)(\s*)\z/$KatakanaTails->[ $r1 ]$1$2/;
139              
140             } elsif( $e =~ m/\p{InKatakana}$RxPeriod\s*\z/ ) {
141              
142 0         0 $r1 = int rand $hiralength;
143 0         0 $e =~ s/($RxPeriod)(\s*)\z/$HiraganaTails->[ $r1 ]$1$2/;
144              
145             } elsif( $e =~ m/\p{InCJKUnifiedIdeographs}$RxPeriod?\s*\z/ ) {
146              
147 0         0 $r1 = int rand $hiralength;
148 0         0 $r2 = int rand scalar @$Copulae;
149 0         0 $e =~ s/($RxPeriod?)(\s*)\z/$Copulae->[ $r2 ]$KatakanaTails->[ $r1 ]$1$2/;
150              
151             } else {
152 66 100       1586 if( $e =~ m/($RxEndOfSentence)\s*\z/ ) {
    100          
153             # ... => ニャー..., ! => ニャ!
154 14         44 my $eos = $1;
155              
156 14 50       306 if( $e =~ m/\p{InKatakana}$RxEndOfSentence\s*\z/ ) {
    50          
157              
158 0         0 $r1 = int rand( $hiralength / 2 );
159 0         0 $e =~ s/$RxEndOfSentence/$HiraganaTails->[ $r1 ]$eos/g;
160              
161             } elsif( $e =~ m/\p{InHiragana}$RxEndOfSentence\s*\z/ ) {
162              
163 14         322 $r1 = int rand( $katalength / 2 );
164 14         311 $e =~ s/$RxEndOfSentence/$KatakanaTails->[ $r1 ]$eos/g;
165              
166             } else {
167 0         0 $r1 = int rand( $katalength / 2 );
168 0         0 $r2 = int rand( scalar @$Copulae );
169 0         0 $e =~ s/$RxEndOfSentence/$Copulae->[ $r2 ]$KatakanaTails->[ $r1 ]$eos/g;
170             }
171              
172             } elsif( $e =~ m/$RxConversation\s*\z/ ) {
173              
174             # 0.5の確率で会話の後ろで猫が喧嘩をする
175 8 100       154 if( $e =~ m/\A(.*$RxConversation[ ]*)($RxConversation.*)\s*\z/ ) {
176              
177 5         18 $r1 = int rand scalar @$FightingCats;
178 5 100       28 $e = $1.$FightingCats->[ $r1 ].$2 if int(rand(10)) % 2;
179             }
180 8         22 $r1 = int rand scalar @$FightingCats;
181 8 100       35 $e .= $FightingCats->[ $r1 ] if int(rand(10)) % 2;
182              
183             } else {
184              
185 44         143 $r1 = int rand $katalength;
186              
187 44 50       393 if( $e =~ m/[0-9\p{Latin}]\s*\z/ ) {
    50          
188              
189 0         0 $r2 = int rand scalar @$Copulae;
190 0         0 $e =~ s/(\s*?)\z/ $Copulae->[ $r2 ]$KatakanaTails->[ $r1 ]$1/;
191              
192             } elsif( $e =~ m/\p{InKatakana}\s*\z/ ) {
193              
194 0         0 $e =~ s/(\s*?)\z/$HiraganaTails->[ $r1 ]$1/;
195              
196             } else {
197 44         593 $e =~ s/(\s*?)\z/$KatakanaTails->[ $r1 ]$1/;
198             }
199             }
200             }
201              
202 174         883 $e =~ s/[!]$RxPeriod/! /g;
203 174 50       880 $e .= qq(\n) if $haschomped;
204              
205             } # End of for(@$writingset)
206              
207 304 100       1862 return $self->utf8to( join( '', @$writingset ) ) unless $flag;
208 20         178 return join( '', @$writingset );
209             }
210              
211             sub neko {
212 284     284 1 146136 my $self = shift;
213 284         385 my $argv = shift;
214 284   50     1321 my $flag = shift // 0;
215              
216 284         564 my $ref1 = ref $argv;
217 284         376 my $text = undef;
218 284         385 my $neko = undef;
219              
220 284 50 33     1482 return q() if( $ref1 ne '' && $ref1 ne 'SCALAR' );
221 284 50       702 $text = $ref1 eq 'SCALAR' ? $$argv : $argv;
222 284 50       738 return q() unless length $text;
223              
224              
225 284         323 eval {
226 284         642 $self->reckon( \$text );
227 284         772 $neko = $self->toutf8( $text );
228             };
229 284 50       587 return $text if $@;
230              
231 284         1086 my $nounstable = {
232             '神' => 'ネコ',
233             '神' => 'ネコ',
234             };
235              
236 284         871 for my $e ( keys %$nounstable ) {
237              
238 568 100       6434 next unless $neko =~ m{$e};
239 44         97 my $f = $nounstable->{ $e };
240              
241 44         177 $neko =~ s{\A[$e]\z}{$f};
242 44         264 $neko =~ s{\A[$e](\p{InHiragana})}{$f$1};
243 44         325 $neko =~ s{\A[$e](\p{InKatakana})}{$f$1};
244 44         403 $neko =~ s{(\p{InHiragana})[$e](\p{InHiragana})}{$1$f$2}g;
245 44         409 $neko =~ s{(\p{InHiragana})[$e](\p{InKatakana})}{$1$f$2}g;
246 44         904 $neko =~ s{(\p{InKatakana})[$e](\p{InKatakana})}{$1$f$2}g;
247 44         368 $neko =~ s{(\p{InKatakana})[$e](\p{InHiragana})}{$1$f$2}g;
248 44         485 $neko =~ s{(\p{InHiragana})[$e]($RxPeriod|$RxComma)?\z}{$1$f$2}g;
249 44         440 $neko =~ s{(\p{InKatakana})[$e]($RxPeriod|$RxComma)?\z}{$1$f$2}g;
250             }
251              
252 284 50       14360 return $self->utf8to( $neko ) unless $flag;
253 0         0 return $neko;
254             }
255              
256             sub nyaa {
257 4     4 1 1958 my $self = shift;
258 4   100     15 my $argv = shift || q();
259 4 50       10 my $text = ref $argv ? $$argv : $argv;
260 4         8 my $nyaa = [];
261              
262 4         32 push @$nyaa, @$KatakanaTails, @$HiraganaTails;
263 4         27 return $text.$nyaa->[ int rand( scalar @$nyaa ) ];
264             }
265              
266             sub straycat {
267 2     2 1 10413 my $self = shift;
268 2   50     10 my $argv = shift // return q();
269 2   50     15 my $noun = shift // 0;
270              
271 2         5 my $ref1 = ref $argv;
272 2         5 my $data = [];
273 2         4 my $text = q();
274              
275 2         5 my $nekobuffer = q();
276 2         3 my $leftbuffer = q();
277 2         4 my $buffersize = 144;
278 2         12 my $entityrmap = {
279             '、' => '、',
280             '。' => '。',
281             };
282              
283 2 50       19 return q() unless $ref1 =~ m/(?:ARRAY|SCALAR)/;
284 2 100       14 push @$data, $ref1 eq 'ARRAY' ? @$argv : $$argv;
285 2 50       7 return q() unless scalar @$data;
286              
287 2         4 for my $r ( @$data ) {
288              
289             # To be a cat
290 21 50       133 if( $r =~ m|[^\x20-\x7e]+| ) {
291             # Encode if any multibyte character exsits
292 21         30 eval {
293 21         65 $self->reckon( \$r );
294 21         71 $nekobuffer .= $self->toutf8( $r );
295             };
296 21 50       55 next if $@;
297              
298             } else {
299 0         0 $nekobuffer .= $r;
300             }
301              
302 21         65 for my $e ( keys %$entityrmap ) {
303             # Convert character entity reference to character itself.
304 42 50       579 next unless $nekobuffer =~ m/$e/;
305 0         0 $nekobuffer =~ s/$e/$entityrmap->{ $e }/g;
306             }
307              
308 21 100       75 if( length $nekobuffer < $buffersize ) {
309              
310 20 100       340 if( $nekobuffer =~ m/(.+$RxPeriod)(.*)/msx ) {
311              
312 19         50 $nekobuffer = $1;
313 19         111 $leftbuffer = $2;
314              
315             } else {
316 1         4 next;
317             }
318             }
319              
320 20 50       145 if( $nekobuffer =~ m|[^\x20-\x7e]+| ) {
321             # Convert if any multibyte character exsits
322 20         56 $nekobuffer = $self->cat( \$nekobuffer, 1 );
323             }
324              
325 20 50       53 if( $noun ) {
326             # Convert noun
327 0 0       0 $nekobuffer = $self->neko( \$nekobuffer, 1 ) if $nekobuffer =~ m|[^\x20-\x7e]+|;
328 0 0       0 $leftbuffer = $self->neko( \$leftbuffer, 1 ) if $leftbuffer =~ m|[^\x20-\x7e]+|;
329             }
330              
331 20         82 $text .= $nekobuffer;
332 20         30 $nekobuffer = $leftbuffer;
333 20         40 $leftbuffer = q();
334             }
335              
336 2 100       8 $text .= $nekobuffer if length $nekobuffer;
337 2         20 return $self->utf8to( $text );
338             }
339              
340             sub reckon {
341             # Recognize text encoding
342 1219     1219 0 1418 my $self = shift;
343 1219         1330 my $argv = shift;
344              
345 1219         1726 my $ref1 = ref $argv;
346 1219 100       2433 my $text = $ref1 eq 'SCALAR' ? $$argv: $argv;
347 1219 50       2436 return q() unless length $text;
348              
349 2     2   60034 use Encode::Guess qw(shiftjis euc-jp 7bit-jis);
  2         27015  
  2         13  
350 1219         2775 $self->{'utf8flag'} = utf8::is_utf8 $text;
351              
352 1219         3913 my $code = Encode::Guess->guess( $text );
353 1219         103998 my $name = q();
354 1219 100       2741 return q() unless ref $code;
355              
356             # What encoding
357 1129         3834 $name = $code->name;
358 1129 50       9195 $name = $1 if $name =~ m/\A(.+) or .+/;
359              
360 1129 50       2712 if( $name ne 'ascii' ) {
361 1129   66     3375 $self->{'encoding'} ||= $name;
362             }
363 1129         2678 return $self->{'encoding'};
364             }
365              
366             1;
367              
368             __END__