PerlのIRCモジュールと言えば、ちょっと前まで Net::IRCだと思っていたが、久しくcpanでそいつをインストールしようとすると、”時代遅れだからPOE::Component::IRCを使っちゃいなー ! ” と言われた。 イベントドリブンなIRCクライアントを書く為のモジュールで、PING/PONGの自動応答など、IRCセッションを裏で面倒見てくれる便利なモジュールらしい。POE自体、ネットワーク関係の疑似マルチスレッディング、同期通信など、カーネル側でサポートされそうな事をやってくれる便利なパッケージ。これを使うと、よ り環境に依存しないネットワークツールが作れる訳だ。
POE::Component::IRC の日本語ドキュメントもさくっと見つかった。
サンプルがついているので、ちょっと遊んでみる。ついでに、ホスト& IRCサーバともども、UTF-8な日本語環境で利用する為の工夫もしてみた。
</p> <h1>!/usr/bin/env perl</h1> <p>use strict; use warnings; use utf8; use Encode; use POE qw(Component::IRC);</p> <h1>IRC の接続設定</h1> <p>my $nickname = 'poepoe' . $$; my $ircname = 'POE POE Bot'; my $ircserver = 'sasebo.ddo.jp'; my $port = 6665; my @channels = ( '#alice' );</p> <h1>接続設定を渡して、オブジェクトを作成</h1> <p>my $irc = POE::Component::IRC->spawn( nick => $nickname, server => $ircserver, port => $port, ircname => $ircname, ) or die "Failed. $!";</p> <h1>イベントハンドラを登録</h1> <p>POE::Session->create( package_states => [ 'main' => [ qw(_default _start irc_001 irc_public) ], ], heap => { irc => $irc }, );</p> <h1>実行</h1> <p>$poe_kernel->run(); exit 0;</p> <h1>以下、イベント</h1> <h1>接続</h1> <p>sub <em>start { my ($kernel,$heap) = @</em>[KERNEL,HEAP]; my $irc_session = $heap->{irc}->session_id(); $kernel->post( $irc_session => register => 'all' ); $kernel->post( $irc_session => connect => { } ); undef; }</p> <h1>接続完了 → チャンネルへ Join !</h1> <p>sub irc_001 { my ($kernel,$sender) = @<em>[KERNEL,SENDER]; my $poco_object = $sender->get_heap(); print "Connected to ", $poco_object->server_name(), "\n"; $kernel->post( $sender => join => $</em> ) for @channels; undef; }</p> <h1>発言時や状態が変わった時などに呼ばれるイベント。</h1> <h1>ここに自由な挙動を書く。</h1> <p>sub irc_public { my ($kernel,$sender,$who,$where,$what) = @_[KERNEL,SENDER,ARG0,ARG1,ARG2]; my $nick = ( split /!/, $who )[0]; my $channel = $where->[0];</p> <pre><code># 内部 Unicode 用に UTF8 フラグを付与 $what = Encode::decode(&quot;utf-8&quot;,$what); if ( $what =~ /イ[カモ]/ ) { # 本当は、BOT の発言は privmsg ではなく notice にするのがマナー。 $kernel-&gt;post( $sender =&gt; privmsg =&gt; $channel =&gt; &quot;おいしいです、$nick。&quot; ); } </code></pre> <h1>茶筅に投げてみるテスト</h1> <h1>if ( my ($rot13) = $what =~ /^! (.+)/ ) {</h1> <h1>foreach my $line (<code>echo '$rot13'|chasen -iw</code>){</h1> <h1>$kernel->post( $sender => notice => $channel => $line );</h1> <h1>}</h1> <h1>}</h1> <pre><code># 出力時には、UTF8 フラグを除去 $what = Encode::encode(&quot;utf-8&quot;,$what); undef; </code></pre> <p>}</p> <h1>標準出力に動作ログを吐く</h1> <p>sub <em>default { my ($event, $args) = @</em>[ARG0 .. $#_]; my @output = ( "$event: " ); foreach my $arg ( @$args ) { if ( ref($arg) eq 'ARRAY' ) { push( @output, "[" . join(" ,", @$arg ) . "]" ); } else { push ( @output, "'$arg'" ); } } print STDOUT join ' ', @output, "\n"; return 0; }
ソースも LOCALE も IRC サーバも UTF-8 だが、Perl の内部保持している文字列データは単純な Unicode なので、UTF-8 フラグを付けてから処理してやらなければならない。 上の例では、「イカ」とか「イモ」という発言があれば反応する。