<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xml:lang="ja">
  <channel>
    <title>Hacker Track - JPerl Advent Calendar 2009</title>
    <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/</link>
    <description>自分が書いたモジュールの解説や、ちょっとした tips などを紹介していきます。</description>
    <item>
      <title>Module::Requires で依存モジュールをきっちりチェック</title>
      <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/25.html</link>
      <description><![CDATA[<div class="section">
<p>今月の advent calendar だけで通算27日分もの記事を書いている Yappo ですみなさんお元気ですか?</p>

<p>なんだか hacker track が人手不足なので今日ネタを書くために昨日思いついたモジュールを CPAN にアップロードした上で二度目の参戦をします。</p>

<p><a href="http://github.com/yappo/p5-Module-Requires">http://github.com/yappo/p5-Module-Requires</a></p>
</div>
<div class="section">
<h3> まえおき</h3>

<p>みなさんがコードを書く上で依存モジュールの管理に悩む。なんてのは誰しもが通る道だと思います。</p>

<p>もうすでに Makefile.PL の中に依存モジュールを書けば、依存モジュールを全部入れてくれるので悩む事は無いと思います。</p>

<p>さらには、テストケースで必要な依存モジュールのチェックなども Test::Requires が登場した事により、気楽にテストする事も出来ます。</p>

<p>だがしかし、プラガブルなモジュールなどが含まれるディストリビューションを作ったときに、このサブモジュールを使う時は、このモジュールも入れてね的に Makefile.PL に以下のような feature 句を入れるかと思います。</p>
<pre>
# Plack の Makefile.PL から拝借
feature 'FastCGI daemon and dispatcher',
    -default => 0,
    'FCGI' => 0.67,
    'FCGI::Client' => 0.02;
</pre>
<p>これは、実際のインストールフェーズでは以下のように依存モジュールを入れるか聞かれます。</p>
<pre>
[FastCGI daemon and dispatcher]
- FCGI                            ...missing.
- FCGI::Client                    ...missing.
==> Auto-install the 2 optional module(s) from CPAN? [n] 
</pre>
<p>ユーザがインストールする時に、ここで提示されたモジュールを入れてくれれば何も問題ないでしょう。</p>

<p>しかしながら、最初は要らないと思っていても後で使う気になった時には当然これら必須モジュールがはいっていないので「Can't Locate ...」などのエラーが出てきます。</p>

<p>不足してる依存モジュールが少数だったら許せるでしょうが、足りないモジュールがいっぱいあると「Can't Locate ...」と言われるたびに install するとかいうめんどくさい事になってしまいます。</p>

<p>簡単に言うと Module::Requires は、この「Can't Locate ...」エラーメッセージを一度に出して依存モジュールで足りてないモジュール群を一度に提示してあげるという事に使えるのです。</p>

<p># もちろん、これを排除するには sub feature 的なモジュールを別ディストリにしちゃうのが一番綺麗でしょう</p>
</div>
<div class="section">
<h3> 簡単な使い方</h3>

<p>使い方はとても簡単です。</p>

<p>例えば Class::Trigger と Class::Accessor に依存してる場合には以下のように書きます。</p>
<pre>
use strict;
use warnings;
use Module::Requires 'Class::Trigger', 'Class::Accessor';
use Class::Trigger;
use Class::Accessor;
</pre>

<p>もし、両方ともインストールされてないときは下記のようなエラーメッセージを出力します。</p>

<pre>
Can't load Class::Trigger
Can't locate Class/Trigger.pm in @INC (@INC contains: ry) at (eval 1) line 2.
BEGIN failed--compilation aborted at (eval 1) line 2.

Can't load Class::Accessor
Can't locate Class/Accessor.pm in @INC (@INC contains: ry) at (eval 2) line 2.
BEGIN failed--compilation aborted at (eval 2) line 2.
 at lib/Module/Requires.pm line 105
        Module::Requires::import('Module::Requires', 'Class::Trigger', 'Class::Accessor') called at ./a.pl line 3
        main::BEGIN() called at lib/Module/Requires.pm line 3
        eval {...} called at lib/Module/Requires.pm line 3
BEGIN failed--compilation aborted at ./a.pl line 3.
</pre>

<p>ちゃんと、両方の「Can't Locate ...」エラーメッセージが同時に出てきます。</p>
<p>もちろん片方がインストールされてれば、片方だけのエラーメッセージを出すし10個くらいのモジュールをチェックしてて全部入ってなければ全部のエラーを出します。</p>
</div>
<div class="section">
<h3> バージョンの指定</h3>

<p>もちろん通常の use と同じようにバージョンの指定もできます。</p>

<pre>
use strict;use warnings;
use Module::Requires
    'Class::Trigger'  => 0.99,
    'Class::Accessor' => 14.22;
use Class::Trigger;
use Class::Accessor;
</pre>

<p>こう書くと以下のようにバージョンがたりねー！と怒ります。</p>

<pre>
Class::Trigger version 0.99 required--this is only version 0.13
Class::Accessor version 14.22 required--this is only version 0.31 at lib/Module/Requires.pm line 105
        Module::Requires::import('Module::Requires', 'Class::Trigger', 0.99, 'Class::Accessor', 14.22) called at ./a.pl line 4
        main::BEGIN() called at lib/Module/Requires.pm line 5
        eval {...} called at lib/Module/Requires.pm line 5
BEGIN failed--compilation aborted at ./a.pl line 5.
</pre>
</div>
<div class="section">
<h3> 細かいバージョンの指定</h3>

<p>例えば、とあるモジュールが 0.10 まで出ていて 0.03 以上が入ってたら良いんだけど、 0.09 だけバグがあるので 0.03 以上で 0.09 以外のモジュールに依存したいとか書く必要が出てくる場合があると思います。</p>

<p>記憶が確かなら他の CPAN モジュールでも上記要求を満たすモジュールが入ってれば load するなんてのもありますが、 Module::Requires の機能としても実装してあります。</p>

<pre>
use strict;
use warnings;
use Module::Requires
    'Foo'  => [ '>' => 0.03, '!=' => 0.09 ],
    'Bar'  => [ '<=' => 0.02, '>=' => 0.01 ],
    'Baz'  => [ '<' => 0.08 ];
use Foo;
</pre>

<p>もしもインストールされている Foo のバージョンがが 0.09 であった場合下記のエラーを吐きます。</p>

<pre>
Foo version > 0.03 AND != 0.09 required--this is only version 0.09 at /lib/Module/Requires.pm line 105
        Module::Requires::import('Module::Requires', 'Foo', 'ARRAY(0x81948c)') called at ./a.pl line 4
        main::BEGIN() called at lib/Module/Requires.pm line 4
        eval {...} called at lib/Module/Requires.pm line 4
BEGIN failed--compilation aborted at ./a.pl line 4.
</pre>
</div>
<div class="section">
<h3> 同時にロードする</h3>

<p>実は上の方法では、 Module::Requires::* 以下の名前空間から各種モジュールを require してるだけなので use Module::Requires してる名前空間から正しく use するには別途 use ModuleName として書かないと正しく use 出来ませんでした。</p>

<p>これでは冗長なケースもあるので -autoload というオプションを付ける事により require チェックと同時に require && module->import を行うようになります。</p>

<pre>
# これは encode_base64 が入ってないのでだめよ
use strict;
use warnings;
use Module::Requires
    'MIME::Base64';
print encode_base64('last day');
</pre>

<pre>
# 正しく encode_base64 が load されてる
use strict;
use warnings;
use Module::Requires -autoload,
    'MIME::Base64';
print encode_base64('last day');
# use MIME::Base64; と同等
</pre>

<pre>
# decode_base64 しか export されてないので動かない
use strict;
use warnings;
use Module::Requires -autoload,
    'MIME::Base64' => {
        import => ['decode_base64'],
    };
print encode_base64('last day');
# use MIME::Base64 'decode_base64'; と同等
</pre>

<pre>
# これは encode_base64 だけを export してるので動く
use strict;
use warnings;
use Module::Requires -autoload,
    'MIME::Base64' => {
        import => ['encode_base64'],
    };
print encode_base64('last day');
# use MIME::Base64 'encode_base64'; と同等
</pre>

<p>このようにして、import メソッドに渡す引数を指定します。</p>
<p>use ModuleName () と同等にするには下記のように書きます。</p>

<pre>
# decode_base64 しか export されてないので動かない
use strict;
use warnings;
use Module::Requires -autoload,
    'MIME::Base64' => {
        import => [],
    };
print encode_base64('last day');
# use MIME::Base64 (); と同等
</pre>

<p>use Module () って空括弧を引数に渡すと import を呼ばなくなる仕様を忘れててすっかりドハマリしてバグ作ってましたが直しました＞＜</p>
</div>
<div class="section">
<h3> autoload しつつ version していする</h3>

<p>これも出来ます。</p>

<pre>
use Module::Requires -autoload,
    'MIME::Base64' => {
        import  => [qw/ encode_base64 /],
        version => 0.03,
    };
# use MIME::Base 0.03 qw( encode_base64 ); と同等
</pre>

<p>こんな風にシンプルなバージョンの指定から</p>

<pre>
use Module::Requires -autoload,
    'MIME::Base64' => {
        import  => [qw/ encode_base64 /],
        version => [ '>=' => 0.03, '!=' => '0.08' ],
    };
</pre>

<p>のような細かいバージョンの制御もできます。</p>

</div>
<div class="section">
<h3> まとめ</h3>

<p>Module::Requires を使ってモジュールの依存を細かく定義して、万が一依存モジュールの条件を満たさない場合はユーザが楽できる用にエラーを出すという事を紹介しました。</p>

<p>バグ出しやらなんやらで賞味一時間強で創り上げました。</p>

<p>また、このモジュールの実際の仕様のネタ出しは lestrrat さんと nekokak さんにして頂きましたありがとうございます。</p>

<p>例によって英語ドキュメントが不足気味なので、興味を持たれた方は是非ともドキュメントを充実させてくれると嬉しいです。</p>


<p>ということで地味なモジュールで今年の JPerl Advent Calendar を締めくくりましたが、そんなんで良いんじゃないかとおもいます。</p>

<p>ではでは、関係者の皆さんお疲れ様でした。こんどは寿司屋でありましょう！</p>

</div>
]]></description>
      <dc:creator>yappo</dc:creator>
      <pubDate>Fri, 25 Dec 2009 06:13:01 GMT</pubDate>
      <category></category>
    </item>
    <item>
      <title>Win32::APIでPerlの中に直接機械語を書いてるときのデバッグ</title>
      <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/24.html</link>
      <description><![CDATA[<div class="section">
<p>はせがわようすけです。こんにちは。今日みたいな日だとリア充揃いのPerl geeksは人手不足なようで、ほとんどPerlを使ったことのない私まで駆り出されましたよ。</p>
</div>
<div class="section">
<h3>まえおき</h3>

<p>というわけで、Perlで機械語を埋め込む技を応用すると、ActivePerl で stdcall な通常のDLL関数だけでなく、MSVCRT.DLL に含まれる sprintf のような可変長引数の cdecl な呼び出し規約の関数も利用できます。</p>

<pre>
#!/c/perl/bin/perl
use strict;
use warnings;
use Win32::API;

#include <windows.h>
my $EnumWindows = Win32::API->new( "user32", "EnumWindows", "NN", "N" );
my $GetProcAddress = Win32::API->new( "kernel32", "GetProcAddress", "NP", "N" );
my $LoadLibrary = Win32::API->new( "kernel32", "LoadLibraryA", "P", "N" );
my $FreeLibrary = Win32::API->new( "kernel32", "FreeLibrary", "N" );

sub my_sprintf{
    if( @_ < 1 ){
        die "argument error";
    }

    my $hDll = $LoadLibrary->Call( "msvcrt" );
    my $sprintf = pack( 'L', $GetProcAddress->Call( $hDll, "sprintf" ) );   # sprintf is cdecl
    my $buf = "\0" x 1024;
    my $x86 ="";
    my $i = @_;

    while( $i-- ){
        $x86 .= "\x68" . $_[ $i ];      # push args
    }
    $x86 .= "\x68" . pack( 'P', $buf ); # push $buf
    my $n = ( @_ + 1 ) * 4;
    $x86 .= ""
.       "\xb8" . $sprintf               # mov eax, func
.       "\xff\xd0"                      # call eax
.       "\x81\xC4"                      # add esp, @_ * 4
.       pack( 'L', $n )
.       "\x33\xc0"                      # xor eax, eax
.       "\xc2\x08\x00"                  # ret
;

    $EnumWindows->Call( unpack( 'L', pack( 'P', $x86 ) ), 0 );
    $FreeLibrary->Call( $hDll );
    $buf =~s/\0.*$//;
    return $buf;
}

my $s = my_sprintf( pack( 'P', "%s, %s" ), pack( 'P', "Hello" ), pack( 'P', "World" ) );
print $s;

</pre>

<p>実行結果</p>
<pre>
C:\>xmax.pl
Hello, World
</pre>

<p>このように、用意しておいたバイト配列を<a href="http://msdn.microsoft.com/en-us/library/ms633497%28VS.85%29.aspx">EnumWindows</a> APIのコールバック関数として渡してやることで、任意の機械語を簡単に実行させることができます。</p>
<p>ただ、熟練したバイナリアンでなければ機械語を一発で動かすことは難しく、たいていの場合は途中でプログラムが強制終了させられてしまいます。</p>

<p>そこで、もう少し効率的にデバッグする方法を紹介します。</p>
</div>
<div class="section">
<h3>printf デバッグ</h3>
<p>まず、もっとも簡単な方法として、みんな大好きな printf デバッグで機械語を確認することにしましょう。</p>

<pre>
    $x86 .= ""
.       "\xb8" . $sprintf               # mov eax, func
.       "\xff\xd0"                      # call eax
.       "\x81\xC4"                      # add esp, @_ * 4
.       pack( 'L', $n )
.       "\x33\xc0"                      # xor eax, eax
.       "\xc2\x08\x00"                  # ret
;
    print unpack( 'H2' x length( $x86 ), $x86 );
    print "\n";
</pre>

<p>実行結果</p>
<pre>
C:\>xmax.pl
68d4764d0268b4764d026894764d02685c8b4c02b831bd9676ffd081c41000000033c0c20800
Hello,World
</pre>

<p>ごらんのとおり、実行される機械語が画面に表示されますので、どこで機械語の指定を間違えたのか一目瞭然になります。</p>
<p>超画期的です。</p>
</div>
<div class="section">
<h3>デバッガでアタッチ</h3>
<p>printfによる目視デバッグでもあまり困らないのですが、あまりやりすぎると</p>
<p><a href="http://d.hatena.ne.jp/hyoshiok/20090322#p1">よしおかさんに怒られちゃう</a>ので、きちんとデバッガを使うようにしましょう。使うデバッガ環境はもちろん Visual Studio です。</p>

<p>Visual Studioは、「C:\Windows\System32\vsjitdebugger.exe -p プロセスID 」とすることで、任意のプロセスをデバッガにアタッチすることができますので、Perlのなかから自身のプロセスIDを指定してこれを呼び出すことで、うまくデバッガにアタッチできそうです。</p>
<p>指定してこれを呼び出すことで、うまくデバッガにアタッチできそうです。</p>
<p>ただし、Perlのsystem関数を使ってそのままvsjitdebugger.exeを呼び出したのでは、デバッガ終了までperl側の処理がブロックされてしまい、デバッガが立ち上がっても継続してデバッグすることができません。</p>
<p>そこで、start コマンド経由で vsjitdebugger.exe を呼び出すことにします。</p>

<pre>
system("start", "vsjitdebugger.exe", "-p", "$$" );
</pre>

<p>こうすることで、startコマンドは vsjitdebugger.exe を起動すると速やかに終了し、Perl側では system は制御を戻すので、デバッガと並行してコードの実行を進めることができます。</p>

<p>ただし、このままではデバッガが起動しデバッグ対象プロセス(ActivePerl)にアタッチしてデバッグの準備ができるのを待つことなく、Perl側はどんどんコードの実行を進めてしまいますので、今度はデバッガの準備ができるまでPerl側のコードの実行を停止させる必要があります。</p>
<p>これには、Windows APIの<a href="http://msdn.microsoft.com/en-us/library/ms680345%28VS.85%29.aspx">IsDebuggerPresent</a>関数を使います。</p>

<pre>
while( $IsDebuggerPresent->Call() == 0 ){
    sleep( 1 );
};
</pre>

<p>これで、デバッガがきちんとアタッチしていない間は有意なコードの実行を停止させることができます。</p>


<p>つぎに、x86バイナリコードにブレークポイントを置くわけですが、これは単純に int 3 を実行することでデバッガにブレークを通知できます。</p>

<pre>
my $x86 = "\xCC.....";
</pre>

<p>CPUがこの0xCCという機械語を実行すると、デバッガ側にはブレークポイントとして通知され、以降のコードを自由にデバッガ上で動かすことができます。</p>

<p>というわけで、さきの Hello, World の機械語部分をデバッガ上で実行するよう書き換えたコードを以下に示します。</p>

<pre>
#!/c/perl/bin/perl
use strict;
use warnings;
use Win32::API;

#include <windows.h>
my $EnumWindows = Win32::API->new( "user32", "EnumWindows", "NN", "N" );
my $GetProcAddress = Win32::API->new( "kernel32", "GetProcAddress", "NP", "N" );
my $LoadLibrary = Win32::API->new( "kernel32", "LoadLibraryA", "P", "N" );
my $FreeLibrary = Win32::API->new( "kernel32", "FreeLibrary", "N" );
my $IsDebuggerPresent = Win32::API->new( "kernel32", "IsDebuggerPresent", "", "N" );

sub my_sprintf{
    if( @_ < 1 ){
        die "argument error";
    }

    my $hDll = $LoadLibrary->Call( "msvcrt" );
    my $sprintf = pack( 'L', $GetProcAddress->Call( $hDll, "sprintf" ) );   # sprintf is cdecl
    my $buf = "\0" x 1024;
    my $x86 ="";
    my $i = @_;

    $x86 = "\xCC";                      # int 3

    while( $i-- ){
        $x86 .= "\x68" . $_[ $i ];      # push args
    }
    $x86 .= "\x68" . pack( 'P', $buf ); # push $buf
    my $n = ( @_ + 1 ) * 4;
    $x86 .= ""
.       "\xb8" . $sprintf               # mov eax, func
.       "\xff\xd0"                      # call eax
.       "\x81\xC4"                      # add esp, @_ * 4
.       pack( 'L', $n )
.       "\x33\xc0"                      # xor eax, eax
.       "\xc2\x08\x00"                  # ret
;

    $EnumWindows->Call( unpack( 'L', pack( 'P', $x86 ) ), 0 );
    $FreeLibrary->Call( $hDll );
    $buf =~s/\0.*$//;
    return $buf;
}

system("start", "vsjitdebugger.exe", "-p", "$$" );
while( $IsDebuggerPresent->Call() == 0 ){
    sleep( 1 );
};

my $s = my_sprintf( pack( 'P', "%s,%s" ), pack( 'P', "Hello" ), pack( 'P', "World" ) );
print $s;
</pre>
</div>
<div class="section">
<h3>まとめ</h3>
<ul>
<li>Perlに機械語埋め込むときでもデバッガ使ったほうが怒られないで済むよ！</li>
<li>WindowsならVisual Studio最強ですよ!</li>
<li>int 3は0xCC。バッドノウハウ万歳!</li>
</ul>

<p>明日の最後のエントリーは・・・Yappoさんが締めくくってくれる予定？どんなネタか今から楽しみです！</p>
</div>
]]></description>
      <dc:creator>hasegawayosuke</dc:creator>
      <pubDate>Thu, 24 Dec 2009 10:13:01 GMT</pubDate>
      <category></category>
    </item>
    <item>
      <title>Plack::Server::Standalone 系を使ってウェブアプリケーション開発と運用が楽になる話</title>
      <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/23.html</link>
      <description><![CDATA[<div class="section">
<p>こんばんわ。Advent Calendar ２回目の登場になります、kazuho です。<a href="http://perl-users.jp/articles/advent-calendar/2009/hacker/05.html">前回</a>は hacker トラックなのに標準添付モジュールの紹介でしたが、今回は <a href="http://search.cpan.org/dist/Plack/">Plack</a> 関連の話です。</p>
</div>
<div class="section">
<h3>既存の環境に対する不満</h3>

<p>Perl のウェブアプリケーションを構築するにあたっては、リバースプロキシと mod_perl を組み合わせるか、あるいは FastCGI (ExternalServer) を利用するのが一般的だと思います。しかし、どちらをとっても、環境を構築して設定するのが難しいというのが個人的な不満でした (mod_redirect を設定したり mod_fastcgi にパッチをあててインストールしたり startup.pl を書いたり...)。自分が Plack の開発 (主に <a href="http://search.cpan.org/dist/Plack/lib/Plack/Server/Standalone.pm">Server::Standalone</a> と <a href="http://search.cpan.org/dist/Plack/lib/Plack/Server/Standalone/Prefork.pm">Server::Standalone::Prefork</a>) に関わるようになったのも、そのイライラを解消したかったからです。</p>

<p>その目的は、ほぼ達成することができ、先週、会社で運用しているサービス「<a href="http://pathtraq.com/">パストラック</a>」のバックエンドを Apache + FastCGI から Apache (mod_proxy) + <a href="http://search.cpan.org/dist/Plack-Server-Standalone-Prefork-Server-Starter/">Plack::Standalone::Server::Prefork::Server::Starter</a> へ切り替えました。</p>

<p>そこで今日は、Plack::Server::Standalone 系のモジュールを利用したウェブアプリケーションの開発と運用の実際について、その楽さ加減を宣伝したいと思います。</p>
</div>
<div class="section">
<h3>.psgi と plackup</h3>

<p>Standalone 系のサーバの特徴は、Plack の Middleware と組み合わせて、単独で動作するウェブサーバを構築できるところです。パストラックの .psgi ファイルは、概ね以下のようになっています。/static 以下のファイルを静的コンテンツとして配信し、動的コンテンツは昔ながらの <a href="http://search.cpan.org/dist/CGI-Application-Dispatch/">CGI::Application::Dispatch</a> を用いて生成しています。</p>

<pre>
builder {
    enable 'AccessLog', format => 'combined';
    enable 'ConditionalGET';
    enable_if { $_[0]->{PATH_INFO} =~ q{^/static/\d+/} } 'Header', set=> [ 'Expires' => 'Tue, 31 Dec 2019 23:59:59 GMT' ];
    enable 'Plack::Middleware::Static', path => qw{^/static/}, root => $ROOT;
    enable 'Plack::Middleware::Static', path => qw{^/(?:favicon\.(ico|png)|robots\.txt)$}, root => "$ROOT/static";
    CGI::Application::Emulate::PSGI->handler(
        sub {
            MyApp->dispatch();
        },
    );
};
</pre>

<p>開発環境では、この .psgi ファイルを以下のようにして Plack::Server::Standalone で動かします。httpd を起動する必要も設定ファイルを書く必要もありません。plackup 自身が、上で述べたように静的コンテンツも含む完全なウェブアプリケーションとして動作します。また、-r オプションによって、コードを書き換えると自動的に再起動するようになるので、修正→テストのサイクルを素早く回すことができます。</p>

<pre>
% plackup -r index.psgi
</pre>
</div>
<div class="section">
<h3>運用環境への投入</h3>

<p>運用環境では、上の .psgi ファイルを Plack::Server::Standalone::Prefork::Server::Starter (以下 PSSPSS) を利用して動かしています。サービスの起動スクリプト (daemontoolsで管理) は、以下のとおり。.psgi は開発用のものと全く同一。他に設定ファイルはありません。</p>

<pre>
#! /bin/sh

exec 2>&1
cd /var/webapp || exit 1
exec /usr/bin/start_server --port=80 -- /usr/local/bin/setuidgid www \
  /usr/bin/plackup -E production -s Standalone::Prefork::Server::Starter --max-workers=40 --max-keepalive-reqs=1 index.psgi
</pre>

<p>PSSPSS は、Plack::Server::Standalone ベースのマルチプロセス httpd である Plack::Server::Standalone::Prefork に、完全無停止での更新機能を追加した httpd です。ウェブアプリケーションのプログラムを書き換えた後に SIGHUP を送ることで、サービスを一切停止しないホットデプロイが可能です。この仕組みについては、詳しくは「<a href="http://developer.cybozu.co.jp/kazuho/2009/09/writing-hot-dep.html">Kazuho@Cybozu Labs: Writing Hot-deployable servers (introduction of Server::Starter)</a>」をご覧ください。</p>

<p>自分は daemontools で管理しているので、以下のようにして SIGHUP を送っています。</p>

<pre>
# svc -h /servire/webapp
</pre>

<p>Plack::Server::Standalone::Prefork (とその子クラスであるPSSPSS) では、デフォルトで keep-alive がオンになるのですが、ここではリバースプロキシと組み合わせるために、keep-alive をオフにしています(--max-keepalive-reqs=1)。</p>

<p>ちなみにパストラックでは、この設定で 20〜40 リクエスト/秒ほどの動的コンテンツを XenServer 上で生成しています。</p>
</div>
<div class="section">
<h3>リバースプロキシとの組み合わせ</h3>

<p>PSSPSS (あるいは Plack::Server::Standalone::Prefork) は単独でのウェブサービス提供も十分可能なポテンシャルを持っていますが、パストラックでは Apache (mpm_worker) ベースのリバースプロキシと組み合わせて運用しています。mpm_worker で同時接続数の上限を稼ぐ。それによって keep-alive オンでの運用が可能となり、ユーザーのレスポンスが向上するから、というのが理由です。</p>

<p>この場合の設定も簡単。plackup が単独で全コンテンツをサーブできるので、必要なのはリバースプロキシとキャッシュだけです。だいたい、以下のような設定で運用しています。</p>

<pre>
&lt;VirtualHost _default_:80&gt;
  ServerName webapp.example.com
  ErrorLog /var/log/httpd/webapp.example.com/error_log
  CustomLog /var/log/httpd/webapp.example.com/access_log combined
  CacheEnable disk /static
  &lt;Location /&gt;
    Order allow,deny
    Allow from all
    ProxyPass http://webapp.local/
    ProxyPassReverse http://webapp.local/
    ProxyPreserveHost On
  &lt;/Location&gt;
&lt;/VirtualHost&gt;
</pre>
</div>
<div class="section">
<h3>まとめ</h3>

<p>このように、Plack::Server::Standalone 系のモジュールを使うことで、開発から運用までのコストを低く抑えることが可能です。具体的には、</p>

<ul>
<li>開発環境の構築が容易</li>
<li>開発環境と運用環境の差異が少ない (ので問題が発生しにくい)</li>
<li>設定項目が少ない</li>
<li>運用環境でのホットデプロイが簡単</li>
<li>全て HTTP ベースなので、問題の切り分けが容易</li>
</ul>

<p>といったあたりになるでしょうか。大規模な案件で使うメリットがどれだけあるかは不明ですが、小〜中規模な開発では便利だと思います。一度お試しあれ。</p>

<p>PS. 明日は、ななしさんです。お楽しみに！</p>
</div>
]]></description>
      <dc:creator>kazuho</dc:creator>
      <pubDate>Thu, 24 Dec 2009 03:26:02 GMT</pubDate>
      <category></category>
    </item>
    <item>
      <title>DBICx::Modeler::Generatorでスキーマクラス群とモデルクラス群を一発生成しよう</title>
      <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/22.html</link>
      <description><![CDATA[<h2>ご挨拶</h2>

<p>はじめまして、<a href="http://blog.eorzea.asia/">gardejo</a>こと守屋と申します。金融ユー子で働いています。<a href="http://conferences.yapcasia.org/ya2009/">YAPC::Asia 2009</a>の<a href="http://conferences.yapcasia.org/ya2009/wiki?node=TrainingHome">特別研修</a>で、（<a href="http://perl-users.jp/articles/advent-calendar/2009/hacker/16.html">16日目</a>を執筆された）<a href="http://blog.livedoor.jp/dankogai/">dankogaiさん</a>の<a href="(http://conferences.yapcasia.org/ya2009/talk/2307)">研修</a>の後に、（<a href="http://perl-users.jp/articles/advent-calendar/2009/hacker/15.html">15日目</a>を執筆された）<a href="http://mt.endeworks.jp/d-6/">lestrratさん</a>などの特別補講を受ける機会に恵まれたのですが、「業務でCOBOLを使っている人？」という質問にただ独り挙手して、たいそう恥ずかしい思いをしました。</p>

<p>そんな勤め先では定例作業撲滅のためなどにPerlをゲリラ的に活用していますが、現場レベルでの対症療法であるに過ぎません。私にとってのPerlとは、エスペラント日本語翻訳システムの開発など、趣味の言語として楽しむ対象です。従って、このhacker trackの執筆陣として居並ぶハッカーの方々には多分に見劣りしますが、どうかご容赦ください。</p>

<p>本日は<a href="http://search.cpan.org/perldoc?Moose"><code>Moose</code></a>と<a href="http://search.cpan.org/perldoc?DBIx::Class"><code>DBICx::Class</code></a>が大好きな人にお勧めしたいアプリケーション設計方法論を踏まえて、<a href="http://search.cpan.org/perldoc?DBIx::Class::Schema::Loader"><code>DBIx::Class::Schema::Loader</code></a>と<a href="http://search.cpan.org/perldoc?DBICx::Modeler"><code>DBICx::Modeler</code></a>のヘルパーモジュールである<a href="http://search.cpan.org/perldoc?DBICx::Modeler::Generator"><code>DBICx::Modeler::Generator</code></a>をご紹介します。</p>

<h2>目次</h2>

<ol>
<li>モデルをWAFともスキーマとも分離する設計</li>
<li>クラスの山をどう作るか</li>
<li>作業の実際</li>
<li>実用上の留意点</li>
<li>中身の話</li>
<li>まとめ ～ Perlはエンタープライズアプリケーションに向いています！</li>
</ol>

<h2>1. モデルをWAFともスキーマとも分離する設計</h2>

<h3>1.1. エンタープライズアプリケーションで一番大事なビジネスロジック</h3>

<p>いわゆるエンタープライズアプリケーションの開発に際しては、大量のデータにまみれることになります。ここでの大量とは、テーブルの行方向も指しますが、むしろテーブルの列方向や、テーブル自体の数をこそ指すものと思ってください。</p>

<p>しかし扱うべきデータの量に圧倒されていてはいけません。エンタープライズアプリケーションで一番大事なものは何でしょうか。それはlestrratさんの『モダンPerl入門』でも触れられている通り、ビジネスロジックなのです。</p>

<h3>1.2. ビジネスロジックの書き方</h3>

<p>PoEAA（"Patterns of Enterprise Application Architecture", 邦訳『エンタープライズアプリケーションアーキテクチャパターン』）では、ビジネスロジック（PoEAAでは「ドメインロジック」という用語が使われています）を実装するパターンとして、</p>

<ul>
<li>Transaction Scriptパターン</li>
<li>Domain Modelパターン</li>
<li>Table Moduleパターン</li>
</ul>

<p>が挙げられています。このうち、私は特にDomain Modelパターンを強くお勧めしたいところです。これらの違いを簡潔に説明し、かつ、Domain Modelパターンのすばらしさをまとめている資料として、<a href="http://ameblo.jp/ouobpo">ouobpoさん</a>の「<a href="http://www.slideshare.net/ouobpo/ss-326835">ドメインロジックの実装方法とドメイン駆動設計</a>」というスライドが参考になります。</p>

<p>要はせっかくオブジェクト指向で生活しているんだから、データと振る舞いを分けるTransaction Scriptパターンではなく、データと振る舞いをカプセル化した「賢いデータ」を使うDomain Modelパターンを使うと楽しいよ、ということです。モデリングの敷居は多少高いけれども、業務を可視化して綺麗に書ける利点はとても大きいです。</p>

<p>ouobpoさんはまた<a href="http://ameblo.jp/ouobpo/entry-10036477015.html">日本ではTransaction Scriptパターンが優勢</a>とも述べています。しかし動的言語であるPerlであれば、Javaのように「静的言語を動的に扱う道具仕立て」自体が存在し得ないので、「いいところどり」を出来る余地があるのではないでしょうか。</p>

<p>実際にPerlでDomain Modelパターンに基づいて書いてみると、拍子が抜けるくらいに素直に実装出来る物です。食わず嫌いをやめてみて、一度試してみる価値は十分にあると思います。</p>

<h3>1.3. ビジネスロジックを他の層と分離する</h3>

<p>さてそんなビジネスロジックは、ouobpoさんのスライドの中にあるように、</p>

<ul>
<li>プレゼンテーション層</li>
<li>ドメイン層</li>
<li>インテグレーション層</li>
</ul>

<p>のうち、ドメイン層に位置します。</p>

<p>『モダンPerl入門』では、ビジネスロジックは<code>Catalyst</code>などのWAF（ウェブアプリケーションフレームワーク）とは分離されていて然るべきものだ、と言及されています。これはプレゼンテーション層とドメイン層を分離するという意味です。</p>

<p>そしてインテグレーション層には<code>DBIx::Class</code>などが当てはまりますが、これもドメイン層と分離されていて然るべきです。</p>

<p>lestrratさんの「<a href="http://mt.endeworks.jp/d-6/2008/03/db-1.html">ＭＶＣのモデルはDBじゃなくてもいいんだよ</a>」の記事にあるように、モデルはDBとのやりとりとは超然としているべきであって、インテグレーション層を取り扱うクラスを別途設けるのが手堅い方法論です。lestrratさんの記事では、<code>Model::DBIC</code>を別個設けるという方法論が例示されています。</p>

<h3>1.4. Perlに於けるDomain Modelパターン</h3>

<p>Perlのウェブアプリケーション作成の定番として<code>Catalyst</code>と<code>DBIx::Class</code>を利用する場合で、Domain Modelパターンに基づいた設計をするとどうなるでしょうか。これについては、（<a href="http://perl-users.jp/articles/advent-calendar/2009/hacker/07.html">7日目</a>を執筆された）<a href="http://dann.g.hatena.ne.jp/dann/">dannさん</a>による「<a href="http://www.slideshare.net/techmemo/catalyst-367905">CatalystからModelを切り離せ - MVCのMのあるべき姿 -</a>」のスライドが一つの答えになります。</p>

<p>これは「<a href="http://catalyst.g.hatena.ne.jp/dann/20080305/1204732094">Catalystを使っていて困ること</a>」から10を超える記事を経て「<a href="http://catalyst.g.hatena.ne.jp/dann/20080307/1204890012">CatalystでのMVCの私的まとめ</a>」へ至って導き出された考え方で、順を追うととてもよく理解が出来ます。</p>

<p>スライド24枚目にあるように、ドメイン層であるモデルクラスが<code>Schema::*</code>などを参照するということで、実際にはPOPO Modelのさらに奥にインテグレーション層であるスキーマクラスがあることになります。</p>

<p>なお、モデルの後ろにスキーマが必ず控えているとも限らないことも留意しておく必要があります。例えばValue Objectパターンに基づくモデルクラスを追加で作ることもあるでしょう。</p>

<h3>1.5. Mooseベースのクラスでモデルクラスを書く</h3>

<p>さてそのモデルクラスをどう書きましょうか。上述のdannさんの例では、POPO（Plain old Perl object）と書かれていますが、これは<code>Catalyst::Model</code>ベースではないという意味だと理解しています。つまり、そこでは古式ゆかしい<a href="http://search.cpan.org/perldoc?Class::Accessor::Fast"><code>Class::Accessor::Fast</code></a>を使うこともあるでしょう。そして、折角ならばみんな大好きな<code>Moose</code>を是非使いたいところです。</p>

<p>そして「<code>Schema::*</code>などを参照する」という作業をやってくれるのが、<code>DBICx::Modeler</code>というモジュールです。これは<code>DBIx::Class</code>スキーマと<code>Moose</code>クラスを仲立ちする薄いレイヤーで、橋渡しとしては申し分のない出来となっています。これにより、モデルクラスからスキーマクラスを透過的に取り扱えるようになります。</p>

<h3>1.6. <code>DBICx::Modeler</code>以外の解</h3>

<p><code>Moose</code>と<code>DBIx::Class</code>とを繋ぐ方法としては、他にスキーマの記述も<code>Moose</code>記法で書いてしまおうという野心的な<a href="http://github.com/stevan/moosex-dbic/"><code>MooseX::DBIC</code></a>というモジュールがあります。</p>

<p>また、<code>DBIx::Class</code>というORMにこだわらなければ、<a href="http://search.cpan.org/perldoc?KiokuDB"><code>KiokuDB</code></a>や<a href="http://search.cpan.org/perldoc?Fey::ORM"><code>Fey::ORM</code></a>などを活用する手法もあるでしょう。</p>

<p>これらはいずれも魅力的な方法ですが、モデリング結果をコードに落とし込むことを自動化したいという要求に焦点を当てたいので、本稿ではこれ以上は触れないこととします。</p>

<h2>2. クラスの山をどう作るか</h2>

<p>上述の通りエンタープライズアプリケーションではデータが膨大になり、込み入った業務を目指すと、途端にテーブルが数十個、場合によっては百個超に膨れあがってしまいます。</p>

<p>モデルクラスという層を新たに設けることにしたとして、スキーマクラスだけでも2桁・3桁になり得るのに、さらにそれに前後する量のモデルクラスを手作りするのは、気の遠くなる話です。</p>

<h3>2.1. DBIx::Class::Schema::Loaderによるスキーマクラス群の一発生成</h3>

<p>ただし、スキーマクラス群の生成には、定石と言える方法があります。<code>DBIx::Class::Schema::Loader</code>を使って、今そこにあるDBを解析して、一発でコードを生成するというものです。</p>

<ul>
<li><a href="http://trac.mizzy.org/public/blog">mizzyさん</a>の<a href="http://blog.mizzy.org/articles/2007/05/06/dbix-class-schema-loader">Re: DBICとDBIx::Class::Schema::Loader 僕のいろいろな勘違い</a></li>
<li>（<a href="http://perl-users.jp/articles/advent-calendar/2009/hacker/04.html">4日目</a>を執筆された）<a href="http://unknownplace.org/memo/">typesterさん</a>による<a href="http://unknownplace.org/memo/2007/05/07/#e001">Schema::Loader 使い方</a></li>
<li>（<a href="http://perl-users.jp/articles/advent-calendar/2009/hacker/06.html">6日目</a>を執筆された）<a href="http://d.hatena.ne.jp/ZIGOROu">ZIGOROuさん</a>による、<a href="http://d.hatena.ne.jp/ZIGOROu/20080318/1205828357">DBIx::Class::Schema::Loaderの手動スキーマ生成、初心者向けチュートリアル</a></li>
</ul>

<p>そうであれば、<code>DBICx::Modeler</code>を使ったモデルクラス群の生成も何とか自動化し、単純作業は撲滅したいところです。</p>

<p>そもそも、開発者にとって一番信用ならない人間は誰でしょうか。私は、それは自分だと思います。こと他人であれば事細かく確認したであろう内容であっても、自分に対しては「奴（=自分）はよしなにやってくれるだろう」と見つめてしまうからです。</p>

<p>私は上述のスキーマクラスを作る方法でさえ<del>面倒</del>……もとい、自分の犯しがちな間違いを恐れています。ライブラリ探索パスを<code>use lib</code>で切り替えて2回スクリプトを流すという工程では、DBを直してはコードを生成するという作業を何度か繰り返しているうちに、<code>use lib</code>のコメントアウトをトグルし忘れて流してしまう自信があります。</p>

<h3>2.2. DBICx::Modeler::Generatorによる（スキーマクラス群と）モデルクラス群の一発生成</h3>

<p>ということで、そんな自堕落な自分のために、<code>DBICx::Modeler::Generator</code>というヘルパーモジュールを作ってみました。いやはや、ようやく本題に入れました。</p>

<p>これは、<code>DBIx::Class::Schema::Loader</code>の一連の作業をラップした上で、さらに<code>DBICx::Modeler</code>のモデルクラス群をも一発生成するという代物です。</p>

<h2>3. 作業の実際</h2>

<p>それでは、<code>DBICx::Modeler::Generator</code>を使った作業を、順を追って見ていきましょう。</p>

<p>ここでは、<code>DBIx::Class</code>のPODや<code>DBICx::Modeler</code>のテストでも挙げられている、</p>

<ul>
<li>artist</li>
<li>cd</li>
<li>track</li>
</ul>

<p>というテーブルと、それに関連するスキーマクラス群およびモデルクラス群として、以下のようにクラス群を生成することを目的とします。</p>

<pre><code>path/
    to/
        approot/
            lib/
                MyApp/
                    Model/
                        Artist.pm
                        Artist/
                            Rock.pm
                        Cd.pm
                        Track.pm
                    Schema.pm
                    Schema/
                        Artist.pm
                        Cd.pm
                        Track.pm
</code></pre>

<p>なお、DBICx-Modeler-Generatorディストリビューションには、本稿で触れた内容を全て<code>examples/</code>ディレクトリ以下に収めています。</p>

<p>また、本稿は<a href="http://search.cpan.org/perldoc?DBICx::Modeler::Generator">POD</a>（<a href="http://search.cpan.org/perldoc?lib/DBICx/Modeler/Generator.ja.pod">日本語版</a>）を再構成したものです。PODにはこれ以外のちょっとしたtipsも載せていますので、適宜そちらも参照してください。</p>

<h3>3.1. MySQL Workbenchにより、テーブルを設計</h3>

<p>ここでの例として、テーブル設計ツールとして<a href="http://www.mysql.com/products/workbench/">MySQL Workbench</a>を利用します。</p>

<p>GUIツールであるMySQL Workbench自体は直感的な操作が可能ですので、特に迷うことはないと思います。唯一の落とし穴は、関係（relationship）をGUIで定義する際に、関数従属<em>される方</em>から<em>する方</em>へ順にテーブルをクリックしなければならないことです。つまりArtist has many CDという関係を定義する場合、1:Nのボタンを押下してカーソルを1:N選択モードにした後で、<code>cd</code>テーブル→<code>artist</code>テーブルの順に押下する必要があります。</p>

<p>この作業の成果物は、ディストリビューションにも同梱している<a href="http://search.cpan.org/src/MORIYA/DBICx-Modeler-Generator-0.0003/examples/doc/DBDSC_schemata.mwb">examples/doc/DBDSC_schemata.mwb</a>を参考にしてください。</p>

<h3>3.2. ER図の生成</h3>

<p>MySQL WorkbenchではER図を出力することも出来ます。スキーマクラス群やモデルクラス群を生成するためには必須ではありませんが、文書化という観点では必須と言えるでしょう。</p>

<p>[File] - [Export] - [Export as PNG...]メニューを辿ってPNGで出力した例も、<a href="http://search.cpan.org/src/MORIYA/DBICx-Modeler-Generator-0.0003/examples/doc/DBDERII_Including_Information.png">examples/doc/DBDERII_Including_Information.png</a>として同梱しています。SVGやPDFでも出力出来るので、用途に合わせて出力しましょう。</p>

<h3>3.3. DBへの反映、またはDDLスクリプトの生成</h3>

<p>[File] - [Export] - [Forward Engineer SQL CREATE Script...]メニューを辿り、DDL（要は<code>CREATE</code>文）のスクリプトを生成します。DDLスクリプトの例は<a href="http://search.cpan.org/src/MORIYA/DBICx-Modeler-Generator-0.0003/examples/src/myapp.sql">examples/src/myapp.sql</a>です。</p>

<p>なお、一発で完全なスキーマを作れることはまずないでしょうから、既存のDBにあるテーブルを<code>DROP</code>するよう、生成時オプションで記述しておくのが無難です。</p>

<p>後述の作業で、このスクリプトの内容をDBに反映させます。勿論、DDLスクリプトからDBへ反映する際には、RDBMSのCLIを使う方法もあります。</p>

<p>MySQLならば</p>

<pre><code>mysql &lt; foobar.sql
</code></pre>

<p>SQLiteならば</p>

<pre><code>sqlite3 &lt; foobar.sql
</code></pre>

<p>などです。実際のところ、<code>DBICx::Modeler::Generator</code>は内部で上記をやっているに過ぎません。</p>

<p>MySQL Workbenchではさらに、[Database] - [Forward Engineer...]メニューを辿り、設計したスキーマを直接DBに反映することも可能です。</p>

<h3>3.4. 自動生成されない内容をスキーマクラスに記述</h3>

<p>先にご紹介したみなさんの<code>DBIx::Class::Schema::Loader</code>の利用例にあるように、自動生成されない内容を同名クラスで予め記述しておき、生成先とは別のパスに保存しておきます。この例では、<code>path/to/approot/lib/Schema/</code>以下ではなく、<code>path/to/approot/src/lib/Schema/</code>以下に保存することにしましょう。</p>

<pre><code>path/
    to/
        approot/
            lib/
            src/
                lib/
                    MyApp/
                        Schema.pm
                        Schema/
                            Artist.pm
                            Cd.pm
                            Track.pm
</code></pre>

<p>或るクラスについて追加するコードが何もない場合は、そのクラスを<code>path/to/approot/src/lib/MyApp/Schema/</code>以下に用意する必要はありません。</p>

<p>追加するコードとしてよくある内容としては、</p>

<ul>
<li>インフレーション（inflations: データベースから取り出す際にオブジェクト化する処理など）</li>
<li>デフレーション（deflations: データベースへ格納する際にオブジェクトを文字列化する処理など）</li>
<li>追加の関係（relationships）</li>
</ul>

<p>などが挙げられます。</p>

<p>注意しなければならない点として、ここで記述したクラスはそれ単独でPerlクラスになっていなければならいない、ということが挙げられます。例えばパッケージは真を返さなければなりません。また、<code>DBIx::Class::Schema::Loader</code>に拾ってもらうため、<code>package</code>もきちんと書かなければなりません。具体的には、同梱した<a href="http://search.cpan.org/src/MORIYA/DBICx-Modeler-Generator-0.0003/examples/src/lib/MyApp/Schema/Artist.pm">examples/src/lib/MyApp/Schema/Artist.pm</a>のように書く必要があります。</p>

<h3>3.5. 自動生成されない内容をモデルクラスに記述</h3>

<p>スキーマと同様、モデルについても、自動生成されない内容を記述しておき、生成先とは別のパスに保存しておきます。この例では、<code>path/to/approot/lib/Model/</code>以下ではなく、<code>path/to/approot/src/lib/Model/</code>以下に保存することにしましょう。</p>

<pre><code>path/
    to/
        approot/
            lib/
            src/
                lib/
                    MyApp/
                        Model/
                            Artist.pm
                            Artist/
                                Rock.pm
                            Cd.pm
                            Track.pm
</code></pre>

<p>ここでもスキーマと同様に、或るクラスについて追加するコードが何もない場合は、そのクラスを<code>path/to/approot/src/lib/MyApp/Model/</code>以下に用意する必要はありません。モデルをスキーマの数だけ用意する必要は必ずしもありませんし、或いは逆に、<code>MyApp::Model::Artist::Rock</code>のようにスキーマにないモデルを用意することもあり得ます。</p>

<p>ここではスキーマと違って、<code>Text::MicroTemplate::Extended</code>のテンプレートとしてコードを記述します。具体的には、<code>Base</code>テンプレートを継承し、<code>code</code>ブロックに追加したいコードをそのまま記述します。具体的には、同梱した<a href="http://search.cpan.org/src/MORIYA/DBICx-Modeler-Generator-0.0003/examples/src/lib/MyApp/Model/Cd.pm">examples/src/lib/MyApp/Model/Cd.pm</a>のように書きます。</p>

<p>「自動生成されない内容」として追加するコードとしては、「スキーマクラスを透過的に取り扱う」以外にモデルクラスでやりたいこと全てです。そもそも「自動生成される内容」とは、<code>use DBICx::Modeler::Model</code>とPODの雛形程度に過ぎません。モデルには沢山のビジネスロジックが記述されるでしょう。</p>

<p>後はlestrratさんが『モダンPerl入門』で提唱するように、<code>MyApp::API</code>などのサービスクラスを用意し、モデルを跨いだロジックや、モデルを用意しない場合のスキーマクラス用のロジックを記述していくことになります。</p>

<p>あくまで例なので、ディストリビューションに同梱したサンプルにはビジネスロジックを何も記述していません。<code>MyApp::Model::Cd</code>では、<code>price</code>アトリビュートを追加したり、<code>play()</code>メソッドを追加している程度です。前者については、この例では<a href="http://search.cpan.org/perldoc?DBIx::Class::VirtualColumns"><code>DBIx::Class::VirtualColumns</code></a>を利用する方が良いでしょうけれども、<code>Moose</code>アトリビュートであれば</p>

<ul>
<li>ロールでのアトリビュートの定義</li>
<li><code>lazy_build</code>による相互依存の合理的表現</li>
<li>各種メソッドモディファイヤーでの柔軟な処理</li>
</ul>

<p>等々の魔法が使えるので、用途に応じて使い分けるのも一つの手かも知れません。</p>

<h3>3.6. コマンド一発でDB反映・スキーマ生成・モデル生成</h3>

<p>さあ、これで必要な材料は揃いました。後述するようにDIを利用したり、<a href="http://search.cpan.org/perldoc?DBICx::Modeler::Generator::CLI"><code>DBICx::Modeler::Generator::CLI</code></a>で調子に乗って<a href="http://search.cpan.org/perldoc?MooseX::Getopt"><code>MooseX::Getopt</code></a>を利用しているので、面倒な設定は全て外に出しておきましょう。</p>

<p>実行用のスクリプトでは<a href="http://cpansearch.perl.org/src/MORIYA/DBICx-Modeler-Generator-0.0003/examples/src/sbin/maintain_models.pl">examples/src/sbin/maintain_models.pl</a>のように、</p>

<pre><code>use DBICx::Modeler::Generator::CLI;
my $generator = DBICx::Modeler::Generator::CLI-&gt;new_with_options-&gt;generator;
$generator-&gt;deploy_database;    # DDLスクリプトをDBに反映
$generator-&gt;update_schemata;    # DBIx::Class::Schema::Loaderでスキーマクラス群を生成
$generator-&gt;update_models;      # Text::MicroTemplate::Extendedでモデルクラス群を生成
</code></pre>

<p>と書きます（上記の3.3.で、DDLスクリプトを介さずにスキーマを直接DBに反映済みであれば、<code>deploy_database()</code>メソッドを呼ばずにコメントアウトしてください）。</p>

<p>必要なオプションを付けて、上記のスクリプトを呼びます。</p>

<pre><code>maintain_models.pl -a MyApp -r path/to/root -d MySQL
</code></pre>

<ul>
<li><code>-a</code>, <code>--application</code>では、アプリケーション名<code>MyApp</code>や<code>My::App</code>などを指定します。</li>
<li><code>-r</code>, <code>--root</code>では、クラス群を生成する先である、アプリケーションルートパス<code>path/to/approot</code>などを指定します。</li>
<li><code>-d</code>, <code>--driver</code>では、お使いのRDBMSに適合したドライバーを指定します。MySQLならば<code>MySQL</code>、SQLiteならば<code>SQLite</code>です。</li>
</ul>

<p>DB接続用のユーザー・パスワードや、DBサーバーのホスト・ポートやら、諸々の指定についても、必要に応じて指定してください。</p>

<p><a href="http://search.cpan.org/perldoc?MooseX::SimpleConfig"><code>MooseX::SimpleConfig</code></a>も利用しているので、設定ファイルに上記を記述しておいて、<code>--configfile</code>で設定ファイルのパスを渡すだけでも良いです。</p>

<p>設定ファイルの例は<a href="http://search.cpan.org/src/MORIYA/DBICx-Modeler-Generator-0.0003/examples/src/myapp.yml">examples/src/myapp.yml</a>にあります。</p>

<h3>3.7. これで完成です！</h3>

<p>以上で、モデルクラス絡みのコード記述は終わりました。ウェブアプリケーションを作る場合には、<a href="http://search.cpan.org/perldoc?Catalyst">Catalyst</a>や<a href="http://github.com/typester/ark-perl">Ark</a>などのお好みのWAFを活用して、素敵なアプリケーションを作ってください。</p>

<p>モデルは一度作って終わりではなく、アプリケーションの一生を通して繰り返し成長し、かつ合理化していくものです。従ってその実装たるコードも変わっていくものですが、そのための作業が楽だとリファクタリングの心理的敷居が下がります。この些細なヘルパーモジュールが、モデル作成・保守作業の一助となれば、と思います。</p>

<p>なお、MySQL Workbenchと<code>DBIx::Class::Schema::Loader</code>の合わせ技は、冒頭に触れたYAPC::Asia 2009の特別研修の補講で教えていただいた内容のほぼそのままです。JPAのみなさん、どうもありがとうございます！</p>

<h2>4. 実用上の留意点</h2>

<p>趣味で開発中のプロジェクトの一つ（某MMORPG向けのERPやグループウェア）は80テーブル超に肥大化して、モデルもそれに関連してメタボ気味になりましたが、<a href="http://japan.cnet.com/interview/story/0,2000055954,20060067,00.htm">ドッグフードを食べて</a>みたところ、モデルの海を自在に泳いで開発出来ている実感があります。</p>

<p>ただし、実用する際には幾つかの点に留意する必要があります。</p>

<h3>4.1. 多対多の関係は未対応</h3>

<p>一番の留意点は、多対多(N:M)の関係のハンドルはこれからサポートされる予定である、ということです。これは<code>DBICx::Modeler</code>側の<a href="http://search.cpan.org/~rkrimen/DBICx-Modeler-0.005/lib/DBICx/Modeler.pm#Many-to-many_is_not_handled">0.005時点での制約</a>です。多対多の関係を透過的に扱いたい場合には、自分でロールを作って皮を被せるか、<code>DBICx::Modeler</code>自体を拡張するか、いずれかの対処が必要となります。</p>

<h3>4.2. スキーマ全てにモデルが必要ではない</h3>

<p>上述のスライドでdannさんが提唱されている通り、必ずしも全てのスキーマをモデルでラップする必要はありません。エンタープライズアプリケーションというのは、処理の少なからぬ割合がDBの単なるCRUD処理であることも珍しくありません。であれば、無駄に一つ層を設けるよりも、素直にそのままスキーマクラスを取り扱った方が、パフォーマンス面で優れるのみならず、開発生産性や保守性も優れることがあります。層を分かつ原理主義に陥ることなく、現実との距離感を適切に保って、妥協して行きましょう。</p>

<p>ただ、あまり早期から最適化を進めるのも考え物です。端から箸にも棒にも掛からない状態は論外ですが、それはまずい実装に起因することが多いはずで、層を分けた事による極端な性能劣化はあまり起き得ません。まずは綺麗な設計を推し進めてみて、それで性能面の顕著な問題が生じた場合にのみ、以降の保守開発に支障を来さない範囲で、最適化を図れば良いでしょう。</p>

<h3>4.3. 独自ツールへの不安？</h3>

<p>こうした開発効率化の錦の御旗は、あっけないほどに容易に切り裂かれることがあります。</p>

<p>真っ先に思い付く「“どこの馬の骨とも知れぬ”ツールを業務に使うことはまかりならん」、という例のアレについては、MySQL公式のツールなので、安心感があります。Oracle, DB2, Symfoware, HiRDBなどではなくMySQLを使える現場であれば、説得は比較的容易でしょう。</p>

<p>次に、「標準外のツールを使うのはまかりならん」という問題。社用PCには間違いなく入っているExcelと違い、遍在していないツールの使用は敷居が高いことがあります。私もチーム内でVisioを使って、良い顔をされなかった経験があります。</p>

<p>私はExcel方眼ドキュメント否定派ですが、基本要件など、顧客(ユー子ならば親会社)と協同する作業工程であればむしろExcelを活用すればいいと思います。一方でER図に顧客が手を入れる場面というのもあまり考えにくいので、ここは開発側のみで閉じた作業と位置付けて、独自ツールを使う論陣を張りたいところです。</p>

<p>いずれにせよ成果物としてER図の画像やテーブル定義書も生成出来るので、それを納品すれば良いことになります。</p>

<p>「うちはどうしてもExcelで納品しなければいけないんだ」という場合であっても、ER図であれば画像をそのままExcel文書に貼り付ければ良いですし、テーブル定義書もXML文書を（<a href="http://search.cpan.org/perldoc?XML::Parser">XML::Parser</a>などで）パースして、その結果を基に（<a href="http://search.cpan.org/perldoc?Spreadsheet::Write">Spreadsheet::Write</a>などで）Excel文書を生成すれば事足ります。</p>

<ins>追記: Standard版ではHTMLで出力出来ます。Community版は`*.mwb`をunzipして`document.mwb.xml`を扱う手があります。</ins>

<p>同じ作業をツールをまたいで何度も行う雇用創出的な仕事に従事することほど辛いことはありませんよね。</p>

<h3>4.4. MySQL Workbenchにこだわる必要はない</h3>

<p>ここまでMySQL Workbenchを猛プッシュして来ましたが、それ以外のツール（たくさんあります！）でも同様のことは出来ます。</p>

<p>DDLスクリプトを出力出来ること、ないしはDBに直接反映出来ることという条件さえ満たせば、<code>DBIx::Class::Schema::Loader</code>によるスキーマクラス群の生成以降の流れが一緒になるからです。</p>

<p>DB定義書やER図を素のExcelで（オートシェイプと表組みを駆使して）定義しているのでない限り、現在お使いのツールと組み合わせて、各現場なりの創意工夫で作業手順をカスタマイズすることも容易だと思います。</p>

<p>ディストリビューションに同梱した例ではSQLite用のDDLスクリプトを手書きしてしまいましたが、これは<a href="http://search.cpan.org/perldoc?DBICx::Deploy"><code>DBICx::Deploy</code></a>を利用して、スキーマクラス群を元にSQLiteのDBを生成する方が自然だと思います。</p>

<ins>追記: [SQLite出力用のプラグイン](http://www.henlich.de/software/sqlite-export-plugin-for-mysql-workbench/)があります。</ins>

<h3>4.5. ドッグフードの範囲は限定的</h3>

<p>私は<code>DBICx::Modeler::Generator</code>をいくつかのプロジェクトで実用していますが、それはあくまで日曜プログラミングでの範囲に過ぎません。エンタープライズアプリケーションと連呼しておきながら恐縮ですが、勤め先ではPerlを使った案件が殆ど全くないので、本当の業務アプリケーションへの適用事例はまだありません。</p>

<p>何事もそうですが、<code>DBICx::Modeler</code>共々、作ろうとしている（もしくは保守しようとしている）アプリケーションの特性を良く考えて、</p>

<ul>
<li>モジュールの利用が開発生産性および保守性に寄与するか</li>
<li>それらの利点が欠点と比べてなお有用か</li>
</ul>

<p>を、冷静に判断することが求められると言えるでしょう。</p>

<h3>4.6. 怪しげな名前空間</h3>

<p><code>DBICx::Modeler::Generator</code>は<code>DBICx::Deploy</code>と同様に間違い易い名前空間にいますが、それには</p>

<ul>
<li><a href="http://search.cpan.org/dist/DBI"><code>DBI</code></a>の拡張（e*X*tension）として<code>DBIx::Class</code>)があり、</li>
<li>それはしばしばDBIC（「でぃびっく」と読むようです）と略され、</li>
<li>さらにその拡張として<a href="http://search.cpan.org/search?query=DBICx%3A%3A&amp;mode=all">DBICx::*</a>という名前空間がある</li>
</ul>

<p>という理由があります。これは<code>DBICx::Modeler</code>のヘルパーモジュールである以上、宿命として諦めました。</p>

<h2>5. 中身の話</h2>

<p>さて、中身の話は無味乾燥になりがちですが、少し補足しておきます。</p>

<h3>5.1. MooseとOrochiで拡張容易性を確保</h3>

<p><a href="http://search.cpan.org/dist/Moose"><code>Moose</code></a>の他、lestrratさんが<a href="http://perl-users.jp/articles/advent-calendar/2009/hacker/15.html">15日目に紹介</a>された<a href="http://ja.wikipedia.org/wiki/%E4%BE%9D%E5%AD%98%E6%80%A7%E3%81%AE%E6%B3%A8%E5%85%A5">DI（dependency injection, 依存性注入）</a>フレームワークである<a href="http://search.cpan.org/dist/Orochi"><code>Orochi</code></a>を利用しています。</p>

<p>DIをまだまだ十全に使いこなしているとは言えないのですが、DIのおかげで疎結合な構造に出来たので、レゴブロックのように部品を組み替えることが容易です。このモジュールではごく一般的な要件にのみ対応した枠組みしかご用意していませんが、特殊用途への対応部分を肉付けすることも比較的容易なので、一つの実装参考例としてご覧頂ければ、と思います。</p>

<h3>5.2. <a href="http://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%B5%E3%82%AE#.E6.85.A3.E7.94.A8.E5.8F.A5.E3.80.81.E3.81.93.E3.81.A8.E3.82.8F.E3.81.96.E3.81.AA.E3.81.A9">獅子搏兎</a>気味なオーバーキルモジュール</h3>

<p>上述の通り、既に一発スクリプトが色々あるくらいですので、わざわざモジュール化するまでもないかも知れません。少なくとも、<code>Moose</code>やDIパターンを使わなくても十分書ける単純な処理であることは確かです。</p>

<p>正直なところ、鳩を撃つのに豆鉄砲でなく大砲を持ち出すような感もあります。ですが、このヘルパーモジュールが必要となりうる場面は、テーブルが満載のエンタープライズアプリケーションを作ろうとする場面だと認識しています。</p>

<p>また、そもそもこのモジュールはコードジェネレーターであるため、本質的に開発者向けのものです。生成されるコードと違って、このモジュール自体は本番環境（production environment）には配備（deploy）しません。</p>

<p>従って、依存モジュールについてはある種の開き直りに基づいて、楽に書けるものを利用させていただいています。</p>

<h3>5.3. でもバッドノウハウです</h3>

<p><a href="http://blog.myfinder.jp/">myfinderさん</a>が<a href="http://perl-users.jp/articles/advent-calendar/2009/hacker/18.html">18日目に紹介</a>された<a href="http://search.cpan.org/perldoc?DBIx::Encoding"><code>DBIx::Encoding</code></a>について、ご本人はBK（<a href="http://0xcc.net/misc/bad-knowhow.html">バッドノウハウ</a>）だと謙遜されています。一方、<code>DBICx::Modeler::Generator</code>は正真正銘のBKです。</p>

<p>DBの内容から生成したスキーマクラス(Aとします)に、それ以外の内容のみを記述した同名のクラス(A'とします）の内容を付加して、最終的なスキーマクラス(A''とします）を生成するというのが<code>DBIx::Class::Schema::Loader</code>の一つの流れです（上述のZIGOROuさんの記事の様に、もう一つの流れもあります）。</p>

<p>この流れを実現するために、<a href="http://search.cpan.org/perldoc?Class::Unload"><code>Class::Unload</code></a>でクラスを一旦アンロードした後に<code>@INC</code>を追加し、再度（最初とは別の場所にある）同名クラスをロードしています。</p>

<p><code>use lib</code>指定をし直して2度スクリプトを実行するということと本質的には同じで、ライブラリ探索パスの動的な切り替えのために<a href="http://gist.github.com/217006">別プロセスの<code>perl</code>を使い分けるという方法</a>よりはましとはいえ、これはかなり気持ちが悪い処理です。</p>

<h3>5.4.  モデルクラスは単なるコードジェネレーターとして生成</h3>

<p>モデルクラスのコード生成にあたっては、人気のテンプレートエンジン<a href="http://search.cpan.org/perldoc?Text::MicroTemplate::Extended"><code>Text::MicroTemplate::Extended</code></a>を利用しています。</p>

<p>であればスキーマクラスのコード生成も<code>DBIx::Class::Schema::Loader</code>に頼らず、DB解析結果の情報だけ拝借して生成する手もあるかと思いました。</p>

<p>上述のZIGOROuさんの記事でも、</p>

<blockquote>
  <p>あるいはSchema::Loader自体に手を加えるかですかね。</p>
</blockquote>

<p>という記述があります。しかし、現状で既に満足出来るワークフローになっているので、深追いはしないことにしました。</p>

<h2>6. まとめ ～ Perlはエンタープライズアプリケーションに向いています！</h2>

<p>以上、casual track的な内容で恐縮ですが、<code>DBIx::Class::Schema::Loader</code>のようにスキーマクラス群とモデルクラス群を一発生成する、<code>DBICx::Modeler::Generator</code>のご紹介でした。</p>

<p>Perlの内在思想として最も有名なのは<a href="http://en.wikipedia.org/wiki/There%27s_more_than_one_way_to_do_it">"There's More Than One Way To Do It"（TMTOWTDI, 方法は一つじゃない）</a>ですけれども、<a href="http://japan.cnet.com/interview/story/0,2000055954,20100857,00.htm">"Easy things should be easy, hard things should be possible"（簡単なことは簡単に、難しいことも可能に）</a>というものもあります。</p>

<p>Perlは<a href="http://ja.wikipedia.org/wiki/%E8%BB%BD%E9%87%8F%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E8%A8%80%E8%AA%9E">LL</a>の代表格なので、軽薄短小で小粋なシステム向きだと思われることがあります。しかしPerlは、Javaの専従分野と思われがちな重厚長大なエンタープライズアプリケーションでさえも開発出来るのです。「も出来る」というと、何か痩せ我慢をして無理にPerlを使っている後ろ向きな感触を受けかねませんので、さらに踏み込みましょう。Perlはエンタープライズアプリケーションでこそ開発生産性や保守性が華開くのだと。</p>

<p>例えば本稿でご紹介した要件・モデリング・実装までを乖離なく貫くことが出来る仕事の仕組みは、“エンタープライズアプリケーションをアジャイルに開発する”という新鮮な体験の一端をもたらしてくれます。DBひとつ作るのに、延々と続く会議や、山ほどの依頼書や、実装としばしば噛み合わない仕様書……等々が必要な仕事に閉口している方は、是非一度体験してみてください。</p>

<p>言語とは言語単独で評価すべきものではなく、便利な外部モジュールであるとか、確立された自動化テスト環境基盤の総体として評価すべきものではないでしょうか。『モダンPerl入門』にも記載されていますが、Perlではそれらが豊富に揃っているのです。</p>

<p>日本に於いて、そして世界に於いて、エンタープライズ分野でのPerlの存在感が増すことを願ってやみません。あなたもPerlで日本の情報システム産業を<a href="http://ja.wikipedia.org/wiki/%E8%A1%8C%E6%94%BF%E5%88%B7%E6%96%B0%E4%BC%9A%E8%AD%B0#.E4.BA.8B.E6.A5.AD.E4.BB.95.E5.88.86.E3.81.91">事業仕分け</a>してみませんか？　……ただしあまりに切り込みすぎて不興を買うこと（実話）を避けるためにも、上司や同僚への進言はくれぐれも慎重に！</p>

<h2>to be continued...</h2>

<p>さあ、JPerl Advent Calendar 2009 hacker trackも、遂にゴールが見えてきました。あと3日間です。明日23日目を執筆してくださる方を絶賛募集中です！</p>
]]></description>
      <dc:creator>gardejo</dc:creator>
      <pubDate>Thu, 24 Dec 2009 13:59:01 GMT</pubDate>
      <category></category>
    </item>
    <item>
      <title>FormValidator::LazyWay で検証ルールをまとめよう</title>
      <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/21.html</link>
      <description><![CDATA[<div class="section">
<p>
どうも、亀仙人になって鼻血ブーしたい vkgtaro です。ご機嫌いかがですか。亀仙人が最初なのかどうか知らないけど、鼻血を吹くというマンガ表現はすごく好きです。おっと、hacker track でした。<br />
ということで僕もハッカーではないけれど、自分がメンテナンスしてるモジュールの中から一つ紹介させてもらいますね。
</p>

<p>今日は <a href="http://search.cpan.org/dist/FormValidator-LazyWay/">FormValidator::LazyWay</a> で検証ルールをまとめちゃいます。</p>
</div>
<div class="section">
<h3>フォームの検証</h3>

<p>web アプリケーションを作っていると、どのページでも出てくる入力項目ってあると思います。</p>

<p>会員登録時のパスワード項目とログイン時のパスワード項目とユーザ情報変更時のパスワード項目と退会時に求められるパスワード入力項目、リマインダで再設定するパスワード入力項目……などなど。</p>

<p>
これらの項目がフォームごとにルールを指定してると、登録時は半角英数字と記号のみで6文字から14文字なのに、ログイン時は半角英数字のみで4文字から12文字になってたりとかおかしなことになったりしないでしょうか？<br />
「仕様書を見るから大丈夫だよ」という声も聞こえてきそうですが、定義はまとめておいたほうが変更しやすくて良いですよね。
</p>

<p>そこで FormValidator::LazyWay です。検証ルールをフォームごとにせずに項目ごとにして怠けましょう。</p>
</div>
<div class="section">
<h3> 設定</h3>

<p>こんな感じで設定を書きます。</p>

<pre>
my $config = {
    rules => [ 'Email', 'String' ], # 使用するルール
    setting => {
        strict => {
            # Email は Email の書式でないとだめ
            email    => {
                rule => ['Email#email']
            },
            # password は4文字から12文字で半角英数字のみ
            password => {
                rule => [
                    {   'String#length' => {
                            'min' => '4',
                            'max' => '12'
                        }
                    },
                    'String#ascii'
                ]
            },
        }
    },
    lang   => 'ja',
    # バリデーションに引っかかったときのメッセージに出力するラベル名
    labels => {
        ja => {
            email    => 'メールアドレス',
            password => 'パスワード'
        }
    },
};
</pre>
</div>
<div class="section">
<h3> 使用</h3>

<p>そしてこんな風に使います。</p>

<pre>
use FormValidator::LazyWay;

# この $fv オブジェクトはサイト全体で使い回すと良いよ
my $fv =  FormValidator::LazyWay->new($config);

# $q は CGI とか Catalyst::Request とかのオブジェクト
my $result = $fv->check($q, {
    required => [qw/email password/],
});
</pre>

<p>フォームによって必須項目変えたければ変えればいいです。</p>
<p>たとえば、ブログ的なもので登録時は内容のみ必須でタイトルはオプショナル。</p>

<pre>
my $result = $fv->check($q, {
    required => [qw/body/],
    optional => [qw/title/]
});
</pre>

<p>そして検索時は両方オプショナル。</p>

<pre>
my $result = $fv->check($q, {
    optional => [qw/title body/],
});
</pre>

<p>各項目の検証ルールはすでに決まってるので、使うときはどの項目を検証すればいいかだけ考えればいいですね。</p>
</div>
<div class="section">
<h3>検証結果</h3>

<p>検証結果には <a href="http://search.cpan.org/~taro/FormValidator-LazyWay-0.11/lib/FormValidator/LazyWay/Result/JA.pod">FormValidator::LazyWay::Result</a> オブジェクトが返ってきます。</p>

<pre>
# $result が FormValidator::LazyWay::Result オブジェクト
my $result = $fv->check($q, {
    required => [qw/nickname email password/],
    optional => [qw/message/]
});

if ( $result->has_error ) {
    print Dumper $result->error_message;

    # 検証結果に応じてメッセージを自動生成してくれます。
    # このメッセージは設定で指定した label と
    # ルールモジュールで設定された内容を掛け合わせてます。
    # $VAR1 = {
    #   'email' => 'メールアドレスが空です。',
    #   'password' => 'パスワードには4文字以上12文字以下が使用できます。'
    # };
}
else {
    # OK!
    # 検証されたデータは $result->valid にハッシュとして持ってます。
    # 検証後はこの valid で取り出した値を使いましょう
    print Dumper $result->valid;
}
</pre>
</div>
<div class="section">
<h3>同じ項目で違うルールを指定したい</h3>

<p>設定で level を変えてあげれば可能です。</p>
<p>ハッシュで書くと長いので YAML で書きますね。</p>

<pre>
config:
  setting:
    strict:
      email:
        rule:
          - Email#email
    loose:
      email:
        rule:
          - Email#email_loose
</pre>

<p>こんな風に strict と loose というのを用意してあげましょう。そして使うときはこんな感じ。</p>

<pre>
my $result = $fv->check( $q,
    {   required => [qw/email/],
        level => {
            email => 'loose'
        }
    }
);
</pre>

<p>email 項目が loose の方の設定で検証されるようになるよ。</p>
</div>
<div class="section">
<h3>項目をマージして検証</h3>

<p>複数の入力項目から一つの値にして検証もできます。たとえば、年月日がそれぞれ別項目で、妥当な日時か検証したいとき。</p>

<pre>
config:
  setting:
    merge:
      date:
        format: "%04d-%02d-%02d"
        fields:
          - year
          - month
          - day
    strict:
      date:
        rule:
          - DateTime#date
</pre>

<p>year, month, day という項目を %04d-%02d-%02d というフォーマットで date 項目を作って、date 項目に対して妥当な日時かどうか検証します。</p>
</div>
<div class="section">
<h3> filter -> rule -> fix</h3>

<p>FormValidator::LazyWay は、項目の検証の前後にフックを持っていて、検証前に項目の値の値と検証後の値の変更が可能です。</p>

<p>たとえば、ハイフンっぽい文字列をハイフンに統一したあとに、妥当な日時かどうか検証して、DateTime オブジェクトにして返すとか。</p>

<pre>
  setting:
    strict:
      date:
        filter:
          - Unify#hyphen
        rule:
          - DateTime#date
        fix:
          - DateTime#format:
              - '%Y-%m-%d'
</pre>

<p>問題無く検証できれば $result->valid->{date} が DateTime オブジェクトになって返ってくるよ。</p>

<p>そのほかにもメッセージのカスタマイズとか、param メソッド持ってないただのハッシュの検証とか色々機能があります。</p>

<p><a href="http://search.cpan.org/~taro/FormValidator-LazyWay-0.11/lib/FormValidator/LazyWay/JA.pod">日本語の POD もあるのでご参照いただければ幸いです</a></p>

<p>明日は……誰か書きませんか！</p>
<p>JPerl Advent Calendar hacker track の明日を作るのはあなたです！</p>
</div>
]]></description>
      <dc:creator>vkgtaro</dc:creator>
      <pubDate>Mon, 21 Dec 2009 10:01:01 GMT</pubDate>
      <category></category>
    </item>
    <item>
      <title>Windows環境でUnicodeファイルを扱う</title>
      <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/20.html</link>
      <description><![CDATA[<div class="section">
<p>こんにちわ！クリスマスを過ぎるとニートになることが決まっている xaicron です！</p>
<p>ハッカーでもなんでもないのですが、勢いに任せて登録してみました！！すいません＞＜</p>
</div>
<div class="section">
<h3> はじめに</h3>

<p>今日は、Windows環境以外の人は何にも関係ない、モジュール Win32::Unicode をご紹介しようとおもいます。</p>
<p>しかもまた文字コード関連の話ですね！！に<a href="http://perl-users.jp/articles/advent-calendar/2009/casual/10.html">Encodeでラクラク日本語処理</a>を読んでから詠むと、より理解が深まるかもしれません。</p>
</div>
<div class="section">
<h3> Win32::Unicodeって？</h3>

<p>Windows で perl を使う場合の選択肢としては ActivePerl と Strawberry Perl の二種類があげられます。</p>
<p>どちらも Windows 用にカスタマイズされたものなのですが、悲しいことにどちらの Perlを使っても Unicode 文字の含まれたファイルが扱えません。</p>

<p>でもそれだと悲しいので、Unicode なファイルも扱えるように書いてみたというわけです。</p>
</div>
<div class="section">
<h3> Unicode 文字の含まれたファイルはやっかい</h3>

<p>Windowsでは1つのファイルに対して上記3種類のものが扱えます。</p>

<ul>
<li> cp932</li>
<li> 8.3形式 (PROGRA~1とか)</li>
<li> Unicode (UTF-16LE)</li>
</ul>

<p>基本的に Perl は一番最初の cp932 としてファイル名を扱うようになっています。しかし、Windowsのマルチバイト環境では、Unicode のファイルが許されています。</p>
<p>しかし、Unicode 文字があるファイルは「?」となってしまい、Windows のシステムからすればそんなファイルはないので読み取れません。</p>
<p>iTunesとかで海外の曲を買ってると、知らず知らずのうちの、 Unicode ファイルができている、何てこともあります。</p>
<p>ためしに、「明日の天気は&#9731;.txt」というファイルが含まれているディレクトリのリストを表示してみましょう。</p>

<pre>
&gt;perl
opendir my $dh, '.' or die $!;
print join &quot;\n&quot;, readdir $dh;
closedir $dh;
__END__
.
..
今日の天気は?.txt
</pre>

<p>「&;#9731;」は cp932 に存在しない文字なので「?」に変換されてしまいました。</p>
<p>もちろん、 Perl プログラムに cp932 で埋め込むことはできません。 UTF-16LE で書いたところで、Perl自体がまともに動かないのでそれも不可能です。</p>
</div>
<div class="section">
<h3> Win32::Unicode を使う</h3>

<p>さて、それではどうすれば Unincode ファイルを扱えるのでしょうか？実は Windows 自体には Unicode ファイルを扱う API が用意されているのです。</p>
<p>そいつを使ってやれば、ちゃんと Unicode ファイルの操作ができます。Window の API を Perl からたたくのは、 Win32::API を使えば実現できます。</p>
<p>でも、こいつは Perl の書き方とはかけ離れているので、日常的に使うにはとってもめんどくさいです。</p>

<p>Win32::Unicode は Perl の書き方とほぼ同じように Unicode ファイルを扱えるように Win32::API をラップしたモジュールです。</p>
<p>use すると、大量の関数をエクスポートするのが特徴です。しかも、デフォルトでは、COREの関数をoverrideしないように、ほとんどのものに「W」というのがついています。</p>
<p>でもそれだとダサいので、最後のほうで「Win32::Unicode::Native」っていうのを紹介します。</p>

<p>Win32::Unicode では、すべての関数で flagged utf8 を使うことにしているので、モダンな気持ちを味わいながら書くことができると思います。</p>
</div>
<div class="section">
<h3> Win32::Unicode::File;</h3>

<p>Unicode 文字のファイルの読み書きができる IO::File っぽいインターフェースを持ったモジュールです。</p>
<p>ファイルの読み書きだけでなく、 rename、copy、unlink などもあります。</p>
<p>それでは、さっき開けなかった「明日の天気は&#9731;.txt」に何か書き込んで見ましょう。</p>

<pre>
use strict;
use warnings;
use utf8;
use Win32::Unicode::File;

my $fh = Win32::Unicode::File-&gt;new;
open $fh, '&gt;', &quot;明日の天気は\x{2603}.txt&quot;;
binmode $fh, ':encoding(cp932)';
print $fh &quot;こんにちわ！こんにちわ！\n&quot;;
close $fh;
</pre>

<p>とっても簡単ですね！！もちろん読み込むこともできます。</p>

<p>Win32::Unicode では-X 演算子を PP で実装する方法がわからなかったので、「file_type」という関数を使わなくてはなりません。さらに、ファイルサイズを取得する場合は、-s ではなく file_size を使用します。</p>
<p>そのかわり、Windows 固有のファイル属性の判定ができ、なおかつ、重ね打ちも可能です。</p>
<p>このあたり、何かいい手段があれば教えていただけると幸いです。</p>

<pre>
if (file_type rhf =&gt; $file_name) {
    # (読み込み専用で隠し属性のファイル)
}

my $size = file_size $file_name # -s $file_name と等価
</pre>

<p>あと、まだstatとかflockとかが未実装だったり、4GB以上のファイルがたぶん扱えなかったりしますが、そのうち実装されるんじゃないかと思います。</p>
</div>
<div class="section">
<h3> Win32::Unicode::Dir;</h3>

<p>次はディレクトリ周りです。使いかたは Win32::Unicode::File と大体一緒です。</p>
<p>こっちにも find、mkpath、cptree、mvtree など、よく使う関数も一緒にエクスポートします。</p>

<pre>
use strict;
use warnings;
use utf8;
use Win32::Unicode::Dir;

my $dh = Win32::Unicode::Dir-&gt;new;
$dh-&gt;open('.');
print join &quot;\n&quot;, $dh-&gt;readdir;
$dh-&gt;close;
</pre>

<p>こんな感じで使います。</p>
<p>でもこれを実行すると、</p>

<pre>
Wide character in print at readdir.pl line 8.
.
..
譏取律縺ｮ螟ｩ豌励・笘・txt
</pre>

<p>とかいって文字化けしてしまいます。</p>
<p>これは、readdir で帰ってくる文字が、 flagged utf8 だからなので当然といえば当然です。</p>
<p>でも、</p>

<pre>
use strict;
use warnings;
use utf8;
use Win32::Unicode::Dir;

binmode STDOUT =&gt; ':encoding(cp932)'; # 追加

my $dh = Win32::Unicode::Dir-&gt;new;
$dh-&gt;open('.');
print join &quot;\n&quot;, $dh-&gt;readdir;
$dh-&gt;close;
</pre>

<p>としたところで、</p>

<pre>
.
..
&quot;\x{2603}&quot; does not map to cp932.
明日の天気は\x{2603}.txt
</pre>

<p>と、怒られてしまいます。</p>
<p>なんだかここまでくれば、コマンドプロンプトにも「明日の天気は&#9731;.txt」って表示してほしいなーと思いました。</p>
<p>で、実はこのファイルがあるディレクトリで「dir」するとなんと普通に「明日の天気は&#9731;.txt」って表示されるんです！！</p>

<p>ということは、コマンドプロンプトにも Unicode を表示する API があるということですね。</p>
</div>
<div class="section">
<h3> Win32::Unicode::Console</h3>

<p>なので、つくりました。</p>
<p>Win32::Unicode::Console はコマンドプロンプトに Unicode 文字を表示できます。</p>
<p>printW printfW sayW dieW warnW という関数がエクスポートされます。</p>
<p>これらはすべて、 flagged utf8 を受け取ります。</p>

<p>これをつかってさっきのやつを書き換えると</p>

<pre>
use strict;
use warnings;
use utf8;
use Win32::Unicode::Dir;
use Win32::Unicode::Console;

binmode STDOUT =&gt; ':utf8'; # リダイレクトのため

my $dh = Win32::Unicode::Dir-&gt;new;
$dh-&gt;open('.');
printW join &quot;\n&quot;, $dh-&gt;readdir;
$dh-&gt;close;
</pre>

<pre>
.
..
明日の天気は&#9731;.txt
</pre>

<p>おおお！無事に表示されましたね！！</p>
<p>ちなみに、リダイレクト時には、通常の print が使用されるため、binmode しておいたほうがいいでしょう。</p>
</div>
<div class="section">
<h3> Win32::Unicode::Error</h3>

<p>次はエラーメッセージです。とはいっても、これがエクスポートするのは errorW のみです。</p>
<p>位置づけとしては、「$!」の代わりに使うという感じです。</p>
<p>これまた、$! を書き換える方法がわからなかったので、仕方なく という感じです。($! にはエラーコードを示す数値のみ代入でき、文字列を入れることはできない。)</p>
<p>メッセージはWindow API のエラーメッセージとなります。マルチバイト環境では日本語が返ってくるので、dieW errorW という風に使います。</p>

<pre>
use strict;
use warnings;
use utf8;
use Win32::Unicode::Error;
use Win32::Unicode::Console;
use Win32::Unicode::File;

my $fh = Win32::Unicode::File-&gt;new;
open $fh, '&lt;', '存在しないファイル' or dieW errorW;
print &lt;$fh&gt;;
close $fh;
</pre>

<p>これを実行すると、</p>

<pre>
指定されたファイルが見つかりません。 at errorW.pl line 8
</pre>

<p>みたいになります。</p>
</div>
<div class="section">
<h3> Win32::Unicode</h3>

<p>ここまで、４つぐらいのモジュールが登場しましたが、毎回全部 use するのはめんどくさいので、 use Win32::Unicode します。</p>
<p>これで、今までのモジュールがすべでロードされ、さらにそれぞれの関数もすべてエクスポートされます。</p>
</div>
<div class="section">
<h3> Win32::Unicode::Native</h3>

<p>でも、ここまで書いておいていうのもあれですが、正直「W」とないわー。</p>
<p>しかもファイルオープンとかも new しないいけないしめんどいなー。</p>
<p>どうにかならんかなー。ってことで、 Win32::Unicode::Native です。</p>

<p>こいつをuse すると標準関数を override します。とはいっても、CORE::GLOBAL::* を書き換えるわけではなく、単純に同名の関数をエクスポートして上書きします。</p>
<p>use した範囲だけ適用されるので、ほかのモジュールなどには影響しません。</p>
<p>唯一の例外が、 STDOUT です。これだけは、 Win32::Unicode::Console::Tie というモジュールに tie しているため、すべてに影響します。</p>

<pre>
use strict;
use warnings;
use utf8;
use Win32::Unicode::Native;

print &quot;flagged utf8な文字も普通にいける&quot;;

# Win32::Unicode::File-&gt;newとかしない
open my $fh, '&gt;', '森鷗外.txt' or die error;
print $fh &quot;ほげほげ&quot;;
close $fh;

# Win32::Unicode::Dir-&gt;newとかしない
opendir my $dh, &quot;\x{2600}&quot; or die error;
say join &quot;\n&quot;, readdir $dh;
close $dh;
</pre>

<p>ほとんど Perl の記法と一緒ですね！！</p>

<p>ちなみに、use Win32::Unicode '-native'としてもOKです。</p>
</div>
<div class="section">
<h3> Win32::Unicodeは遅い</h3>

<p>Win32::Unicode は普通に遅いです。</p>
<p>Perl がネイティブにやってくれるところをわざわざ PP で再実装しているので当然なのですが。</p>
<p>Unicode のファイルをPerlで扱う必要がまったくない場合は、使わないことをお勧めします。</p>

<p>また、当然のことながら(いないとはおもいますが・・・)モジュールなどには使わないほうがいいでしょう。</p>
<p>個人的に Windows 上で動かしたいスクリプトなどで重宝するんじゃないかなーと思っています。</p>
</div>
<div class="section">
<h3> まとめ</h3>

<p>Windows で Unicode のあれこれを扱えるモジュールを紹介しました。</p>
<p>このモジュールは、Windows でファイル操作をしているときに、扱えないファイルがあって、なんだか悲しかったのでつくりました。</p>
<p>本来であれば、Perl がわで実装されるべきではないかと思っていますが、影響範囲や実装方法などが、なかなかややこしいと思うので、昨今まで実装されていないのではないでしょうか？</p>
<p>将来的にはネイティブに扱えるようになるといいなーと思います。</p>

<p>また、現在は PP で書いていますが、 Win32 API をラップして使っているだけなので、XS で書いたほうがもっといい感じに実装できるでしょう。</p>
<p>XS かけるようになったら挑戦してみたいと思います。(そのときに Windows を使っていればね！)</p>

<p>というわけで、明日は vkgtaro さんです！！風のうわさでは仙人になるのではないかとのことですが、本当のところはどうなんでしょうか？</p>
<p>どんな話をしてくれるのか今からとっても楽しみですね・・・！！</p>
</div>
<div class="section">
<h3> SEE ALSO</h3>

<p><a href="http://subtech.g.hatena.ne.jp/miyagawa/20070513/1178988848">http://subtech.g.hatena.ne.jp/miyagawa/20070513/1178988848</a></p>
<p><a href="http://subtech.g.hatena.ne.jp/miyagawa/20070513/1179038019">http://subtech.g.hatena.ne.jp/miyagawa/20070513/1179038019</a></p>
<p><a href="http://subtech.g.hatena.ne.jp/miyagawa/20070815/1187134943">http://subtech.g.hatena.ne.jp/miyagawa/20070815/1187134943</a></p>
<p><a href="http://subtech.g.hatena.ne.jp/miyagawa/20070815/1187134943">http://subtech.g.hatena.ne.jp/miyagawa/20070815/1187134943</a></p>
<p><a href="http://xaicron.web.fc2.com/misc/presen/20091120/index.html">http://xaicron.web.fc2.com/misc/presen/20091120/index.html</a></p>


</div>
]]></description>
      <dc:creator>xaicron</dc:creator>
      <pubDate>Tue, 22 Dec 2009 17:00:01 GMT</pubDate>
      <category></category>
    </item>
    <item>
      <title>Module::Setup でらくらくモジュール作成</title>
      <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/19.html</link>
      <description><![CDATA[<div class="section">
<p>こんにちわ！こんにちわ！acotie hackathon の懇談会来てるのに一人寂しくビール飲んでる Yappo です。</p>
<p>皆様お元気ですか?僕は寂しいです。</p>

<p>さて今日は今さっき shipit したての Module::Setup について紹介しましょう。</p>
</div>
<div class="section">
<h3> what is Module::Setup?</h3>

<p>Module:Setup とは miyagawa さん作の pmsetup を CPANize した物です。</p>

<p>で、 pmsetup は何かというと Module::Starter などのモジュール開発を始める上の雛形を便利な感じで作ってくれる物です。</p>

<p>まぁ pmsetup でも良かったんですが、みんな好き勝手にオレオレ pmsetup を作り出してて無駄かなと思ったので CPANize したのでした。</p>
</div>
<div class="section">
<h3> how to use Module::Setup</h3>

<p>さぁ Module::Setup を使ってみましょう。使うには Module::Setup をインストールしといてください。</p>
<p>最新版は 0.07 です。必要におうじて cpanf で入れてください。</p>
<p>インストールすると module-setup というコマンドが適当な bin の中にインストールされるので、これを使って操作を行います。</p>

<p>インストールしてすぐにつかえるというワケではなくて、最初に初期化を行わないとなりません。</p>

<p>初期化には module-setup コマンドに --init というオプションを与えます。</p>

<pre>
]$ module-setup --init
Creating directory /Users/username/.module-setup
(略)
Creating directory /Users/username/.module-setup/flavors/default/template
Do you use SVN? [yN] [n] 
Do you use SVK? [yN] [n] 
Do you use Git? [yN] [n] y
You chose version control system: Git
Your name:  [Default Name] 名前を入力
Your email:  [default {at} example.com] メールアドレスを入力
Dump config /Users/username/.module-setup/flavors/default/config.yaml
</pre>

<p>だいたいこんな感じです。</p>
<p>途中で "Do you use " と聞いてる部分では、あなたが使いたい VCS のところで y を入れてください。</p>
<p>Your name と Your email は、作成する Module やら README やらで使われるので正しく入れておきましょう。</p>

<p>作成ログを見れば分かりますが ~/.module-setup に Module::Setup 用のファイル構造が作成されます。</p>


<p>Module::Setup では flavor という単位で作成するモジュールの雛形を複数保存しておくことができます。</p>
<p>今回は Default flavor を使いましたが、例えば XS の為を flavor を作りたい場合には、 Flavor のモジュール名と flavor 名をコマンドラインに与えます。</p>

<pre>
]$ module-setup --init --flavor-class=XS xs
Creating /Users/username/.module-setup/flavors/xs/template/Makefile.PL
(略)
Your name:  [Default Name] 名前を入力
Your email:  [default {at} example.com] メールアドレスを入力
Dump config /Users/username/.module-setup/flavors/xs/config.yaml
</pre>

<p> --flavor-class というオプションで flavor class を指定して最後の引数で作成する flavor の名前を指定します。</p>
<p>作成する flavor の名前はあなたの好きな物を選べますが、 flavor class は Module::Setup::Flavor::* の中のものを指定します。</p>

<p>今のところ以下の flavor class が標準で入っています。</p>

<pre>
$ ls lib/Module/Setup/Flavor
CatalystStarter.pm      Default.pm              PBP.pm                  XS.pm
CodeRepos.pm            GitHub.pm               SelectVC.pm
</pre>

<p>もし、あなたの名前空間で flavor class を作っていたら --flavor-class=+YourModule::FlavorName とかいう感じで指定できます。</p>
</div>
<div class="section">
<h3> 雛形を作る</h3>

<p>初期化がすんだら雛形を作りだす事ができます。</p>

<pre>
$ module-setup モジュール名
</pre>

<p>という感じで module-setup コマンドを叩くと、モジュール名の雛形がカレントディレクトリに作成されます。</p>

<pre>
$ module-setup My::Module
[1]: default
[2]: xs
Select flavor: [1] 
</pre>

<p>ここまでのステップを踏むと default と xs という flavor が install されていますので、ここでどの flavor を使うかの選択肢がでます。</p>
<p>ここでは 1 の default を選びましょう。</p>

<pre>
Select flavor: [1] 1
You chose flavor: default
Creating directory My-Module
Creating My-Module/.shipit
Creating My-Module/Changes
Creating My-Module/Makefile.PL
Creating My-Module/MANIFEST.SKIP
Creating My-Module/README
Creating My-Module/lib/My/Module.pm
Creating My-Module/t/00_compile.t
Creating My-Module/xt/01_podspell.t
Creating My-Module/xt/02_perlcritic.t
Creating My-Module/xt/03_pod.t
Creating My-Module/xt/perlcriticrc
Creating My-Module/.gitignore
Check Makefile.PL? [Yn]  [y] 
</pre>

<p>こんどは、 Makefile.PL を使って make test をして正しく雛形が出来ているかを聞かれています。</p>
<p>まよわず y だ</p>


<pre>
Check Makefile.PL? [Yn]  [y] y
(略
Git init? [Yn]  [y] 
</pre>

<p>make test が無事実行できたら git init を実行して git repository を作るかを聞いています。</p>
<p>なぜ git かというと、最初の module-setup --init の例で git を選んでいたのです。</p>

<p>せっかく git をえらんだので y です</p>

<pre>
Git init? [Yn]  [y] y
Initialized empty Git repository in /Users/username/p5-Module-Setup/My-Module/.git/
The following paths are ignored by one of your .gitignore files:
MANIFEST
Use -f if you really want to add them.
fatal: no files added
Created initial commit 277e984: initial commit
 12 files changed, 137 insertions(+), 0 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 .shipit
 create mode 100644 Changes
 create mode 100644 MANIFEST.SKIP
 create mode 100644 Makefile.PL
 create mode 100644 README
 create mode 100644 lib/My/Module.pm
 create mode 100644 t/00_compile.t
 create mode 100644 xt/01_podspell.t
 create mode 100644 xt/02_perlcritic.t
 create mode 100644 xt/03_pod.t
 create mode 100644 xt/perlcriticrc
$
</pre>

<p>無事プロジェクトが出来ました。</p>

<pre>
$ ls My-Module/
Changes         MANIFEST        MANIFEST.SKIP   Makefile.PL     README          lib             t               xt
</pre>

<p>Module::Setup では、基本的にモダンでかつ実用的な雛形を標準で用意しているので、 module-setup --init をしたあとは気軽にモジュール作成を行うことができます。</p>

<p>もし標準の雛形が気に入らなければ  ~/.module-setup/flavors/default/template/ 以下がひな形のファイル構造が入っているので、これ以下のファイルを編集することによってお気に入りの雛形にすることができます。</p>

<p>もちろん改造した雛形は --pack オプションによっていつでも flavor class にすることができます。</p>

<pre>
$ module-setup --pack MyFlavor default

package MyFlavor;
use strict;
use warnings;
use base 'Module::Setup::Flavor';
1;

=head1

MyFlavor - pack from default
</pre>

<p>また、こうして flavor class を開発するための便利オプションなども充実しているのですが紙面が足りなさすぎるので perldoc Module::Setup とか、それ以下のモジュールのドキュメントを詳しくよんでね！</p>
</div>
<div class="section">
<h3> 0.07 の新要素</h3>

<p>ながらく 0.06_01 だったのですが、先程 0.07 を shipit しました。</p>

<p>一番大きい要素を紹介します。</p>

<h4> add Helper support</h4>

<p>いわゆる Catalyst::Helper を作るのに便利な Helper サポートを追加しました。</p>

<p>Module::Setup::Helper になってます。</p>
<p>これはさらに hacker 向けではあると思うので、ここでは説明しませんが Ark の setup script などに使うと良いでしょう。</p>

<h4> XS flavor</h4>

<p>XS なモジュールを書くための便利な flavor が追加されています。</p>

<p>おそらく id:gfx がいい感じにモダンな雛形にしてくれるとおもいます！</p>

<h4> GitHub flavor</h4>

<p>GitHub ユーザ向けの flavor が追加されています。</p>

<pre>
$ module-setup --init --flavor-class=GitHub
(略
use readme_pod_from? (depend Module::Install::ReadmePodFromPod, installed 0.01 [Yn]  [y] 
use githubmeta? (depend Module::Install::GithubMeta, installed 0.10 [Yn]  [y] 
use readme_markdown_from? (depend Module::Install::ReadmeMarkdownFromPod, not installed [Yn]  [y] n
use readme_from? (depend Module::Install::ReadmeFromPod, installed 0.06 [Yn]  [y] 
github repository name format:  [p5-%s] 
Dump config /Users/ko/.module-setup/flavors/github/config.yaml
</pre>

<p>という感じで setup します。</p>

<p>途中で聞いているのは perl ./Makefile.PL をした時に、メインのパッケージから README ファイルを作るかどうか聞いています。</p>
<p>3種類ありますが、普通の README か pod 形式化 markdown 形式かというのが選べます。</p>
<p>全部 CPAN から手に入ります。</p>

<p>もう一つ GithubMeta を使うかどうかも聞いています。</p>
<p>これは META.yml のデータの元を GitHub のメタデータから作れる物です。</p>

<p>最後の github repository name format は、雛形作成時に GitHub のリポジトリを作るときのリポジトリ名のフォーマットを決めます。</p>
<p>作ったモジュールの名前が %s に置換されます。</p>

<p>実際に使う時は以下のようになります。</p>

<pre>
$ module-setup My::GitHub
[1]: default
[2]: github
[3]: xs
Select flavor: [1] 2
You chose flavor: github
Creating directory My-GitHub
Creating My-GitHub/.shipit
(略
create GitHub repository? [Yn]  [y]
github repository name:  [p5-My-GitHub]
github repository description:  [Perl Module of My::GitHub]
github repository homepage:  []
create private repository? [yN]  [n]
include /Users/username/p5-Module-Setup/My-GitHub/inc/Module/Install.pm
(略
 create mode 100644 xt/03_pod.t
 create mode 100644 xt/perlcriticrc
try git push to GitHub? [Yn]  [y]
Enter passphrase for key '/Users/username/.ssh/id_dsa': 
Counting objects: 19, done.
Compressing objects: 100% (16/16), done.
Writing objects: 100% (19/19), 2.47 KiB, done.
Total 19 (delta 1), reused 0 (delta 0)
To git@github.com:yappo/p5-My-GitHub.git
 * [new branch]      master -> master
</pre>

<p>という感じで、実際に GitHub 上にリポジトリを作って、作りたてのリポジトリに雛形を push できます。</p>

<p>さすがに作りたての物を push するなんて誰得すぎるけどついでに作っといた反省しない。</p>
</div>
<div class="section">
<h3> その他</h3>

<p>本当に Module::Setup はできることが多すぎて紹介しきれないんですが、例えば Helper suppoert を使わなくとも Module::Setup をあなたのモジュールに組み込むこともできる、組み込まれることを想定して作りこんであるので hack しがいがあると思います。</p>

<p>大抵のことはドキュメントに書いてあるつもりですし、もし不明点があれば僕を捕まえて聞いてみてください。</p>
</div>
<div class="section">
<h3> おわりに</h3>

<p>ということで shipit したての Module::Setup のご紹介でした。</p>

<p>あしたは Module::Setup 0.07 の shipit 作業を物理的に行なってくれた xaicron さんです。</p>

<p>なんか、この文章書いてたら懇談会のおわりのじかんっぽいんですけど、この補填は kan さんのお寿司であてたいとおもいます。</p>

</div>
]]></description>
      <dc:creator>myfinder</dc:creator>
      <pubDate>Sat, 19 Dec 2009 12:45:02 GMT</pubDate>
      <category></category>
    </item>
    <item>
      <title>DBIx::Encoding でPerlとDB間の文字コード &amp; utf8 flagを透過的に扱う</title>
      <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/18.html</link>
      <description><![CDATA[<div class="section">
<h3> はじめに</h3>

<p>はじめまして、myfinderといいます。</p>
<p>Casual Trackの記事をupしたときに話が出たので、記事を書いてみたいと思います。</p>

<p>今回ご紹介するモジュールは <a href="http://github.com/myfinder/DBIx-Encoding">DBIx::Encoding</a> です。</p>

<p>DBIx::Encodingは非常に小粒なモジュールですが、BKだなと自分でも思っています。</p>
<p>cho45さんの紹介されているモジュールと割と趣が近い気がします。</p>

<p>Casual Trackのxaicronさんの記事にもあるように、いわゆるモダンなPerl開発ではソースコードをUTF-8で記述し「use utf8;」し、文字列は「入力時にdecode、出力時にencode」し、プログラム中の文字はすべて内部表現で扱う様にするのが基本です。</p>
<p>この場合、データベースの文字コードも同様にUTF-8に統一したいところですが、歴史あるプロジェクトのデータベースを共有する場合、全部が全部UTF-8とは限りません。</p>

<p>データベース側を変えることができれば良いのですが、そうすることができない場合は涙を飲んで今の文字コードに従うか、アプリケーションもしくはフレームワーク、あるいはO/Rマッパのどこかで文字コードを変換しつつflaggedにしたり、その逆の操作をする層を用意する必要が出てきます。</p>

<p>このモジュールは、DBIを利用して取り出したデータを指定した文字コードでdecodeし、逆にDBへデータを入れるときには指定の文字コードでencodeする機能を提供します。</p>

<p>「DBIを使っていて、データベースの文字コードがEUC-JPやShift-JIS(cp932)で作られているが、プログラムをUTF-8で書きつつ文字列をutf8 flaggedで扱いたい」というなケースで、DBIx::Encoding は役に立つかもしれません。</p>
</div>
<div class="section">
<h3> 利用例</h3>

<p>モジュールがインストールしてあれば、DSNと一緒に渡すアトリビュートでRootClassと文字コードを指定するだけで利用できます。</p>

<pre>
use DBIx::Encoding;

my @dsn = (
   'dbi:mysql:host=localhost;database=mysql;mysql_socket=/tmp/mysql.sock;',
   'root',
   '',
   {
       RootClass => 'DBIx::Encoding',
       encoding  => 'cp932',
   },
);

my $dbh = DBI->connect(@dsn) or die;
</pre>

<p>このように記述するだけで、このDBハンドルメソッドあるいはステートメントハンドルメソッドで実行するクエリに関して</p>

<ul>
<li> データ取得の場合は指定文字コードでdecode</li>
<li> 作成、更新の場合は指定文字コードでencode</li>
</ul>

<p>という操作を行ってくれます。</p>

<p>このモジュールはDBIのサブクラスで、内部的にはDBIの各メソッドをオーバーライドして、それぞれを呼ぶ直前/直後にencode/decodeする形で動作します。</p>

<p>アトリビュートで指定するので、DBICなどのO/Rマッパから利用する事も可能です。</p>
</div>
<div class="section">
<h3> おわりに</h3>

<p>「え、それってMySQLならset namesして、mysql_enable_utf8指定すれば終わりじゃないの？」という突っ込みをしようとした方、その通りだと思います。</p>
<p>DBDやデータベースが提供してくれる機能で事が足りる場合は、そちらを利用する事をおすすめします。</p>

<p>このモジュールは、「データベースのバージョンが非常に古かったり、あるいはあまり手を付けられない境遇で、文字コードの変換とflagの扱いをちゃんとしたい」という要求を満たすために作ったものです。</p>

<p>多分にBKなモジュールではありますが、同じような境遇でお悩みの方への一つの解となれば幸いです。</p>
</div>
]]></description>
      <dc:creator>myfinder</dc:creator>
      <pubDate>Thu, 17 Dec 2009 15:17:01 GMT</pubDate>
      <category></category>
    </item>
    <item>
      <title>Sub::Pipe で UNIX pipe みたいな関数適用をする</title>
      <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/17.html</link>
      <description><![CDATA[<div class="section">
<p>こんにちは、s?fujiwara です。</p>

<p>本日は UNIX pipe みたいな関数適用ができる <a href="http://search.cpan.org/~fujiwara/Sub-Pipe-0.03/lib/Sub/Pipe.pm">Sub::Pipe</a> をご紹介します。</p>
</div>
<div class="section">
<h3> おことわり</h3>
<p>現在 CPAN に上がっている Sub::Pipe のコードは dankogai さんから寄贈していただいたものですが、元になった実装は <a href="http://d.hatena.ne.jp/sfujiwara/20090521/1242921474">自分の blog で書いたもの</a> なので、ここでは自分のモジュールとして紹介させていただきます。</p>
</div>
<div class="section">
<h3> これはなに?</h3>
<p>Sub::Pipe は非常に小粒なモジュールです。どれぐらい小粒かというと、本質部分は</p>
<pre>
package Sub::Pipe;
use overload '|' => sub { $_[0]->( $_[1] ) };
sub joint(&) { bless $_[0], __PACKAGE__ };
</pre>
<p>この 3行のみ、というぐらい小粒なわけですが、なかなかおもしろいモジュールじゃないかと思っています。</p>

<p>Sub::Pipe を使うと、UNIX pipe のような記法で適用する関数を作成できます。</p>
<pre>
use Sub::Pipe;
sub trim {
    joint {
        my $str = shift;
        $str =~ s/^\s+|\s+$//g;
        return $str;
    }
}
$foo = " foo " | trim;   # is $foo, "foo"
</pre>
<p>これは文字列の前後の空白を除去する trim という関数を用意した例です。</p>
<p>joint は | で適用できるオブジェクトを返すので、変数に代入して使ったり</p>
<pre>
$uc = joint { uc $_[0] };
"foo" | $uc;   # FOO
</pre>
<p>直接 joint { CODE } を適用することも可能です。</p>
<pre>
"foo" | joint { uc $_[0] }; # FOO
</pre>

<p>引数を取りたい場合はこう書きます。</p>
<pre>
sub replace {
    my ($regex, $to) = @_;
    joint {
        my $str = shift;
        $str =~ s/$regex/$to/g;
        return $str;
    };
}

"abcdefg" | replace("abc", "ABC");  # ABCdefg
</pre>
</div>
<div class="section">
<h3> なにがうれしいの?</h3>
<p>さて、これでは単に変態的な記法が追加されただけではないか、という疑問はごもっともです。</p>

<p>これはもともと <a href="http://search.cpan.org/~kazuho/Text-MicroTemplate-0.10/">Text::MicroTemplate</a> (T::MT)というテンプレートエンジン内で、<a href="http://search.cpan.org/~abw/Template-Toolkit-2.22/">Template-Toolkit</a> (TT) のようなフィルタ記法が使いたくて考案したものでした。</p>

<p>TT では</p>
<pre>
[% value | repalce("foo", "bar") | uri %]
</pre>
<p>のように、値の後ろに | でフィルタを並べて適用、という記法が使えます。</p>
<p>この記法は表示される対象である値が先頭に書かれているのが読みやすい。</p>

<p>T::MT は Perl がそのまま書けるのでとても柔軟で高速なのですが、以下のように書かざるを得ないため、対象の値が何なのかが一見して分かりにくいなあと思ったのでした。</p>
<pre>
&lt;?= uri( replace( $value, "foo", "bar" ) ) ?&gt;
</pre>
<p>ここで Sub::Pipe を使えば</p>
<pre>
&lt;?= $value | replace("foo", "bar") | uri ?&gt;
</pre>
<p>のようにできますよね。</p>
</div>
<div class="section">
<h3> 仕組み</h3>
<p>さて、Sub::Pipe はどのような仕組みでこの (変な) 記法を実装しているのかといいますと、『演算子オーバーロード』を使っています。詳しくは perldoc overload をご参照ください。(日本語訳は 5.6.1 のものですが <a href="http://perldoc.jp/docs/perl/5.6.1/overload.pod">こちらにあります</a>)</p>

<p>ソースコードをみていきましょう。</p>
<pre>
sub joint(&) { bless $_[0], __PACKAGE__ };
</pre>
<p>まず joint はコードリファレンスを引数に取り、それを bless した値を返すことで、関数の挙動をオブジェクト化します。</p>
<p>オブジェクトを作る場合はハッシュリファレンスを bless することが多いと思いますが、リファレンスならなんでも bless 可能なんですね。</p>

<p>そして演算子オーバーロードを使うと、あるパッケージのオブジェクトに対して、ある演算子が適用された場合の挙動を変更することができます。</p>
<pre>
use overload '|' => sub { $_[0]->( $_[1] ) };
</pre>
<p>ここでは通常 bit 演算の OR に使われる二項演算子 | を overload しているので、Sub::Pipe のオブジェクトに対して | が実行されると、sub { $_[0]->( $_[1] ) } が呼び出されます。</p>
<p>そこで、第1引数 $_[0] (これは bless されたコードリファレンスであるオブジェクト自身) に対して、第2引数 $_[1] (これは | の演算が適用される値です) を引数に与えて実行、という処理をしています。ややこしいですね!</p>

<p>A | B という演算なのに $_[0] が B で $_[1] が A なのはどうしてかというと、オブジェクトメソッドの最初の引数は常にそのパッケージのオブジェクトである必要から、引数の順序が入れ替わっているためです。</p>
<p>入れ替わっているかどうかは、$_[2] の値で判断できます。真なら入れ替わっていて、偽なら入れ替わっていない、という意味になりますがここも詳しくは perldoc overload の "Calling Conventions for Binary Operations" の項をご覧ください。</p>
<p># Sub::Pipe の場合はオブジェクト同士を | で演算することはありえないため、常に入れ替わっているものとみなして扱っています</p>
</div>
<div class="section">
<h3> 他に overload を使っているモジュールは?</h3>
<p>例えば DateTime がそうです。日付を < や > で比較したり、+ で DateTime::Duration を足したりできるのは overload のおかげです。</p>
<p>他にも、オブジェクトを足したり引いたり比較したりできるモジュールは多々ありますよね。</p>
</div>
<div class="section">
<h3> まとめ</h3>
<p>以上 UNIX pipe のような記法で関数適用を可能にする Sub::Pipe の紹介でした。</p>
<p>正直、普通のスクリプト内で使うのは止めたほうがいいでしょうが、テンプレート内の DSL としてはなかなか使えるんじゃないかと思っています。</p>

<p>明日は myfinder さんです。お楽しみに!</p>
</div>
]]></description>
      <dc:creator>fujiwara</dc:creator>
      <pubDate>Wed, 16 Dec 2009 15:00:00 GMT</pubDate>
      <category></category>
    </item>
    <item>
      <title>Have Your Own Perl!</title>
      <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/16.html</link>
      <description><![CDATA[<div class="section">
<p>こんにちは、<a href="http://blog.livedoor.jp/dankogai/">dankogai</a>です。<a href="http://search.cpan.org/dist/Encode/">Encode.pm</a>のメンテナーとかしています。なのでEncodeのことでも書こうかと思ったのですが、すでに<a href="http://perl-users.jp/articles/advent-calendar/2009/casual/10.html">Encodeでラクラク日本語処理</a>をxaicronに書かれちゃいました。</p>

<p>それじゃ何書く?と思ったら、残ってましたよ。最も大事なものが。</p>
</div>
<div class="section">
<h3> Perlハッカーに最も必要なもの</h3>

<p>ここでなぞなぞです。Perlハッカーにとって最も必要なのは何でしょうか?</p>

<p>Perlそのもの、ですよね。</p>

<p>そうなんです。どんなすばらしいPerlモジュールも、Perl本体がなければ動きません。Perlはモジュールがなくてもなんとか動きますが、その逆は真ではないのです。</p>
</div>
<div class="section">
<h3> 自分専用Perlを持つべき理由</h3>

<p>あまりに当たり前のこの事実ですが、その一方、およそ Windows を除けばPerlは主要OSにははじめから組み込まれているのでそのことになかなか気がつきません。Perlがそこにあること、それは非Perlプログラマーにとってさえ空気がそこにあるがごとき前提条件となっています。 </p>

<p>だから、Perlがそこにあることを前提にしてPerlハックにいそしみたいところですが、ちょっと待って下さい。Perlはあなた自身でビルドできますし、Perlを本格的に使いたかったらそうするべきなのです。理由は以下のとおりです。</p>

<h4> あなたのOSがPerlを必要としている</h4>

<p>なぜ主要OSにはPerlが付属しているのか。OSが必要としているからです。ということは、もしOS付属のPerlに何かあった場合、OSの挙動がおかしくなる可能性があるということです。実際、<a href="http://search.cpan.org/dist/libwww-perl">LWP</a>をインストールするとMac OS Xの/usr/bin/headがHEADコマンドに置き換えられてしまうということもかつてありました。</p>

<p>OS付属のPerlとは独立したPerlを持てば、こうした可能性はほとんどゼロになります。</p>

<h4> バンドル版Perlは最新とは限らない</h4>

<p>OSのリリーススケジュールとPerlのリリーススケジュールは異なります。ですから最新のOSが、最新のPerlをバンドルしているとは限りません。例えば Mac OS X v10.6 = Snow Leopard が発売されたのは今年の9月ですが、付属しているのは Perl 5.10.0 で、最新版のPerl 5.10.1とはバージョンにずれがあります。</p>

<p>FreeBSDに至ってはさらに保守的で、OSの最小構成にはPerlを載せていない上に、Ports/Packageがデフォルトでインストールするのは Perl 5.8.9 です。</p>

<p>最新のPerlを使いたかったら、やはり自分でビルドするしかないのです。</p>

<h4> スーパーユーザー権限がない</h4>

<p>レンタルサーバーなどでPerlを利用する際には、上の条件に加えてさらにこの条件が加わります。最新のPerlどころかモジュールをインストールするにも支障をきたすのです。</p>

<p><a href="http://search.cpan.org/dist/local-lib/">local::lib</a>などを使ってこの制限を乗り越える方法は確かにありますが、実は自分用のPerlをホームディレクトリにインストールしてそれを使う方が簡単だったりもします。</p>
</div>
<div class="section">
<h3> DIYの実際</h3>

<p>というわけであなたは自分のPerlを持つことに決めたのですが、一体どうしたらよいのでしょう。</p>

<p>大まかな流れでいくと、以下のとおりとなります。</p>

<pre>
% curl -O http://www.cpan.org/src/perl-5.10.1.tar.bz2
% tar jxvf perl-5.10.1.tar.bz2
% cd perl-5.10.1
% sh Configure -des
% make
% sudo make install
</pre>

<p>最初の curl -O は Mac OS X の場合ですが、ここは fetch なり wget なり各OSの流儀にあわせてください。なんならWebブラウザーでダウンロードしても構いません。</p>

<p>これで自分用のPerlは出来ることは出来るのですが、自分用であっても「おしきせ」のPerlしか出来ません。自分用というからには Configure の指定をもっと細かくする必要があります。</p>
</div>
<div class="section">
<h3> Configure の実際</h3>

<p>何のオプションも付けないで Configure した場合、Perlのデフォルトがそのまま使われますが、OSベンダーでさえそんなことはしていません。実際に各OSにバンドルされているPerlが、どのように Configure されているのかを確認してみることにしましょう。ちなみに確認するためには</p>

<pre>
/path/to/perl -MConfigure -le 'print $Config{config_args}'
</pre>

<p>とします。</p>

<h4> Mac OS X v10.6.2</h4>
<p>v5.10.0</p>
<pre>
-ds -e -Dprefix=/usr -Dccflags=-g  -pipe  -Dldflags= -Dman3ext=3pm -Duseithreads -Duseshrplib -Dinc_version_list=none -Dcc=gcc-4.2
</pre>
<h4> Ubuntu 9.10</h4>
<p>v5.10.0</p>
<pre>
-Dusethreads -Duselargefiles -Dccflags=-DDEBIAN -Dcccdlflags=-fPIC -Darchname=i486-linux-gnu -Dprefix=/usr -Dprivlib=/usr/share/perl/5.10 -Darchlib=/usr/lib/perl/5.10 -Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5 -Dvendorarch=/usr/lib/perl5 -Dsiteprefix=/usr/local -Dsitelib=/usr/local/share/perl/5.10.0 -Dsitearch=/usr/local/lib/perl/5.10.0 -Dman1dir=/usr/share/man/man1 -Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1 -Dsiteman3dir=/usr/local/man/man3 -Dman1ext=1 -Dman3ext=3perl -Dpager=/usr/bin/sensible-pager -Uafs -Ud_csh -Ud_ualarm -Uusesfio -Uusenm -DDEBUGGING=-g -Doptimize=-O2 -Duseshrplib -Dlibperl=libperl.so.5.10.0 -Dd_dosuid -des
</pre>
<h4> FreeBSD 8-STABLE</h4>
<p>v5.8.9</p>
<pre>
-sde -Dprefix=/usr/local -Darchlib=/usr/local/lib/perl5/5.8.9/mach -Dprivlib=/usr/local/lib/perl5/5.8.9 -Dman3dir=/usr/local/lib/perl5/5.8.9/perl/man/man3 -Dman1dir=/usr/local/man/man1 -Dsitearch=/usr/local/lib/perl5/site_perl/5.8.9/mach -Dsitelib=/usr/local/lib/perl5/site_perl/5.8.9 -Dscriptdir=/usr/local/bin -Dsiteman3dir=/usr/local/lib/perl5/5.8.9/man/man3 -Dsiteman1dir=/usr/local/man/man1 -Ui_malloc -Ui_iconv -Uinstallusrbinperl -Dcc=cc -Duseshrplib -Dinc_version_list=none -Dccflags=-DAPPLLIB_EXP="/usr/local/lib/perl5/5.8.9/BSDPAN" -Doptimize=-O2 -pipe -fno-strict-aliasing -Ud_dosuid -Ui_gdbm -Dusethreads=n -Dusemymalloc=y -Duse64bitint
</pre>

<p>なんか目のつぶれそうなほど長いオプションをいずれも付けていますが、自分用のPerlを作るときにはこれほど長いものは必要ありません。ちなみに私が Mac OS X で日常的に使っている Perl は、以下のように Configure してあります。</p>

<pre>
% sh Configure \
　-DDEBUGGING \
　-Doptimize='-g -pipe -Os' \
　-Dusethreads \
　-Dusemultiplicity \
　-Duse64bitall \
　-Dprefix=/usr/local \
　-des
</pre>

<p>それでは、一つ一つ解説していきましょう。</p>

<table>
<tr>
<td>-DDEBUGGING</td>
<td>Perl自体のデバッグ機能を有効に</td>
</tr>
<tr>
<td>-Doptimize='-g -pipe -Os'</td>
<td>最適化オプション。-DDEBUGGINGを指定する際には必ず-gを含めます</td>
</tr>
<tr>
<td>-Dusethreads</td>
<td>スレッドサポートを有効に</td>
</tr>
<tr>
<td>-Dusemultiplicity</td>
<td>組み込み(mod_perlなど)のサポートを有効に</td>
</tr>
<tr>
<td>-Duse64bitall</td>
<td>64bitフルサポートを有効に</td>
</tr>
<tr>
<td>-Dprefix=/usr/local</td>
<td>Perlのインストール先を/usr/localに</td>
</tr>
<tr>
<td>-des</td>
<td>すぐにmakeできるよう準備を整えるおまじない。ほぼどんな場合でも指定しておきます</td>
</tr>
</table>

<p>これで"My Perl Ultimate Edition"がビルドできます。</p>

<h4> -Dprefix</h4>

<p>この中でも、おそらく最重要なのは -Dprefix オプションなので、少し解説しておきます。例えばここに/usrを指定した場合、</p>

<table>
<tr>
<td>実行ファイル</td>
<td>/usr/bin/perl</td>
</tr>
<tr>
<td>ライブラリ</td>
<td>/usr/lib/perl5/5.10.1</td>
</tr>
<tr>
<td>マニュアル</td>
<td>/usr/share/man</td>
</tr>
</table>

<p>といった具合にインストールされるわけですが、これを$HOMEにすれば、自分のホームディレクトリ直下にPerlをインストールすることが出来るので、スーパーユーザー権限が不要になるというわけです。もちろんその場合、OS付属のPerlより your perl が優先されるよう、$HOME/binを$PATHに加えるのは言うまでもありません。</p>
</div>
<div class="section">
<h3> くわしくは</h3>

<p>INSTALL および README.os を参照してください。ここでosは各OSの名前。例えば Mac OS X なら README.macosx です。</p>

<p>で、明日は...誰が書くんだろ?</p>

<p>Dan the Contributing Perl Monger</p>
</div>
]]></description>
      <dc:creator>dankogai</dc:creator>
      <pubDate>Tue, 15 Dec 2009 17:15:00 GMT</pubDate>
      <category></category>
    </item>
    <item>
      <title>Orochi紹介</title>
      <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/15.html</link>
      <description><![CDATA[<div class="section">
<h3> Orochiってなんじゃらほい</h3>

<p>Orochi (<a href="http://search.cpan.org/dist/Orochi">http://search.cpan.org/dist/Orochi</a>) は一種のDependenc Injection(DI) フレームワークです。それぞれなんらかの依存関係があるオブジェクト群を初期化するコードを書くのに飽き飽きしていたので、書きました。</p>

<p>なお元々Bread::Board (<a href="http://search.cpan.org/dist/Bread-Board">http://search.cpan.org/dist/Bread-Board</a>) にこの機能を追加したかったので、将来的に同等の機能がBread::Boardに実装された場合はそちらと統合する可能性が高いです。</p>
</div>
<div class="section">
<h3> Orochi使用例</h3>

<p>例えば以下のよう構成のシステムがあったとします。</p>

<pre>
依存関係ダイアグラム
====================

                requires   --------------  requires
                ---------> | MyApp::Log |-----------> $file
   ---------    |          --------------
   | MyApp |----|
   --------     |          -----------------
                ---------> | MyApp::Schema | -------> @connect_info
                requires   -----------------
</pre>

<p>MyAppはLogオブジェクトとDBIx::Classスキーマに依存し、それらも$fileと@connect_infoにそれぞれ依存すると仮定します。これを実装するには以下のようなコードを書くことになります：</p>

<pre>
package MyApp;
use Moose;
use namespace::autoclean;

has log => (
    is => 'ro',
    isa => 'MyApp::Log',
    required => 1,
);

has schema => (
    is => 'ro',
    isa => 'MyApp::Schema',
    required => 1,
);

sub run {
    ....
}

__PACKAGE__->meta->make_immutable();

1;
</pre>

<pre>
package MyApp::Log;
use Moose;
use namespace::autoclean;

has file => (
    is => 'ro',
    isa => 'Str',
    required => 1,
);

__PACKAGE__->meta->make_immutable();

1;
</pre>

<pre>
package MyApp::Schema;
use Moose;
use namespace::autoclean;

extends 'DBIx::Class::Schema'

1;
</pre>

<p>このような構造を用意すると、依存関係を満たして初期化するために以下のようなコードを書く必要があります。</p>

<pre>
use MyApp;
use MyApp::Log;
use MyApp::Schema;

my $log = MyApp::Log->new(file => "/path/to/log.txt" );
my $schema = MyApp::Schema->connection('dbi:mysql:dbname=foo', 'user', 'password');
my $app = MyApp->new(
    log => $log,
    schema => $schema
);
$app->run();
</pre>

<p>この程度であれば一個一個手で書いていけば済む話ですが、依存関係が増えていくにしたがい管理するオブジェクト数とともに書かなければいけない事項があ指数関数的に増えていきます。</p>

<p>そうなってしまっては後から依存関係を追加・変更したりする場合に困ってしまいます。また、例えばWAF内で一旦その初期化を記したとしてもコマンドラインツールから同じオブジェクト群を作成するコードを用意しなければなりません。もちろんやってできないことはありませんが、かなり面倒くさくなってきます。</p>

<p>Orochiはこの作業をなるたけ1回だけ記してあとは自動的にオブジェクト群を生成できるようにするためのツールです。</p>
</div>
<div class="section">
<h3> Orochi の基本</h3>

<p>Orochiは前項で紹介した仕組みの下位レイヤーを構成します。この部分は詳細を説明してもあまりおもしろくありませんのでざっくり割愛します。基本的な動作としては以下のようになります：</p>

<pre>
my $orochi = Orochi->new();

# 遅延評価でMyClass->new(\%args)を実行してオブジェクトに転換して
# 返すよう指定
$injection = $orochi->inject_constructor( $key => (
    class => 'MyClass',
    args  => \%args
) );
        
$object    = $injection->expand(); # この時点で展開
$object    = $orochi->get($key);   # 同等。$keyから$injection
                                   # オブジェクトを検索してexpand()する

# 後でそのままの値を返すよう指定
$injection = $orochi->inject_literal( $key => $value );
$value     = $injection->expand(); # $valueを返すだけ
$value     = $orochi->get($key);   # 同等

# bind_value は inject_* で指定した値をexpand()したものを遅延評価する。
# この場合、 $class->new({ arg1 => $arg1, arg2 => $arg2 }) が
# get()/expand() 時に呼ばれる
$orochi->inject_constructor(
    $key => (
        class => $class,
        args  => {
            arg1 => $orochi->bind_value( $key_for_arg1 ),
            arg2 => $orochi->bind_value( $key_for_arg2 ),
        }
    )
);
</pre>

<p>キモはinject_constructorでコンストラクタとその引数を指定して遅延評価できることと、引数そのものも同じ仕組みで遅延評価し依存関係の関係性だけを表記できることです。</p>
</div>
<div class="section">
<h3> MooseX::Orochi</h3>

<p>Orochiの最終的な目的はMooseオブジェクト群を自動的にフレームワークに登録して、初期化が終わった状態でインスタンスを自動的に作成してもらう事です。Orochiに同梱されているMooseX::Orochiを使用するとMooseクラスにOrochi要のインジェクションルールを書き込んで置くことができるようになります：</p>

<pre>
package MyApp;
use Moose;
use MooseX::Orochi;
use namespace::autoclean;

# 以下の宣言は、後に
#   MyApp->new( {
#       log =>  .... # $orochi->get('myapp/log') を評価した結果
#       scuema =>  .... # $orochi->get('myapp/schema') を評価した結果
#   } );
# と評価されるよう指定しています
bind_constructor myapp => (
    args => {
        log => bind_value 'myapp/log',
        schema => bind_value 'myapp/schema',
    }
);

sub run { ... }

__PACKAGE__->meta->make_immutable();

1;
</pre>

<p>このように "use Moosex::Orochi" とすることにより、現在のスコープで "bind_constructor" と "bind_value" というDSL／関数が使用可能になります。</p>

<p>bind_constructorは前項のinject_constructorと同じように特定のキーと現在定義中のクラスのインスタンスを結びつけます。</p>

<pre>
package MyClass;
bind_constructor $key => ( %params );
</pre>

<p>この定義をすることによって、後に以下のようにインスタンスを取得したい旨を宣言しているわけです：</p>

<pre>
my $obj = $orochi->get($key)
</pre>

<p>なお、%paramsにクラスを指定する必要はありませんので、arg1とarg2が必要なMooseオブジェクトを定義するには</p>

<pre>
package MyClass;
use Moose;
sue MooseX::Orochi;
use namespace::autoclean;

bind_constructor 'myclass' => (
    args => {
        arg1 => bind_value 'myclass/arg1',
        arg2 => bind_value 'myclass/arg2'
    }
);
</pre>

<p>というようにすれば、OrochiはMyClassの引数の設定をしてくれます。もちろんmyclass/arg1とmyclass/arg2は別途注入する必要があります。</p>

<p>他のクラスも同じ仕組みを使って設定を記入していきます：</p>

<pre>
package MyApp::Log;
use Moose;
use MooseX::Orochi;
use namespace::autoclean;

bind_constructor 'myapp/log' => (
    args => {
        file => bind_value 'myapp/log/file'
    }
);

__PACKAGE__->meta->make_immutable();

1;
</pre>

<pre>
package MyApp::Schema;
use Moose;
use MooseX::Orochi;
use namespace::autoclean;

extends 'DBIx::Class::Schema';

bind_constructor 'myapp/schema' => (
    args => bind_value 'myapp/schema/connect_info',
    deref_args => 1,
);

__PACKAGE__->meta->make_immutable();

1;
</pre>

<p>これができたところで、inject_class() メソッドを使って、クラスの中に保存された設定をOrochiインスタンスに注入すれば、あとはget() で作成されたインスタンスを取得するだけです：</p>

<pre>
use Orochi;

my $o = Orochi->new();

# クラス定義から依存関係等を注入
$o->inject_class('MyApp');
$o->inject_class('MyApp::Log');
$o->inject_class('MyApp::Schema');

# このあたりは設定ファイルから読み込むのが吉
$o->inject_literal(
    'myapp/schema/connect_info' => 
        [ 'dbi:mysql:dbname=foo', 'username', 'password' ],
);
$o->inject_literal(
    'myapp/log/file' => '/path/to/log.txt',
);

my $app = $o->get('myapp');
$app->run();
</pre>

<p>なお、ここまでの説明はMooseX::OrochiのPODにも書いてありますのでそちらもあわせて参照してください。</p>
</div>
<div class="section">
<h3> MooseX::Orochiの継承</h3>

<p>一度特定のクラスにMooseX::Orochiの設定を施せばその子クラスも同じ設定を引き継ぐ事ができます。</p>

<pre>
package Parent;
use Moose;
use MooseX::Orochi;
use namespace::autoclean;

bind_constructor 'myapp' => (
    args => {
        arg1 => bind_value 'myapp/arg1',
        arg2 => bind_value 'myapp/arg2',
    }
);
</pre>

<pre>
package Child;
use Moose;
use namespace::autoclean;

extends 'Parent';
</pre>

<pre>
use Orochi;

my $orochi = Orochi->new();
$orochi->inject_literal('myapp/arg1' => 'value1');
$orochi->inject_literal('myapp/arg2' => 'value2');
$orochi->inject_class('Child');

my $child = $orochi->get('myapp');
</pre>

<p>このようにすることでMooseX::Orochiの設定を引き継ぐ事ができるのでオブジェクトの使い回しも簡単にできます。子クラスでbind_constructorを使用すれば子クラス特有の設定でオーバーライドすることも可能です。</p>
</div>
<div class="section">
<h3> CatalystでOrochiを使う</h3>

<p>Catalystは元からある程度の自動初期化機能を搭載していますが、それはあくまでCatalystというコンテキスト内であって、それ以外のコンテキストでは同様の仕組みは使えません。なので私はいわゆるアプリケーションロジック部分をCatalystから切り離し、Orochiを通して オブジェクト群を作成しています。</p>

<p>この仕組みをCatalyst内で簡単に扱うために Catalyst::Model::Orochi(<a href="http://search.cpan.org/dist/Catalyst-Model-Orochi">http://search.cpan.org/dist/Catalyst-Model-Orochi</a>) もCPANに登録されており、Orochiを設定ファイルからコントロールすることができます。</p>

<pre>
package MyApp::Model::Orochi;
use Moose;
use namespace::autoclean;

extends 'Catalyst::Model::Orochi';

__PACKAGE__->meta->make_immutable();

1;
</pre>

<p>使用する際には model() 関数からOrochiインスタンスにアクセスすることができます：</p>

<pre>
package MyApp::Controller::Root;
use Moose;
use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller' }

sub hoge :Local {
    my ($self, $c) = @_;

    my $thing = $c->model('Orochi')->get('whatever');
}

__PACKAGE__->meta->make_immutable();

1;
</pre>

<p>このようなモデルを設定しておき、必要なオブジェクト群にMooseX::Orochiを適用するだけであとは基本的にmyapp.yaml内に記述を追加するだけで様々な値を注入することができます：</p>

<pre>
Model::Orochi:
  injections:
    key1: value1  # リテラル値を注入
    key2: value2
    key3: value3
  classes:
    - Class1      # 明示的に指定されたクラスを注入
    - Class2
    - Class3
  namespaces:
    - MyApp::API  # MyApp::API 内の全てのMooseX::Orochiクラスの
                  # 定義を注入
</pre>

<p>この仕組みを使うと、1行も初期化コードを書かずにオブジェクト群を生成することができます</p>
</div>
<div class="section">
<h3> まとめ</h3>

<p>本稿の最初に書いた通り、もうオブジェクト群を初期化するのにとんと嫌気がさしていたのでこの仕組みは実際にプロダクション環境で使い始めています。以下の注意点等が問題にならないようであれば、是非一度さわってみてください！</p>

<ul>
<li> 使いどころ
<ul>
<li> お互い依存関係のあるオブジェクト群が比較的多くある</li>
<li> Catalyst（もしくはその他のWAF)の中だけでなく、違うコンテキスト（例：コマンドラインツール）などでも同じオブジェクト群の初期化が発生する</li>
<li> 正直初期化コードをもう書きたくない人向け</li>
</ul>
</li>
</ul>

<ul>
<li> 注意点
<ul>
<li> DIは全てのアプリケーションで必要なわけではないので、（人的、リソース的）コストとのバランスを考えて導入したほうがいい</li>
<li> Mooseを使わないなら、Orochiも使わない</li>
<li> Orochiは再帰的な依存関係の自動解決しません。その場合はOrochi::Injection::Setterを使います</li>
<li> MooseX::Orochiを使うと基本的に1クラス＝1インスタンスになります。複数必要な場合は違う方法で指定する必要があります</li>
</ul>
</li>
</ul>

<p>明日は・・・うほ！<a href="http://perl-users.jp/articles/advent-calendar/2009/hacker/16.html">dankogai</a>さんです！</p>
</div>
]]></description>
      <dc:creator>lestrrat</dc:creator>
      <pubDate>Tue, 15 Dec 2009 01:00:00 GMT</pubDate>
      <category></category>
    </item>
    <item>
      <title>続・最速IPアドレスマッチ研修会</title>
      <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/14.html</link>
      <description><![CDATA[<div class="section">
<h3> 前置き</h3>

<p><a href="http://perl-users.jp/articles/advent-calendar/2009/casual/">CasualTrack</a>の第一日目、kazeburoさんの「<a href="http://perl-users.jp/articles/advent-calendar/2009/casual/01.html">最速IPアドレスマッチ研修会</a>」を読んで触発され、より最速な高みを目指し、作成したモジュール「Net::IP::Match::Trie」を紹介します。</p>

<ul>
<li> <a href="http://github.com/hirose31/p5-net-ip-match-trie">http://github.com/hirose31/p5-net-ip-match-trie</a></li>
<li> <a href="http://search.cpan.org/dist/Net-IP-Match-Trie/">http://search.cpan.org/dist/Net-IP-Match-Trie/</a></li>
</ul>
</div>
<div class="section">
<h3> 本題</h3>

<p>正確にいうと、「作った」のではなく、mod_cidr_lookupというApacheモジュールを「ポーティング」しました。</p>

<ul>
<li> <a href="http://lab.klab.org/wiki/Mod_cidr_lookup">mod_cidr_lookup</a></li>
</ul>

<p>Net::IP::Match::* 系のCPANモジュールには、様々なデータ構造、探索方法の実装があるのですが、今回のお題の「Net::IP::Match::Trie」は、その名に冠しているようにTrie(トライ木)というデータ構造を採用しています。</p>

<p>Trieについての解説は、</p>

<ul>
<li> <a href="http://ja.wikipedia.org/wiki/Trie">http://ja.wikipedia.org/wiki/Trie</a> , <a href="http://en.wikipedia.org/wiki/Trie">http://en.wikipedia.org/wiki/Trie</a></li>
<li> <a href="http://dsas.blog.klab.org/archives/51294589.html">http://dsas.blog.klab.org/archives/51294589.html</a></li>
</ul>

<p>などを参照していただくとして、ここでは、他の Net::IP::Match::* 系の実装と比べて、Net::IP::Match::Trieがどのような特徴を持っているか書いてみたいと思います。</p>
</div>
<div class="section">
<h3> まずはベンチマーク</h3>

<p>kazeburoさんの記事のベンチマークスクリプトをベースにして、ベンチマークをとってみました。(ベンチマークスクリプトは、 <a href="http://github.com/hirose31/p5-net-ip-match-trie/blob/master/samples/benchmark/benchmark.pl">http://github.com/hirose31/p5-net-ip-match-trie/blob/master/samples/benchmark/benchmark.pl</a> にあります)</p>

<p>ベンチマークスクリプトの変更点は以下の通りです。</p>

<ul>
<li> Net::IP::Match::Trieを追加</li>
<li> Net::IP::Match::XS2を追加</li>
<li> 検査の母データとなるCIDRを155個に増量</li>
</ul>

<p>Net::IP::Match::Trie は XS 版と Pure Perl 版があるので、それぞれでベンチマークをとりました。結果はこうなりました:</p>

<pre>
$ ./samples/benchmark/benchmark.pl
155
Net::IP::Match::Trie::XS
            (warning: too few iterations for a reliable count)
              Rate     cidr  regexp patricia       xs      bin      xs2     trie
cidr       44643/s       --    -67%     -71%     -77%     -92%     -93%     -97%
regexp    134529/s     201%      --     -11%     -31%     -77%     -78%     -90%
patricia  151515/s     239%     13%       --     -22%     -74%     -76%     -88%
xs        194805/s     336%     45%      29%       --     -66%     -69%     -85%
bin       576923/s    1192%    329%     281%     196%       --      -8%     -56%
xs2       625000/s    1300%    365%     312%     221%       8%       --     -52%
trie     1304348/s    2822%    870%     761%     570%     126%     109%       --

$ env NIMT_PP=1 ./samples/benchmark/benchmark.pl
155
Net::IP::Match::Trie::PP
             Rate     cidr   regexp patricia       xs     trie      bin      xs2
cidr      40323/s       --     -69%     -74%     -80%     -82%     -93%     -93%
regexp   128205/s     218%       --     -16%     -36%     -42%     -79%     -79%
patricia 152284/s     278%      19%       --     -24%     -31%     -75%     -75%
xs       201342/s     399%      57%      32%       --      -9%     -66%     -66%
trie     220588/s     447%      72%      45%      10%       --     -63%     -63%
bin      600000/s    1388%     368%     294%     198%     172%       --      -0%
xs2      600000/s    1388%     368%     294%     198%     172%       0%       --
</pre>

<p>XS版はダントツで最速、Pure Perl版もPure Perlな実装の間では最速という結果がでました。</p>
</div>
<div class="section">
<h3> 入力CIDR数と、セットアップとマッチ処理時間の関係</h3>

<p>さて、「最速」というのはわかったのですが、Net::IP::Match::Trieがどのような「特徴」をもっているかというのはこれだけではわかりません。ですので、もうひとつ、ベンチマークスクリプトを走らせてみたいと思います。</p>

<p>ベンチマークには、Net::IP::Match::Regexp に含まれる speedtest.pl を改変したものを使いました。(スクリプトは、 <a href="http://github.com/hirose31/p5-net-ip-match-trie/blob/master/samples/benchmark/speedtest.pl">http://github.com/hirose31/p5-net-ip-match-trie/blob/master/samples/benchmark/speedtest.pl</a> にあります)</p>

<p>結果はこうなりました。("Networks:"は、探索母データとなるCIDRの数です)</p>

<pre>
$ ./samples/benchmark/speedtest.pl
Initialization time of test: 0.032882

Networks: 1, IPs: 10000
Test name              | Setup time | Run time | Total time | Errors
-----------------------+------------+----------+------------+--------
simple                 |    0.000   |  0.058   |    0.058   | n/a
Net::IP::Match::XS     |    0.000   |  0.015   |    0.016   | 0
Net::IP::Match::Regexp |    0.001   |  0.072   |    0.072   | 0
Net::IP::Match::Trie   |    0.000   |  0.022   |    0.022   | 0

Networks: 10, IPs: 10000
Test name              | Setup time | Run time | Total time | Errors
-----------------------+------------+----------+------------+--------
simple                 |    0.000   |  0.085   |    0.085   | n/a
Net::IP::Match::XS     |    0.000   |  0.022   |    0.022   | 0
Net::IP::Match::Regexp |    0.001   |  0.091   |    0.093   | 0
Net::IP::Match::Trie   |    0.000   |  0.023   |    0.023   | 0

Networks: 100, IPs: 10000
Test name              | Setup time | Run time | Total time | Errors
-----------------------+------------+----------+------------+--------
simple                 |    0.000   |  0.371   |    0.371   | n/a
Net::IP::Match::XS     |    0.000   |  0.084   |    0.084   | 0
Net::IP::Match::Regexp |    0.010   |  0.098   |    0.107   | 0
Net::IP::Match::Trie   |    0.001   |  0.022   |    0.024   | 0

Networks: 1000, IPs: 10000
Test name              | Setup time | Run time | Total time | Errors
-----------------------+------------+----------+------------+--------
simple                 |    0.002   |  2.784   |    2.786   | n/a
Net::IP::Match::XS     |    0.001   |  0.647   |    0.648   | 0
Net::IP::Match::Regexp |    0.090   |  0.103   |    0.193   | 0
Net::IP::Match::Trie   |    0.064   |  0.023   |    0.087   | 4
</pre>

<p>この結果から読み取れることはこんなところでしょうか:</p>

<ul>
<li> Net::IP::Match::XS
<ul>
<li> API的に、セットアップ処理がなくマッチ処理のみの実装になっている</li>
<li> マッチ処理はそれほど高速ではない</li>
</ul>
</li>
<li> Net::IP::Match::Regexp
<ul>
<li> 入力CIDR数の増加によりセットアップ時間が線形に増加するので、少ないうちはいいが多くなると注意</li>
<li> マッチ処理に要する時間も徐々に増加した</li>
</ul>
</li>
<li> Net::IP::Match::Trie
<ul>
<li> 入力CIDR数の増加によりセットアップ時間も増加する</li>
<li> 一方、Trieの特長により、マッチ処理時間はまったく変わらない (CIDR数が増加しても一定)</li>
</ul>
</li>
</ul>

<p>ちなみに、最後の結果で Net::IP::Match::Trie の Errors の項が非ゼロですが、これは、Net::IP::Match::Trie はマッチするCIDRが複数ある場合には、ネットワークアドレスが一番長い(=ネットマスクが一番短い)ものを返す実装になっているのに対し、ほかのものはそういう実装になっていないからです。</p>

<p>たとえば、</p>
<pre>
$matcher->add("big"   => [qw(10.0.0.0/8)]);
$matcher->add("small" => [qw(10.6.25.0/24)]);
say $matcher->match_ip("10.6.25.1");
</pre>
<p>の結果は、最初に add した "big" ではなく、より限定的(ネットワークアドレスが長い=ネットマスクが短い)なCIDRである "small" になります。</p>
</div>
<div class="section">
<h3> まとめ</h3>

<ul>
<li> Net::IP::Match::Trieは、
<ul>
<li> 一度だけ、かならずセットアップ処理が必要です</li>
<li> マッチ処理は最速です (少なくとも今回比較した中では)</li>
<li> また、Trieの特長により、探索母データのCIDRの数がとっても多くなっても、常に一定の速度で結果を返せます</li>
<li> 一回のマッチ処理で、ラベル付けしたいずれかのCIDRにマッチするかどうかがチェックできます
<ul>
<li> 例: 「このIPアドレスは、どの携帯電話キャリア(DoCoMo、au、Softbank、willcom)のものか？」というのが、Net::IP::Match::XSやNet::IP::Match::Regexpではキャリアの数の分だけマッチ処理が必要ですが、Net::IP::Match::Trieなら一発でわかります。</li>
</ul>
</li>
</ul>
</li>
<li> よって、Net::IP::Match::Trie は、このような用途に向いています:
<ul>
<li> そのライフサイクルの中で、初期セットアップの回数より、マッチ処理の回数の回数が圧倒的に多い</li>
<li> CIDRの変化が頻繁にはない
<ul>
<li> 例: daemon的な比較的長寿のサーバプロセスとか</li>
</ul>
</li>
</ul>
</li>
</ul>

<ul>
<li> 最後に。Advent Calendarのおかげで、Net::IP::Match::Trie というモジュールを作るきっかけを得ることができました！ ありがとうございました！ Happy SUSHI!!!</li>
</ul>


<p>というわけで今日はここまでです。明日は lestrrat さんです。</p>
</div>
]]></description>
      <dc:creator>hirose31</dc:creator>
      <pubDate>Mon, 14 Dec 2009 11:23:01 GMT</pubDate>
      <category></category>
    </item>
    <item>
      <title>Qudoで簡単ジョブキュー処理を実施する</title>
      <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/13.html</link>
      <description><![CDATA[<div class="section">
<h3> 前置き</h3>

<p>こんにちはmasartzです。今日は僕とid:nekokakさんが共同で作っている</p>
<p>モジュール「Qudo」を紹介させていただきます。</p>
</div>
<div class="section">
<h3> 本題</h3>

<p>Qudoは既存のジョブキューシステムを使ってみて思ったいくつかの要望を</p>
<p>実現する目的で作成しました。ポイントは拡張性と使いやすさです。</p>


<p>まずは、簡単な例から初めてみましょう。</p>
<p>Advent Calendarということで、クリスマスにプレゼントを願う子供と</p>
<p>それを届けるサンタクロースを再現してみたいと思います。</p>

<p>QudoはデータストアにRDBMSを用いています。</p>
<p>そのため、使用する際にはあらかじめDBを作成する必要があります。</p>
<p>現在MySQL,SQLite,PostgreSQL（多分）に対応しています。</p>
<p>各DB用のスキーマファイルは「<a href="http://github.com/nekokak/qudo/tree/master/doc/">http://github.com/nekokak/qudo/tree/master/doc/</a>」</p>
<p>にありますので、そちらを参照してDBを作成してください。</p>
<p>以下の内容はMySQLを用いた場合を前提として記載しています。</p>

<p>先に、子供がサンタクロースにプレゼントを注文します。( ClientがJobを投入します )</p>
<p>children.pl</p>
<pre>
#!/usr/bin/perl 
use strict;
use warnings;

use Qudo;
use MyApp::Worker::Santa;

my $qudo = Qudo->new(
    driver_class => 'Skinny',
    databases => [+{
        dsn      => 'dbi:mysql:qudo',
        username => 'root',
        password => '',
    }],
);

for my $present ( qw/ cake chocolate / ){
        $qudo->enqueue("MyApp::Worker::Santa", { arg => $present });
}
</pre>

<p>そして、サンタクロースが子供達からのプレゼントを届けます(Jobを処理するWoekerを作ります)</p>
<pre>
package MyApp::Worker::Santa;

use strict;
use warnings;
use base qw/Qudo::Worker/;

sub work {
    my ($self , $job ) = @_;

    my $present = $job->arg();
    print "Hello , I give you present which you hoped.It is $present.\n";

    $job->completed();
}
1;
</pre>

<p>最後に、クリスマス当日を迎えてサンタクロースに届けてもらいましょう(workerを実際に起動します)</p>
<p>cometrue.pl</p>
<pre>
#!/usr/bin/perl 
use strict;
use warnings;

use Qudo;
my $qudo = Qudo->new(
    driver_class => 'Skinny',
    databases => [+{
        dsn      => 'dbi:mysql:qudo',
        username => 'root',
        password => '',
    }],
    manager_abilities => [qw/MyApp::Worker::Santa/],
);

$qudo->work;
</pre>

<p>cometrue.plを実行した結果、以下のように表示されれば成功です。</p>
<p>(workerはwhileのループで動き続けるので、Ctrl-Cで抜けてください)</p>
<pre>
Hello , I give you present which you hoped.It is chocolate.
Hello , I give you present which you hoped.It is cake.
</pre>

<p>と、ここまでが最も簡単な例です。ここから少し応用していきましょう。</p>

</div>
<div class="section">
<h3> 応用その1:Enqueueする情報を複雑化させる</h3>

<p>まずは、この状態だとサンタは相手を選ばずに適当にプレゼントを</p>
<p>バラまいているので、それぞれの子供に希望の物が届くようにしてあげましょう。</p>
<p>children.plを以下のように変更します。</p>
<pre>
< for my $present ( qw/ cake chocolate / ){
<     $qudo->enqueue("MyApp::Worker::Santa", { arg => $present });
---
> my @children = (
>     {
>         name    => 'masartz',
>         present => 'cake',
>     },
>     {
>         name    => 'nekokak',
>         present => 'chocolate',
>     },
> );
> 
> $qudo->manager->global_register_hooks(qw/Qudo::Hook::Serialize::JSON/);
> 
> for my $child ( @children ){
>     $qudo->enqueue("MyApp::Worker::Santa2", { arg => $child });
</pre>
<p>プレゼント名をScalarで渡していたところを、</p>
<p>子供の名前とプレゼントをペアにしたHashRefにしました。</p>
<p>このために、QudoのHook機能を使って、Job をenqueueする時に</p>
<p>引数をシリアライズします。今回はJSONを用いました。</p>
<p>これはオプション扱いですが、Qudoのパッケージに含まれています。</p>

<p>合わせて、Worker側も手を加えます。</p>
<pre>
<     my $present = $job->arg();
<     print "Hello , I give you present which you hoped.It is $present.\n";
---
>     my $child = $job->arg();
>     print "Hello , $child->{name}. I give you present which you hoped.It is $child->{present}.\n\n";
</pre>
<p>こちらは、単純に$job->argで取れてくるものをHashRefで</p>
<p>来るように想定して変更しただけです。</p>

<p>さらに、実行するcometrue.plにもHookを使うのを明示化する一文を追加する必要があります。</p>
<p>workメソッドを実行する直前に以下の1行を追加してください。</p>
<pre>
  manager_abilities => [qw/MyApp::Worker::Santa2 /],
  );
  
+ $qudo->manager->global_register_hooks(qw/Qudo::Hook::Serialize::JSON/);
  $qudo->work;
</pre>

<p>そして、これで実行してみます。</p>
<pre>
Hello , nekokak. I give you present which you hoped.It is chocolate.
Hello , masartz. I give you present which you hoped.It is cake.
</pre>
<p>各Jobで名前とプレゼントの情報を正しく受け取り、実行出来た事がわかります。</p>
<p>子供達がそれぞれ望んだプレゼントを受け取れるようになりました。</p>

<p>ただプレゼントするだけなのも無愛想ですし、せっかくなのでサンタクロースに</p>
<p>お決まりの決め台詞を必ず言ってもらうようにしましょう。</p>

</div>
<div class="section">
<h3> 応用その2:Pluginを作ってみる</h3>

<p>この実現のために、Plugin機構を使います。</p>
<p>Qudoには様々な場所に独自のPluginを追加出来るようになっています。</p>
<p>先にPluginの中身を作成します。</p>

<pre>
package MyApp::Worker::Plugin::PreMessage;
use strict;
use warnings;
use base 'Qudo::Plugin';

sub plugin_name{ 'pre_message' }

sub load {
    my $class = shift;

    $class->register(
        sub {
            print "Merry Christmas!! \n";
        }
    );
}
1;
</pre>
<p>とてもシンプルですが、このメッセージをプレゼントを渡す前に必ず</p>
<p>言ってもらうようにWorkerを修正します。</p>

<p>MyApp::Woker::Santa のprint文の前に以下の1文を追加してください。</p>
<pre>
  my ($self , $job ) = @_;

+ $job->manager->plugin->{pre_message}->();

  my $child = $job->arg();
</pre>

<p>最後に忘れずにcometrue.plも修正します。先ほどのHookの時と同じように</p>
<p>wokメソッドより前に以下の1文を追加してください。</p>

<pre>
  manager_abilities => [qw/MyApp::Worker::Santa2 /],
  );
  
+ $qudo->manager->register_plugins(qw/MyApp::Worker::Plugin::PreMessage/);
  $qudo->manager->global_register_hooks(qw/Qudo::Hook::Serialize::JSON/);
  $qudo->work;
</pre>

<p>さぁ、これで実行すると以下のようになるハズです。</p>
<pre>
Merry Christmas!! 
Hello , nekokak. I give you present which you hoped.It is chocolate.
Merry Christmas!! 
Hello , masartz. I give you present which you hoped.It is cake.
</pre>

<p>成功したでしょうか？</p>

<p>最終形をgistにあげておきました。</p>
<p>children.pl : <a href="http://gist.github.com/254925">http://gist.github.com/254925</a></p>
<p>MyApp::Wokrer::Santa : <a href="http://gist.github.com/254928">http://gist.github.com/254928</a></p>
<p>cometrue.pl : <a href="http://gist.github.com/254932">http://gist.github.com/254932</a></p>

</div>
<div class="section">
<h3> まとめ</h3>

<p>Qudoの機能について簡単ではありますが説明させていただきましたが、</p>
<p>いかがでしたでしょうか？</p>

<p>Qudoの開発状況としては、</p>
<p>・CPANにはDevelopper Versionで登録していましたが、つい最近正式版を公開しました</p>
<p>  -> <a href="http://search.cpan.org/~nekokak/Qudo-0.02">http://search.cpan.org/~nekokak/Qudo-0.02</a></p>
<p>・とはいえ、いくつかTodoも残っているのでgithubで開発は継続中です</p>
<p>  -> <a href="http://github.com/nekokak/qudo">http://github.com/nekokak/qudo</a></p>
<p>・質問やご要望等ある方がいらっしゃいましたら、</p>
<p>  #qudo@irc.perl.org までお気軽にお越し下さい</p>
<p>という感じです。</p>

<p>今回紹介したような拡張性・使いやすさを念頭においていますので、</p>
<p>使ってみたら感想などいただけると大変参考になります。</p>
<p>あと足りない部分の開発フォローしていただくのも歓迎です。</p>


<p>というわけで今日はここまでです。明日はid:hirose31 さんです。</p>
</div>
]]></description>
      <dc:creator>masartz </dc:creator>
      <pubDate>Sat, 12 Dec 2009 16:27:36 GMT</pubDate>
      <category></category>
    </item>
    <item>
      <title>Tie::Traceで簡単に変数の中身を追う</title>
      <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/12.html</link>
      <description><![CDATA[<div class="section">
<h3> 前置き</h3>

<p>こんにちは、<a href="http://d.hatena.ne.jp/ktat/">id:ktat</a>です。最近は、<a href="http://github.com/ktat/Util-All">Util::All</a>というモジュールをいじってますが、CPAN にはあげてないので、紹介できません。</p>
<p>というわけで、今日はデバッグのお供に使えるかもしれない、<a href="http://search.cpan.org/dist/Tie-Trace/">Tie::Trace</a>を紹介します。</p>
</div>
<div class="section">
<h3> 本題</h3>

<p>さて、perlのプログラムのデバッグするなら、perl -d というのも良いですが、print デバッグもお手軽でいいですよね。</p>

<p>しかし、怪しい変数を追いかけたり、見知らぬオブジェクトの中を調べたりするのに、いちいち print や warn を挿入していくのも面倒です。</p>
<p>そんな時には、Tie::Trace が役に立つかもしれません。</p>
</div>
<div class="section">
<h3> 単純な例</h3>

<p>次の $hoge、 @hoge、 %hoge の各変数を追いかけてみます。</p>
<pre>
use Tie::Trace qw/watch/;

watch my $hoge;
watch my @hoge;
watch my %hoge;

$hoge = 1;

push @hoge, "a";
delete $hoge[-1];

$hoge{1} = 1;
$hoge{"abc"} = "xyz";
</pre>
<p>以下のようなメッセージが表示されます。</p>
<pre>
main:: $hoge => 1 at sample1.pl line 7.
main:: @hoge => PUSH('a') at sample1.pl line 9.
main:: @hoge[0] => DELETED('a') at sample1.pl line 10.
main:: %hoge => {1} => 1 at sample1.pl line 12.
main:: %hoge => {abc} => 'xyz' at sample1.pl line 13.
</pre>
<p>若干分かりにくい表示ですが、main:: 変数名 は、main package で宣言されている変数という意味です。=&gt; の後ろに、代入されたり削除された値が入ります。PUSH や DELETED のように何かしら説明っぽいものが入る場合もあります。</p>
</div>
<div class="section">
<h3> リカーシブに追跡</h3>

<p>watch 関数で監視された変数に、ハッシュリファレンスやアレイリファレンスが代入された場合、それらは再帰的にチェックされ、監視する対象になります。</p>
<pre>
use Tie::Trace qw/watch/;

watch my @array;
push @array, { a => 1 }, [0, 1, 2, [10, 20, 30, { a => 'b'}]];
$array[0]->{b} = 2;
$array[1]->[3]->[3]->{a} = "c";
$array[1]->[3]->[3]->{c} = "d";
</pre>
<p>としてみます。</p>
<pre>
main:: @array => PUSH({'a' => 1},[0,1,2,[10,20,30,{'a' => 'b'}]])
 at sample2.pl line 4.
main:: @array => [0]{b} => 2 at sample2.pl line 5.
main:: @array => [1][3][3]{a} => 'c' at sample2.pl line 6.
main:: @array => [1][3][3]{c} => 'd' at sample2.pl line 7.
</pre>
<p>このように、@arrayに挿入された無名ハッシュや無名配列に値が入ってもメッセージが表示されます。ただし、オブジェクトや tie されたリファレンスなどが入ってきた場合、それらは監視対象にはなりませんので、ご注意ください。</p>
</div>
<div class="section">
<h3> オブジェクトの中身をチェックする</h3>

<p>オブジェクトの中身にをチェックするのにも使えます。Mouse(0.40)でやってみました。</p>
<pre>
package Hoge;

use Mouse;
has "name" => (is =>"rw");
has "height" => (is =>"rw");

package main;

use Tie::Trace qw/watch/;

my $x = Hoge->new;

watch %$x;

$x->name("ktat");
$x->height(173)
</pre>
<p>以下のような表示がされます。</p>
<pre>
{name} => 'ktat' at accessor for name (.../Mouse/Meta/Method/Accessor.pm) line 2.
{height} => 173 at accessor for age (.../Mouse/Meta/Method/Accessor.pm) line 2.
</pre>
<p>package名や変数名が取れていないときは、グローバル変数、無名リファレンスなんかです。</p>
<p>ちなみに、Moose(0.92)だとこんな感じでした。</p>
<pre>
{name} => 'ktat' at accessor name defined at sample4.pl line 6.
{height} => 173 at accessor height defined at sample4.pl line 7.
</pre>
<p>にしても、Mouse も Moose もメッセージが独特な感じですね。Mouseの "line 2" がよくわかりませんが、追ってません。</p>

<p>しかし、いずれも代入された箇所がわかりませんね。以下のように、caller オプションを与えてみましょう。</p>
<pre>
watch %$x, caller => [0, 1];
</pre>
<p>watch の変数名の後の引数はオプションになります。callerオプションをつけると、指定された分だけたどってくれます。</p>
<pre>
{name} => 'ktat' at accessor name defined at sample5.pl line 6.
 at sample5.pl line 15.
{height} => 173 at accessor height defined at sample5.pl line 7.
 at sample5.pl line 16.
</pre>
<p>これで、代入場所が特定できましたね。</p>
</div>
<div class="section">
<h3> リカーシブなチェックをやめる</h3>

<p>リカーシブなチェックはいらないという場合もあるでしょう。そういうときは次のようにします。</p>

<pre>
watch %var, r => 0;
</pre>
<p>これで、リファレンスが代入されても、それらは監視対象にはなりません。</p>
</div>
<div class="section">
<h3> 条件に一致するキーのみ</h3>

<pre>
use Tie::Trace qw/watch/;

watch my %foo, key => ['foo'];
watch my %bar, key => [qr/bar/];
watch my %buz, key => [sub{my($self,$key) = @_;$key =~/buzbuz/}];
watch my %foobarbuz,
  key => ['foo', qr/bar/,
          sub {my ($self, $key) = @_; return $key =~/buzbuz/}];

$foo{foo} = 1;
$foo{hoge} => {foo => 2};
$foo{hoge}->{foo} = 2;

$bar{bar} = 1;
$bar{beer} = 2;
$bar{barbarbar} = 3;

$buz{buz} = 1;
$buz{buzbuz} = 1;

@foobarbuz{qw/foo barbar buzbuz BUZ Buzbuz/} = ('a' .. 'e');
</pre>
<p>結果は以下のように、key が条件に合致するものしか出力されません。</p>
<pre>
main:: %foo => {foo} => 1 at sample5.pl line 10.
main:: %foo => {hoge}{foo} => 2 at sample5.pl line 12.
main:: %bar => {bar} => 1 at sample5.pl line 14.
main:: %bar => {barbarbar} => 3 at sample5.pl line 16.
main:: %buz => {buzbuz} => 1 at sample5.pl line 19.
main:: %foobarbuz => {foo} => 'a' at sample5.pl line 21.
main:: %foobarbuz => {barbar} => 'b' at sample5.pl line 21.
main:: %foobarbuz => {buzbuz} => 'c' at sample5.pl line 21.
</pre>
<p>同じ要領で、key を value に変えると、value に対する条件を指定できます。</p>
</div>
<div class="section">
<h3> メッセージを変更する</h3>

<p>表示するメッセージを変えたいこともあるでしょう。例えば、キー 'foo' が入ってきたときの、キー 'var' の値が知りたいとか。</p>
<pre>
use Tie::Trace qw/watch/;

watch my %foo,
  key => ['foo'],
  debug => sub {my ($self, $v) = @_;
                if (%{$self->storage}) {
                  return $v . " {var} is " . $self->storage->{var}
                } else {
                  return $v;
                }
	      };

%foo = (foo => 1, var => 2);
$foo{foo} = 2;
$foo{var} = 3;
$foo{foo} = 4;
</pre>
<p>'foo' が代入された行数でのみ、メッセージが出ています。</p>
<pre>
main:: %foo => {foo} => 1 at sample7.pl line 13.
main:: %foo => {foo} => 2 {var} is 2 at sample7.pl line 14.
main:: %foo => {foo} => 4 {var} is 3 at sample7.pl line 16.
</pre>
<p>キー 'bar' が入ってきたときの、親のハッシュリファレンスのキー 'xxx' の値が知りたいとか。</p>
<pre>
use Tie::Trace qw/watch/;

my %parent = (child => {foo => 10, bar => 100}, xxx => "xxx");

watch %parent,
  key => ['bar'],
  debug => sub {
             my ($self, $v) = @_;
             if (my $p = $self->parent) {
               return "$v; parent->{xxx} is ". $p->storage->{xxx};
             } else {
               return $v;
             }
           };

$parent{child}->{bar} = 1;
$parent{xxx} = 10;
$parent{child}->{bar} = 1000;
</pre>
<p>以下のようなメッセージとなります。</p>
<pre>
main:: %parent => {child}{bar} => 1; parent->{xxx} is xxx at sample8.pl line 15.
main:: %parent => {child}{bar} => 1000; parent->{xxx} is 10 at sample8.pl line 17.
</pre>
<p>ここで使われている、storage メソッドは、実際のデータが入っているリファレンスを返し、parent メソッドは親のオブジェクトを返します。</p>
</div>
<div class="section">
<h3> 注意事項</h3>

<p>たいていのケースで特に問題なく動くとは思いますが、変数を変質させてますので、何か変なことが起きるかもしれません。そういうときは、素直に perl -d でもしてくださいませ。</p>
</div>
<div class="section">
<h3> まとめ</h3>

<p>今回は、Tie::Trace を使った、お手軽な print デバッグについて解説しました。</p>
<p>一応<a href="http://search.cpan.org/dist/Tie-Trace/lib/Tie/Trace_JP.pod">日本語のドキュメント</a>も用意してありますので、よろしければ、そちらもどうぞ。</p>


<p>というわけで今回はここまで。明日は <a href="http://d.hatena.ne.jp/masartz/">id:masartz</a> さんです。</p>
</div>
]]></description>
      <dc:creator>ktat</dc:creator>
      <pubDate>Fri, 11 Dec 2009 23:00:00 GMT</pubDate>
      <category></category>
    </item>
    <item>
      <title>Perlではじめるテキストマイニング</title>
      <link>http://perl-users.jp/articles/advent-calendar/2009/hacker/11.html</link>
      <description><![CDATA[<div class="section">
<h3> ■前置き</h3>


<p>みなさんこんにちは。ダウンロードたけし（寅年）です。来年は年男なので今からお正月が待ち遠しい35歳2児の父です。</p>

<p>ここ数年、web広告業界ではコンテキスト解析とかユーザの行動分析とか、いわゆるデータマイニング／テキストマイニング系の話題が花盛りです。</p>
<p>自分もそんな業界に属しているんですが、ふと気がつくと日本語のテキストマイニング系モジュールを量産してしまっているので、ここらでいくつか紹介してみたいと思います。</p>

<p>今回はインターネットからブログなどのコンテンツを取得して、それを意味解析してクラスタリングする、といったようなことを題材にモジュールの紹介をしてみます。</p>



</div>
<div class="section">
<h3> ■HTML::Featureで本文抽出</h3>


<p>まずは分析する対象のデータを持ってくるところからなんですが、そこの所は割愛してコンテンツを持ってきたところから話をします。</p>

<p>持ってきたHTMLデータにはヘッダやらフッタやらサイドメニューやら、おおよそ本文とは関係ない部分がたっぷり含まれていますよね。</p>
<p>これらのノイズをどうにかして除去したい。逆に言うと本文だけを効率よく抽出したい、と考えるわけです。</p>

<p>そこで<a href="http://search.cpan.org/~miki/HTML-Feature/">HTML::Feature</a>というモジュールをつくりました。</p>

<p>事前の定義とか一切なしで、おおよそいい感じで本文部分を推測して抽出してくれます。</p>

<p>使い方はこう。</p>

<pre>
use HTML::Feature;
my $f = HTML::Feature->new(
    engines => [
        'HTML::Feature::Engine::LDRFullFeed',
        'HTML::Feature::Engine::GoogleADSection',
        'HTML::Feature::Engine::TagStructure',
    ]
);
print $f->parse($url)->text;
</pre>

<p>engines のところにごちゃごちゃ書いてますが、これは抽出ロジックのエンジン達です。ここに複数の抽出ロジックを並べておくと、うまく抽出できるまで上から順に試していきます。</p>

<p>エンジンは以下の3つを用意しています。</p>

<ul>
<li> LDRFullFeed
<ul>
<li> WedataのLDRFullFeedデータを使ってXPathで本文箇所をピックアップします。なのでマッチするURLであればとても正確。</li>
</ul>
</li>
<li> GoogleADSection
<ul>
<li> Google ADSenceを導入している場合はタグで囲まれてる部分を正規表現で抜きます。なのでこれもタグがあれば正確。</li>
</ul>
</li>
<li> TagStructure
<ul>
<li> HTMLタグの構成を解析して各DOMノードをスコアリングし重要そうな場所を推測。明確に本文があれば結構正確だけど、リンクリストや記事がないようなサイトは苦手。</li>
</ul>
</li>
</ul>

<p>さて、いまここで「特定サイトのコンテンツだけは、手動で定義してでも正確に本文抽出したい」というような要望があったとします。その場合には独自のエンジンを記述することも可能です。</p>

<p>独自エンジンをengines の先頭に配置すれば、「 独自エンジン > LDRFullFeed > GoogleADSection > Tagstructure 」の優先順位で処理が進みます。</p>

<p>ちなみにenginesに何も指定しなければTagStructureがデフォルトエンジンとして動きます。</p>

<p>まずはこんな感じで本文と思わしきところだけを適当に引っこ抜いておきます。楽チンですね！</p>

<p>　参考）</p>
<p>　　<a href="http://d.hatena.ne.jp/download_takeshi/20090728/1248813497">http://d.hatena.ne.jp/download_takeshi/20090728/1248813497</a></p>



</div>
<div class="section">
<h3> ■特徴語の抽出 (Lingua::JA::TFIDF, Lingua::JA::OkapiBM25)</h3>


<p>さて本文だけをスッポリ抽出できたら、次は本文の中からさらに「特徴的な単語」を抽出していきます。</p>

<p>情報検索の世界では特徴語抽出は「いろはのいの字」的なものです。それに関しては古くから「TF/IDF」というアルゴリズムが王道中の王道とされてきました。</p>
<p>ところが、いざ真面目に取り組もうとすると、仕込みというか事前準備がそれなりに必要となってしまい、「気軽に試してみる」というにはちょいと面倒な処理でした。</p>

<p>そこで「精度はちょっとテキトーでもいいから手軽にやってみたいよー」というラテン系な人のために<a href="http://search.cpan.org/~miki/Lingua-JA-TFIDF/">Lingua::JA::TFIDF</a>というモジュールを作りました。</p>

<p>なんの前準備もいらないので手軽です。内部的にかなり大胆な(テキトーな）計算をしてるんですが、その割にまあまあの精度がでます。</p>

<pre>
use Lingua::JA::TFIDF;

my $calc   = Lingua::JA::TFIDF->new;
my $result = $calc->tfidf($text);

# 特徴語とスコアのハッシュをスコアの高い順に上位10件表示
print Dumper $result->list(10);
</pre>

<p>最近ではTF/IDFのかわりに「BM25」というアルゴリズムも使われるようです。TF/IDFの改良版みたいなものですね。</p>
<p>こっちについてはつい数日前にモジュール化してみました。</p>

<p><a href="http://search.cpan.org/~miki/Lingua-JA-OkapiBM25/">Lingua::JA::OkapiBM25</a>です。</p>

<p>使い方はLingua::JA::TFIDFとほぼ同じなのでコードは割愛しますが、試してみるとTF/IDFよりもややバランスがいいかな、といった結果が得られました。</p>

<p>　参考）</p>
<p>　　<a href="http://d.hatena.ne.jp/download_takeshi/20081031/1225463411">http://d.hatena.ne.jp/download_takeshi/20081031/1225463411</a></p>
<p>　　<a href="http://d.hatena.ne.jp/download_takeshi/20091206/1260130230">http://d.hatena.ne.jp/download_takeshi/20091206/1260130230</a></p>



</div>
<div class="section">
<h3> ■Lingua::JA::Categorizeで文書分類してみる</h3>


<p>いよいよ大詰めです。</p>

<p>ドキュメントから特徴語を抽出できるようになったら、あとは大量にデータをさばいていきましょう！</p>

<p>先ほどのLingua::JA::TFIDFなどでのアウトプットとして { URL => { 特徴語 => スコア, 特徴語 => スコア, ... }, ... } なデータが大量に蓄積できました。</p>

<p>これらのデータを使ってなにか面白いことができそうな気がしますよね！？</p>
<p>それでは<a href="http://search.cpan.org/~miki/Lingua-JA-Categorize/">Lingua::JA::Categorize</a>を使ってベイジアンによる文書分類器でもつくってみましょう。</p>

<p>Lingua::JA::Categorize は「お好みのカテゴリ構成の分類器をスピーディーに作るため」に書いたモジュールというかフレームワークのようなものです。</p>

<p>作り方は超簡単。モジュールをインストールして、適当なカテゴリ一覧をYAMLで書いて、あとはgenerate()と唱えてください。</p>

<p>トイレに行ってコーヒーでも飲んでいる間に分類器が出来上がってるはずです！</p>

<pre>
use Lingua::JA::Categorize;
my $c = Lingua::JA::Categorize->new;
$c->generate($category_config);
$c->save('save_file_name');
</pre>

<p>分類器を使うときはこう書きます。</p>

<pre>
use Lingua::JA::Categorize;
my $c = Lingua::JA::Categorize->new;
my $result = $c->categorize($text);
print Dumper $result->score; # 分類結果（1位から3位）
</pre>

<p>らくらくですね♪</p>

<p>　（参考）</p>
<p>　　<a href="http://d.hatena.ne.jp/download_takeshi/20081124/1227539934">http://d.hatena.ne.jp/download_takeshi/20081124/1227539934</a></p>



</div>
<div class="section">
<h3> ■クラスタリングをガンガンこなす（Text::Bayon）</h3>


<p>さきほどの文書分類器は事前にカテゴリを定義して、それに即して自動的に文書を分類するものでした。</p>

<p>ですが実際にカテゴリリストを自分で定義しようとすると「世の中にはどんな分野のテーマがどれくらいあるかなんてわからないよ～、適切なカテゴリなんて決められないよ～」という事態にすぐに陥るわけです。</p>

<p>そこでちょっと視点をかえて、K-means法などを使って与えられたデータを自然なカタチにクラスタリング処理して、その上で各クラスタの重心にあつまってるデータを目視して、実際のカテゴリを検討する、みたいなことをしたくなるはずです。</p>

<p>そこで<a href="http://search.cpan.org/~miki/Text-Bayon/">Text::Bayon</a>の登場です！ (昨日書いたばかりのできたてホヤホヤだよ!)</p>

<p>「<a href="http://alpha.mixi.co.jp/blog/?p=1049">Bayon</a>」というのは非常に優秀な軽量クラスタリングツールでして、Mixiのfujisawaさんという方が開発＆公開されています。</p>

<p>Text::Bayon はこの便利なBayonをperlからシームレスに利用するためのハンドリングモジュールです。これを使えばperlから透過的にBayonを使えるようになります。</p>

<pre>
use strict;
use Text::Bayon;

my $bayon = Text::Bayon->new;

# 架空のデータ生成関数
# { ドキュメントID => { 単語 => スコア, ... }, ... }　なデータ構造を生成
my $input = _gene_data(); 

# Bayonに渡す任意のオプション
my %options = (
    number => 10,
    point  => 1,
    idf    => 1,
);

# クラスタリング！
my $output = $bayon->clustering($input_data, \%options);

print Dumper $output;
# 結果データはこんな構造
# { クラスタ => [ ドキュメントID, ドキュメントID, ... ], ... }
</pre>


<p>スムーズですね！そもそも便利なBayonですが、もっと便利に使えるようになりました。</p>


</div>
<div class="section">
<h3> ■まとめ</h3>

<p>こんな感じで、他にもいろいろなモジュールを使ったり、作ったりしながら、毎日毎日、飽きもせずデータマイニング的なことをしております。</p>

<p>今度どこかで「オレもPerlでマイニングしてるゼ」という人たちで集まってみたいものですね！</p>



<p>明日は id:ktatさんです。お楽しみに～。</p>
</div>
]]></description>
      <dc:creator>download_takeshi </dc:creator>
      <pubDate>Thu, 10 Dec 2009 17:26:43 GMT</pubDate>
      <category></category>
    </item>
  </channel>
</rss>
