D-7 <altijd in beweging>

Day to day life of a Perl/Go/C/C++/whatever hacker. May include anything from tech, food, and family.

2009年02月

おお、指摘ありがとうございます

DATA_LOCALIZE_DEBUG=1 を使ってデバッグしていただく、というそもそもの目論見の部分がうまく活用できたようでよかったよかった。

ってことでさっき0.00002をアップしました。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

Data::Localize 0.00001をリリースした。やってることはLocale::Maketextと一緒。主な違い:

  • オブジェクトベース。
  • Locale::Maketextは名前空間をいじってどうのこうのするんですが、これはしない。基本的には登録されているハンドラを全て試す、っていうだけ。
  • デバッグ用のメッセージを一杯仕込んだので、なぜか国際化がされない場合は多分Locale::Maketextより問題箇所の判断が大分楽
  • Locale::Maketextより速い
速さに関しては、以下の通り:
daisuke@beefcake-7 Data-Localize$ perl -Mblib tools/benchmark/benchmark.pl Rate locale_maketext data_localize locale_maketext 9615/s -- -64% data_localize 26786/s 179% --

で、これをCatalystから使うためのCatalyst::Model::Data::Localizeを作ってみた。こいつはCatalyst::Plugin::I18Nを使わずに国際化するためのツール。といっても、Catalyst::Model::Data::Localizeは単純にCatalystの設定からData::Localizeを設定するためのレイヤーで、同梱のCatalyst::Plugin::Data::LocalizeというモジュールでCatalyst::Plugin::I18Nのようにlocalize()関数を生やすためのものです。Catalyst::Plugin::I18Nを使っていた方ならほぼそのまま使えるかと。

というわけで数週間前にLocale::Maketextの中味を解説しだした私は、結局国際化モジュールを自分で作ってしまった、という落ちでした。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

以下、まぁ書き散らかしです。あんまり推敲してません。すまそ。ちなみに、下記記事に対するブクマはDISも多いけど、素直な反応もちらほらあるようで興味深い。




僕にとってのJavaは2001年に終わってますが・・・。同じ事何回も書かなくちゃいけない言語なんて死んだも同然ですよ。ライブラリもちらばってて何がどこにあるのかわかんないし。

って、書くのは簡単です。多分元記事をテンプレ化してほぼ同じ事をどの言語に対しても僕は書けます。

ただ、エンジニアという職種の人がそんなことしてるのはどうかなぁ、と。エンジニアの使命を問題を解くことです。何でつまづいたかとか、なにがむずかしかったとか、何ができなかったとかそういう事をちゃんと書いて欲しいなと思う。CPANのアップロードとかも状況に対しての認識もなく、「回数」という一面だけで判断をばっさりしてていいのでしょうか。

正直Perlという技術が関わっていなかったとしても基本的にツールの有用性を一面でしか判断できないのは危険信号だと感じます。FUDは言い放つのは簡単ですが、なんらかしらのツールが出ていて、それが使われ続けているということはすなわちそこに「何か」がある、ということだと考えが及ばないのはちょっと想像力が足りないんじゃないかと(きっと古い言語でライブラリがアップデートされないCなんて最悪の言語なんでしょうね。うんうん)。

もうちょっとマジレスすると、言語仕様として、下位レイヤーのライブラリはアップデートがないのもあれですが、回数が多すぎるのもどうかと思います。っていうか、CPANモジュールはアップデートに追いつけない!っていうクレームのほうがどう考えてもおおいんだけど、本当に一年に5回も6回もアップデート(しかもその一回一回の中味が多い)とかしてるライブラリを使いたいのかな。そういうライブラリがないわけじゃないけど、きっと今回話に出ていたXML::RSSやXML::Parserがそれに該当したらそしたらそれで文句たらたらになるんじゃないかな。

XML::Parserに関しては機能に限定的な部分がそれなりにあるものの、下位ライブラリとしてはとてもよくできており、これ以上の更新が必要ないと判断されているので更新されていません。実際使ってみて問題があったのでしょうか。そして、さらにXML関係で高機能なものを求めるのであれば、libxml2のインターフェースであるXML::LibXMLなども存在し、それらもかなり安定しているためそれほど更新がありません。XML::LibXMLなどは僕も完全に安心して使い続けられているモジュールのひとつです。

で、それが他の言語だとどう違うのでしょうか?Rubyにしろ、PHPにしろ、それぞれの良いところがあり、使いどころがありますし、それぞれの運用や開発の癖もあるはずです。ひょっとして・・・そのあたりをよくわからないで書いてませんか?

それならそれで構いません。それはこれまでのPerl業界のマーケティングやトレーニングの失敗だからです。でもツールの失敗じゃないですよね?事実関係を見失いがちな放言は同業者としては気をつけていただきたいと感じます。

なお、マーケティングに関しては(←ブクマで指摘されたので修正)、日本国内では僕らが去年から進めているJapan Perl Association (JPA)という団体が責任を持って行います。僕は個人的にはPerlが最強!とはさすがに言いません。僕はとても性にあった言語だと感じてますし、実際この言語のおかげでいままで大変たすかってきていますが、それなりに使いどころがあると感じているので全部のシチュエーションで使えるとはさすがに考えないからです。

JPAは技術者の皆さんに正しい知識とノウハウを持ってPerlの生かし方を判断してもらえるように、そしてPerl及びその後ろに控える優秀なハッカー達の頭脳をうまく皆さんのビジネスに役立てる方法を啓蒙していくつもりです。Javaだって、僕は4年くらいずっと先生として教えてきたから、良いところも知ってます。でもJavaじゃあ工数かかってしょうがない!とか、そういう場所だってあるわけです。そこで色んなチョイスがあるなかで、今回の記事のようなFUDに踊らされず、正しい知識を持ってPerlという言語を判断してもらえるよう、精一杯活動していくつもりです。

JPAは4月の本格活動に向けて、ただいま色々裏で調整してます。もうちょっと待って!





    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

このパッチで多分直ると思う。管理者達が今お休みタイムなのでフィードバックがもらえてないけど、俺の環境ではOK
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

2.30が出てたみたいですが(http://blog.livedoor.jp/dankogai/archives/51178453.html)、どうもインストールエラーになります。Perl 5.8.8 on Mac OS X
t/mime-header..............1/13 # Failed test 'use Encode::MIME::Header;' # at t/mime-header.t line 27. # Tried to use 'Encode::MIME::Header'. # Error: Nested quantifiers in regex; marked by <-- HERE in m/ # =\? # begin encoded word # (?:[-0-9A-Za-z_]+) # charset (encoding) # (?:\*[A-Za-z]{1,8}+ <-- HERE (?:-[A-Za-z]{1,8})*)? # language (RFC 2231) # \?(?:[QqBb])\? # delimiter # (?:.*?) # Base64-encodede contents # \?= # end encoded word # / at /Users/daisuke/.cpan/build/Encode-2.30-TT_cZT/blib/lib/Encode/MIME/Header.pm line 107. # Compilation failed in require at (eval 5) line 2. # BEGIN failed--compilation aborted at (eval 5) line 2. Unknown encoding 'MIME-Header' at t/mime-header.t line 44
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

うわあ、マジ泣いた。

http://plusmicro.blog98.fc2.com/blog-entry-850.html

ドラえもんを貪るように読んでいた自分ももう大人で、ドラえもんは子供の頃の夢なんだと思っている今、大人の無力なのび太達が感じているノスタルジーはそのまま読者である自分が同化しながら感じてしまい、話の最後で色々こみ上げてきてしまった。

この話の作者もうまいが、まず先にドラえもんという普遍価値を作った藤子先生がやっぱりすげぇなぁ・・・
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

わすれてた。昨日DateTimeX::Liteをアップしてた。
use DateTimeX::Lite; my $dt = DateTimeX::Lite->new(year => 2008, month => 12, day => 1); $dt->year; $dt->month; $dt->day; $dt->hour; $dt->minuute; $dt->second; # Arithmetic doesn't come with DateTimeX::Lite by default use DateTimeX::Lite qw(Arithmetic); $dt->add( DateTime::Liate::Duration->new(days => 5) ); # Strftime doesn't come with DateTimeX::Lite by default use DateTimeX::Lite qw(Strftime); $dt->strftime('%Y %m %d');
だいたいDateTimeと互換性のあるAPIで、ただPurePerlであるところと、とにかくlazyに色々ロードするようにしてある。TimeZoneとLocaleは全部一緒に入ってて、なおかつdo 'timezone.dat'みたいな感じで呼び出してるから大分高速。
あとはTimeZoneとかは一緒にバンドルしててもどうせ全部なんて使わないから、必要な分だけをあとからインストールできるようにしたいな、と。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

ちょっと前に書いたData::Localizeをさらに開発すすめて、dev releaseをCPANにあげてみた。
で、今のベンチマークはこんな感じ:
daisuke@beefcake-7 Data-Localize$ perl -Mblib tools/benchmark/benchmark.pl Rate locale_maketext data_localize locale_maketext 9585/s -- -65% data_localize 27273/s 185% --
という感じ。まだなんか機能的に抜けてるところあるかなー
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

ここ数日かたっぱしからモダンPerl入門について言及されているブログをぐぐってははてブするという生活をしていたので、色々と感想とかを読んだ。

今のところ「わからない」という意見が出てない(ブログに出てないだけなのかもしれないとは思いつつ)のは嬉しい限りだが、「物足りない」とか「もっと具体的な例」をっていうのにはまた違う方法でなんとか応えていきたいと思う。まぁ全員の期待に応えるのは無理なのでそれでもやっぱり捨てるところは捨てますが。とりあえずなんらかの形でこれから先カバーしたいなと考えているところ:

  • 文字コードの扱い in Perl
  • 日付・時間の扱い in Perl
  • Apache::TestでPHPサイトをテストする
  • Apache::Test + Test::WWW::Selenium
  • Perlのスタンドアロンアプリケーションの作り方 (これはこれから研究w)
どれもこれもベストプラクティスは出てきているので、これから先まてめていくっていう作業になるだろうな。

ところで別に作家を本業にするつもりはないんだが、自分にしかできない事を、と考えていくと割とこういう教育的な作業は合っているなぁ、と思うのでなんとかこれからもバズワード以外の情報を広めていきたいな、と思う。できる範囲で。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

090214_1648~01.jpgなんか期せずしていただいた。ありがたい。そして正直 食べた時に「よく俺の好みをご存じで」と思ったのは内緒だ。レダラッハというお店のものらしいですお。

チョコレートをもらった話からは大分飛躍するのだが・・・今ぼーっと考えていて、ふと俺の人生は今が一番楽しいなぁと思った。後悔はいっぱいあるけど、きっと今が一番良い。間違っても子供になんか戻りたくない。


そんな私ですが、今日は散財してきました。


群青学舎はこれで最終刊なんだそうだ。残念。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

デブサミ2009でサイン会なんていうまっこと恥ずかしい事をしてきました。正直余裕ある振りをするのが精一杯。良かったことはなんと言っても「モダンPerl入門」がちゃんと並んでいて、「(発売は)都市伝説なんではないか」という一部の噂が完全にデマだと実感できたからです。とりあえずサイン会はおなかいっぱいです。本当恥ずかしい。

ところで、洒落にと思って置いておいた「週刊エンデワークス(ホップ・ステップ・エンデワークス)」を持って行ってくれた方が結構いました。あれ、インパクトつえぇんだなぁ。なんか俺がすごい目立とうとしてるように思われたらかなわんが、あの表紙とかはうちのスタッフに任せてたらああなったんだからね!

デブサミ参加、楽しかったです。弁当がうまかったです。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

urikire.png前々から書いている通り、この度初めて本なんぞ書かせていただいたわけですが、どうも売れ行きが思いの外好調なようで、2/10 - なんと発売日に - 増刷がかかりまして、もう少々部数を出していただけることになったようです。大変ありがたいです。

翔泳社の岩切様のブログによるとAmazonのランキングでも一時は100位以内に入ったそうで。本当、これも皆様のおかげです。ありがとうございます。

とは言え、自分で本を売ってるわけじゃないので売れ行きが見えるわけじゃありません。なんで全然実感がわかなかったわけですが、先ほど午前10時くらいにAmazonのコンピューター・インターネットカテゴリのベストランキングを見たら、昨日までは発送までの時間が2〜5日とかなっていたのがなんと「通常2〜5週間以内」とかなってるじゃないですか。ぎゃー。これは・・・嬉しい。

あと、これだけの方が手を伸ばしてくれるということはそれだけ潜在的なPerlユーザー人口が存在するというわけで、Japan Perl Association活動のほうもこれでより一層がんばれるというものです。嬉しいわぁ。

まま、というわけで、増刷もかかったところで、もしよろしければまだ手にとっておられない方なぞいましたら是非購入ご検討いただければ幸いです。よろしくお願いいたします。改訂版もできれば書きたいなぁ。

    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

090210_1014~01.jpgまだちょっと早めだけど今年は100% Chocolate Cafeのチョコレート詰め合わせをいただきましたよ。ここのチョコレート、本当にうまい。明治製菓++

← クリックすると大きい画像がみれるお
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

decoded_contentで文字コード明示するも化けらった

デコードするだけなら、この以下のコードをdecode前に足すだけで直ると思う

my @ct = grep { /^text/i } $res->header('content-type'); $res->header('content-type', @ct); print $res->decoded_content;

でもこれだけじゃあ答えが分かった、ってだけで後からこれを読んだ人のためにもならないので、以下どういう手順を取ったか説明してみる。

まず、最小限テストケースを用意。

実行するとばけらった。問題を確認した。この問題に関しては、decoded_content()が色々と問題があるのを事前に知っていたのでperl -dでデバッガモードで検証開始。

DB<1> HTTP::Message::decoded_content(/usr/local/lib/perl5/site_perl/5.8.8/HTTP/Message.pm:201): 201: if (my @ct = HTTP::Headers::Util::split_header_words( \ $self->header("Content-Type"))) {

あーなんかこのあたりでヘッダみてて怪しいなぁ・・・と思って、x @ctで中味を確認

DB<1> x @ct 0 ARRAY(0x8d334c) 0 'text/html' 1 undef 2 'charset' 3 'EUC-JP' 1 ARRAY(0x9f0be8) 0 'application/xhtml+xml' 1 undef 2 'charset' 3 'EUC-JP'

む。確かdecoded_content()はヘッダ内容とかでデコードの仕方を変えてるはず。これ、怪しいなぁ。その後、"n"でステップを薦めていくと以下の行に:

DB<2> n HTTP::Message::decoded_content(/usr/local/lib/perl5/site_perl/5.8.8/HTTP/Message.pm:293): 293: if ($ct && $ct =~ m,^text/,,) {

で、本来ならここに入っていかないとおかしいよね。テキストのデコードなんだから。でもそこに行かないで終わってしまった。ってことはapplication/xhtml+xmlがいけないんじゃね?ってことで以下のスクリプト。

use LWP::UserAgent; my $ua = LWP::UserAgent->new(); my $res = $ua->get('http://yugioh-wiki.net/index.php?%A5%C8%A5%C3%A5%D7%A5%DA%A1%BC%A5%B8'); my @ct = grep { /^text/i } $res->header('content-type'); $res->header('content-type', @ct); print $res->decoded_content;

これで見事動いた。これはバグかどうか微妙なところだよな。applicationで始まるMIME-Typeをデコードしろって言われても・・・ねぇ。xmlだったらテキスト、って判断すればよいのか?
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

MENTAやNanoAでもextlibにつっこむ云々の話はあったが、とりあえずインストール先のサーバーにアクセス権があるという前提のもと、アプリケーションの依存関係を全部extlibに自動的につっこむスクリプトを書いてみた。

use strict; use CPAN; use Module::CoreList; use Module::ScanDeps; use File::Find::Rule; use File::Spec; use File::Temp qw(tempdir); if (scalar @ARGV != 2) { print <<EOM; Usage: deps2extlib.pl target [extlib] target - the directory or script that you want to compile dependencies against. extlib - the path where you want to install your dependecies. EOM exit 1; } my $target = $ARGV[0]; my $dir = File::Spec->rel2abs($ARGV[1] || 'extlib'); unshift @INC, $dir; my @files; if (-d $target) { @files = File::Find::Rule ->file() ->or( File::Find::Rule->name('*.pl'), File::Find::Rule->name('*.pm') ) ->in($target); } else { @files = ($target); } my $h = scan_deps_runtime( compile => 1, files => \@files, recurse => 1, ); my %seen; my $corelist = $Module::CoreList::version{ $] }; CPAN::HandleConfig->load unless $CPAN::Config_loaded++; my $home = tempdir(CLEANUP => 1); local $CPAN::Config->{cpan_home} = $home; local $CPAN::Config->{keep_source_where} = File::Spec->catdir($home, 'sources'); local $CPAN::Config->{build_dir} = File::Spec->catdir($home, 'build'); local $CPAN::Config->{prerequisites_policy} = 'follow'; local $CPAN::Config->{makepl_arg} = "INSTALL_BASE=$dir"; local $CPAN::Config->{mbuild_arg} = "--install_base=$dir"; local $CPAN::Config->{mbuild_install_arg} = "--install_base=$dir"; foreach my $key (sort keys %$h) { next if $key =~ /^unicore/; next if $key =~ /^auto/; $key =~ s/\//::/g; $key =~ s/\.pm$//; next if exists $corelist->{$key}; my $dist = CPAN::Shell->expandany($key)->cpan_file ; if ($dist =~ /\/perl-/) { warn "won't try to install perl, but we found dependency on $dist"; next; } next if $seen{ $dist }++; CPAN::Shell->install($dist); }
こんな感じで、アプリケーションのディレクトリかスクリプトファイルなどを第1引数に指定して、第2引数にはこれらの依存関係をつっこむ先を指定する:
perl deps2extlib.pl /path/to/myapp /path/to/extlib
同じmyapp ディレクトリにextlibがある場合は考えてなかったな。まぁ、それだけきをつけて!
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

Locale::Maketextはそれはそれでいいとして、とりあえずData::Localizeってのを書いてみた。まだエンコーディング対応や.moファイル対応してないので完成とは言い難いけど。

とりあえずcodereposにあります
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

さて、今度はLocale::MaketextとLocale::Maketext::Lexicon。

Locale::Maketextは基本操作は以下のようなイメージ。get_handle() というメソッドでローカリゼーション用のオブジェクトを引っ張り出し、それに対してmaketext() を呼び出して変換を行う。
use MyApp::I18N; my $handle = MyApp::I18N->get_handle('ja'); print $handle->maketext("Hello, World!"), "\n";

get_handle() になにげに言語IDが渡されているのもポイント。引数無しでget_handle() を呼び出すと、前出のI18N::LangTag::Detectのコードとかが自動的に呼ばれる。もしこの辺りを自分でコントロールする必要がないと感じるのであれば、引数無しでもよいかもしれない。

話は戻って、MyApp::I18Nを設定するのに、Locale::Maketextを継承した国際化用のモジュールを作る必要がある。
package MyApp::I18N; use strict; use base qw(Locale::Maketext); 1;

国際化ルール自体は、上記MyApp::I18N名前空間以下に置かれる。Locale::Maketextは基本的に.poファイルや.moファイルには対応しないので、直接ハッシュに指定する形になる。
package MyApp::I18N::ja; use strict; use base qw(MyApp::I18N); our %Lexicon = ( "Hello, World!" => "みなさん、こんにちは!" ); 1;

この名前空間が前もって固定されている、というところに「後付で(プラグイン等から)国際化ルールを追加できない」という制限が出てくる。もちろん、%Lexiconハッシュに直接ぶっこめばいいんだけれども・・・それ用のコード書くのは微妙じゃないか?というわけでなんとなく自分はこのアプローチはよくない気がする。

Locale::Maketext::LexiconはLocale::Maketextから継承とかなんもしないくせに、Locale::Maketextを拡張している。意図はいいんだけど、APIデザインとかに全くセンスを感じられないモジュール。こちらは上記Locale::Maketextを使うときと同じくMyApp::I18Nの設定はするのだけれども、この際に.poファイルや.moファイルの扱いができるようになる。要はLocale::Maketext::Lexiconはそれらのファイルの中味を解析して、%MyApp::I18N::xxx::Lexiconにぶちこんでくれるわけです。
package MyApp::I18N; use strict; use base qw(Locale::Maketext); use Locale::Maketext::Lexicon { '*' => [ 'Gettext' => '/path/to/localization/*.po' ], # ファイル名じゃなくてパス中にen/jaとかがはいるなら、以下のようにする: # '*' => [ 'Gettext' => '/path/to/localization/*/data.po' ], _decode => 1 }; 1;

上記の場合全ての言語(「*」という表記)の国際化データは、gettext形式(.poファイル)で/path/to/localization/ディレクトリ以下の、それぞれの言語IDの名前の付いたファイルに格納されている、と表記してある。Locale::Maketext::Lexiconの場合はあとは.poファイルを作るだけ。

ちなみにAPIは最悪なのですが、Locale::Maketext::Lexiconは後からPerl形式以外の国際化データを使えるというのと、それらを後から追加できるというのが最大のメリット。
eval "package MyApp::I18N; Locale::Maketext::Lexicon->import( { ja => [ Gettext => '/path/to/another/localization/ja.po' ] _decode => 1 }); "

とかすると、新しい日本語データを追加することができる。何回も言うけどAPIは最悪。パッケージ名を指定しなくちゃいけないとか、本当にアホだけど、しないとできない。

あとカバーしてないのは_AUTOとかかな。以下次号。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

前回の話ではLocale::Maketext::Simpleだけでは「どの言語を使うか」までは判定してくれません。そこで登場するのが I18N::LangTagsとI18N::LangTags::Detect。確認してないけど、最初の数行のコードの癖からして作者はLocale::Maketextを書いた人と一緒な気がする。

これの使い方は基本的に以下の通り:
use strict; use I18N::LangTag (); # なんかいっぱいエクスポートしちゃうので・・・ use I18N::LangTag::Detect; use Data::Dumper; print Dumper( [ I18N::LangTag::implicate_supers( I18N::LangTag::Detect::detect() # もしくは # I18N::LangTag::Detect->http_accept_langs() ) ]); # env LC_ALL=ja_JP perl script.plと実行すると以下のように出力されるはず # $VAR1 = [ # 'ja-jp', # 'ja' # ];

マニュアルには実はI18N::LangTags::Detect::detect() しか書かれていない。が、実はHTTPヘッダーを見たり、LC_ALLを見たり、みたいな関数が何個かある。Catalyst::Plugin::I18NではHTTPヘッダ以外見るところはないので http_accept_langs()を直接呼んでいる。コマンドラインの環境変数も同じように確認してほしかったら上記のdetect()を使うのがよろしい。

I18N::LangTags::implicate_supers() を使っているのは、言語タグの中の国指定とかを取り外したバージョンを埋め込むため。例えば en_GB (英語・イギリス)とen_US(英語・アメリカ)でそれぞれ国際化ルールを別にしてもいいけど、たいていの場合はひとつ「en」用の国際化データしか用意しない場合が多いので、それを差し込んでおかないとen_GB/en_US用のデータがない→じゃあ国際化できない>< みたいな事になってしまう。

implicate_supers()関数はこれを行ってくれるので、例えば以下の用にLC_ALL=ja_JPという形で言語タグを指定していた場合、ja-jpとjaの二つの言語タグを返してくれるわけだ。

前の記事ではどの言語にローカライズするのかをloc_lang()等で変更する、と書いたが、要はこの結果をloc_lang()に渡すようにすればいいのだ:
loc_lang( I18N::LangTags::implicate_supers( I18N::LangTags::Detect::detect() ) );

以下次号。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

この前の国際化話の続き。まずLocale::Maketext::Simpleの場合。

Locale::Maketext::SimpleはI18N用のクラス定義とかを全部裏でやってしまうモジュール。あとLocale::MaketextのPODに載ってる get_handle()とかでオブジェクトを持ってくる必要はなく、maketextかlocのようなメソッドが現在の名前空間内にエクスポートされる。以下一番簡単なセットアップ方法:
package MyApp; use strict; use Locale::Maketext::Simple Decode => 1, Path => do { # これは、auto/MyApp/I18N以下にファイルを入れれば、設定する必要はない my $path = $INC{'MyApp.pm'}; $path =~ s{\.pm$}{/I18}; # lib/MyApp/I18N/ に変換 $path; } ; sub run { loc_lang("ja"); print loc("Hello, World!"), "\n"; } 1;
これだけだともちろん国際化用のファイルがないので、lib/MyApp/I18N/ja.poとかにファイルを置いておく。Locale::Maketext::SimpleはLocale::Maketext::Lexiconへのインターフェースだから、.poファイルでも.moファイルでも使える。ちなみに今自分はpoeditとかで編集できる.poファイルが好き、という人がいてそう薦められたのであまり考えもなく.poを使っている。
# lib/MyApp/I18N/ja.po msgid "Hello, World!" msgstr "みなさん、こんにちは!"
以上で終了。perl -Ilib -MMyApp -e 'MyApp->run' とかすると国際化された文字列が出力されるはず。あとは翻訳を追加していくなりなんなり。
マニュアルにほとんど書いてない注意点が少々あります:
  • loc() や loc_lang() はExport引数によって調整可能。しかし、Export => 'hoge' とすると hoge() と hoge_lang() という名前になる(連動している)
  • MyApp->loc() とかやりたい場合はExport => '_loc' とかして、MyApp::loc() から_loc()を呼ぶようにしないとまずい
  • このままではloc_lang() を呼び出し、適切に言語設定をしないと、別になんの国際化もしてくれない。
  • use宣言した際に見つからない言語は適用されない。一応ドキュメントに書かれていないreload_loc() という関数もあるが、ドキュメントされてないってことはどこまで安定して使えるのか俺はよくわからん。
Catalyst::Plugin::I18Nは内部でこれを使っている。とりあえず、以下次号
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

実は来週のデブサミで話してきます。


お題はYAPC等で僕の話を聞いている人にとっては毎度のネタになっているテストについてです。新しく作ってるツールとかそういうことに関しても話したいっちゃあ話したいのですが、最近はJPAで啓蒙したい内容とも相まって実利的な話ばっかりですな。


ともあれ、YAPCのオーディエンスはPerlプログラマだったわけですが、今回はもう少し上の層、マネージャーの方々あたりを対象に自動テストの有効性と、Perlが非常に合っている、という話をさせていただきます。


テストを書く、というのが業務の改善になるんだよ、っていうことがもっとどんどんと浸透して、「デスマーチばっかりでプログラマなんてやめたい」って言う人が一人でも減っていけば嬉しい限りです。


ちなみに具体的なPerlでの実践方法とかはモダンPerl入門にちょこちょこ書いてます。

    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

このページのトップヘ