「優れたPerlプログラマを見分ける27の質問」に回答

元ネタはこちら
http://d.hatena.ne.jp/gfx/20110301/1298944990


回答例はこちら
http://blog.livedoor.jp/dankogai/archives/51645218.html


以下、やってみました。

1. Perl5において変数のシジルが示すものは何か
 → $,@,%,*。スカラー、配列、ハッシュ、型グロブ
 →○

2. 配列のアクセスする際の $items[$index] と @items[$index] の違いは何か
 →$items[$index]は@items配列の$index番目の要素へのアクセス。
 →@items[$index]は%itemsハッシュの$indexをキーとする値へのアクセス。
 →× @items{$index} と勘違いしてた。。

3. == と eq の違いは何か
 →「==」は数値比較。「eq」は文字列比較
 →○

4. ハッシュをリストコンテキストで評価すると得られるものは何か
 →%hash = ( a => 1 , b => 2); だったら、 ( 'a' , 1 , 'b' , 2)の4要素を持つ配列
 →△ この順番とは限らないか・・

5. Perlドキュメントからキーワードを検索するにはどのようにするのか
 →わからなかった・・・
 →× perldocなのか。

6. Perl5における関数とメソッドの違いは何か
 → MyApps::hoge($param) だと第一引数が$paramで、MyApps->hoge($param)だと「MyApps」が第一で、$paramは第二。
 →○

7. Perl5が変数のメモリを再利用するのはいつか
 →わからない><
 →×

8. 変数のスコープがデフォルトでレキシカルであると保証するにはどのようにするのか
 → 「my」 で宣言する
 →○

9. モジュールからシンボルをインポートするにはどのようにするのか
 →?
 →× 設問が読解できてないので論外

10. perlがモジュールのロードを敢行するディレクトリの操作はどのようにするのか
 →「::」を「/」に変換して検索?
→× 適当に書きすぎた

11. Perl5のエラーメッセージの検索はどのようにするのか(発生するエラーメッセージに説明を加える方法を知っていればボーナスポイント)
 →?
 →×

12. 配列を関数に渡したときに起きることは何か
 → $class->func( @ary , $scalar );だったら、sub funcで$scalarを判別することは無理。@_の中に全部まとめて入ってしまうので。
 →× そういうことじゃない

13. 複数の配列をそれぞれ区別して関数に渡すときにはどのようにするのか
 → リファレンス渡し。$class->func( \@ary1 , \@ary2 , \@ary3 );
 →○

14. 呼び出された側から見た return; と return undef; の違いは何か
 → @result = sub func{ return; }; if @result は偽だけど、
   @result = sub func{ return undef; }; if @result は真。「undef」という要素が@resultに入っている。
 →○かな?

15. 標準的CPANディストリビューションではテストはどこに置かれるか
 → t/配下
 →○

16. 標準的CPANディストリビューションでテストを走らせるにはどのようにするのか
 → perl Makefile.pl → make → make test。
 →○

17. CPANから新しいディストリビューションをインストールする際に使うコマンドはなにか
 → cpan install App::cpanminus
 →○ そして、以後はcpanmを・・・

18. 組み込み関数openを3引数形式で使うのは何故か
 → ファイルハンドルをレキシカルスコープにするため
 →△ 微妙にズレてる

19. openのようなシステムコールのエラーを検出(と報告)するにはどのようにするのか(エラーの検出と報告を自動的に有効にする方法を知っていればボーナスポイント)
 → eval{};でくくって、 $@で検出?
 →× なんか読み違えてた

20. Perl5で例外を投げるにはどうするのか
 → die; もしくは Carp::croak;
 →○

21. Perl5で例外を捕捉するにはどうするのか
 → eval{};でくくって、 $@で検出?
 →○

22. ファイルの読み込みにおけるforとwhileの違いは何か
 → わからなかった。。
 →× 猛省します


23. メソッドと関数においてパラメータ*3を取り扱うにはどうしたらよいか
 → $param = shift; で取ると、@_から先頭要素を抜く。 ($param1 , $param2 ) = @_; で取ると、@_からコピーで取得。
 →○

24. my ($value) = @_; の変数を囲む括弧が意味するものは何か、またこの括弧を取り除くと何が起きるか
 → わからなかった。。
 →× 言われてみりゃ、そりゃそうだ・・・

25. new は組み込み関数ないしキーワードか
 → No。
 →○

26. コアライブラリやCPANモジュールのドキュメントを読むにはどのようにするのか
 → perldoc perl
 →○

27. ハッシュの値のみを取り出したい時はどのようにするのか
 → my $result = value ( %hash );
 →× 地味に「value『s』」だったorz

結果
○:14
△:2
×:11


なんていうか、50点・・・。8割で優れているとのことなので、
27 * 0.8 なので22問以上は答えられるよう頑張らないといけないですね。。
ダメすぎて凹んでますが、晒すネタとしてちょうどいいかも。

pm-uninstallで『localな環境』のコアモジュールを消せるアップデートをしていただきました

この前の文字コード問題で、local::libで作った手元の環境だけ
Encode.pmをアップデートしてテストなどしていました。


この辺は今は「 cpanm -l ~/local Encode 」でサクっと出来てステキですね。
そして、実験終了後に消そうと思って、

pm-uninstall -l ~/local Encode

とやったんですが、

Encode is Core Module!! Can't be uninstall

と怒られてしまい、終了。


どうやら過去の経緯からコアモジュールは削除できないようです。


確かに通常のlibの下で考えるなら気軽に消せてはマズイという事で
正しいのですが、同じようにlocalにな環境に入れる場合はないのかな、
ということで #perl-casualで相談してみたところ、即効で対応していただけました!


http://search.cpan.org/~xaicron/App-pmuninstall-0.16/


特にオプション等を増やして実行する必要はなく、対象がコアモジュールでも
コア以外のところ(local等)にインストールされているもので、コアなlibにはちゃんとそれがある、
という確認が出来れば削除するようにしていただきました。


上の判定による対応は非常にスマートで、相談する前の時点では -f のオプションで消せるようにして
欲しいくらいのお願いをするつもりだったので、相談してみて良かったです。


すばやく対応していただいたxaicronさん++

utf8とEncodeの焼きまわし記事

2011年にしてようやくutf8と向き合うことになりました。
と言っても、95%は「原則」を正しく読めば解決しました。
エントリとしては過去情報の焼き増しになるけど、一応メモとして残しておく。


原則
http://d.hatena.ne.jp/tokuhirom/20080408/1207619640
http://perl-users.jp/articles/advent-calendar/2009/casual/10.html


特にxaicronさんのエントリを改めて読み直したらカンペキにまとまっててすごい!Advent Calendar++


最初に認識しておくこと
sjisな世界、eucな世界、utf8な世界は他のレイヤーでもあるが、utf8フラグが立っている世界はperlの中にしかない」


今回困ったのは、

Cannot decode string with wide characters. 〜

のように出た場合と

Wide character in print 〜

が出た場合。
後者はフラグが立った状態でprintした場合なので、encodeして内部文字列じゃなくしてからprintすればおk。


上記原則に則るとまずdecode処理をするわけですが、
Encode::decodeはすなわちutf8フラグを立てることであって、既に立っているものに対して
実行すると上記エラーが発生します。
なので基本は「入口 -> decode-> 処理 -> encode -> 出口」 なんですが、
入口の時点でutf8フラグが立っている場合に備えて、フラグが立っているか確認したほうがいい。
入口が完全に外界のみならば、フラグが立った状態で来ることはないわけだけど、perlの世界における外界からの場合はその可能性がある。これが今回混同してたところ。


実際の処理の中は

  • use utf8; されている(その中で扱う文字列には自動でフラグが立つ)
  • ファイルそのもののエンコーディングがutf8になっている

という前提でいくと、「フラグが立っていない場合のみdecodeする」で状態はめでたく統一される。
もし仮に、フラグが立ってない世界を構築しているのであれば、「立っていたらEncodeする」ことで同じくデータ的には揃った状態になる。

#!/usr/bin/perl
             
use strict;  
use warnings;
             
package UTF8World;
             
use strict;  
use warnings;
             
use Test::More;
use Test::Warn;
use Encode;  
use utf8;    
             
sub function_of_utf8world{
    my $charset = shift;
    my $arg_str = shift;
             
    my $flagged_utf8;
    if( Encode::is_utf8( $arg_str ) ){
        diag 'arg_str is flagged utf8';
        $flagged_utf8 = $arg_str;
    }        
    else{    
        diag 'arg_str is not flagged utf8';
        $flagged_utf8 = Encode::decode_utf8( $arg_str );
    }        
    ok Encode::is_utf8( $flagged_utf8 ) , 'flg ON';
             
    warning_like { print STDERR $flagged_utf8 } qr/^Wide character in print/ ,q/Wide character in print/ ;
             
    $flagged_utf8 .= 'フラグON';
             
    return Encode::encode( $charset , $flagged_utf8 );
             
}

package OutWorld;
             
use strict;  
use warnings;
use Test::More;
use Encode::Guess;
{            
    use utf8;
    my $flg_on_utf8 = 'あ';
    no utf8; 
             
    ok Encode::is_utf8( $flg_on_utf8 );
             
    my $ret = UTF8World::function_of_utf8world( 'utf-8' , $flg_on_utf8 );
             
    ok ! Encode::is_utf8( $ret );
    my $enc = guess_encoding($ret, qw/ shiftjis euc-jp /);
    is $enc , 'shiftjis or utf8' , 'flg on utf8';
}            
             
{            
    use utf8;
    my $str = 'あ';
    no utf8; 
    my $flg_off_utf8 = Encode::encode_utf8( $str );
             
    ok ! Encode::is_utf8( $flg_off_utf8 );
             
    my $ret = UTF8World::function_of_utf8world( 'utf-8' , $flg_off_utf8 );
             
    ok ! Encode::is_utf8( $ret );
    my $enc = guess_encoding($ret, qw/ shiftjis euc-jp /);
    is $enc , 'shiftjis or utf8' , 'flg off utf8';
}            
             
{            
    my $str = 'あ';
    my $euc = Encode::encode( 'euc-jp' , $str );
             
    ok ! Encode::is_utf8( $euc );
             
    my $ret = UTF8World::function_of_utf8world( 'euc-jp' , $euc );
             
    ok ! Encode::is_utf8( $ret );
    my $enc = guess_encoding($ret, qw/ shiftjis euc-jp /);
    is $enc , 'shiftjis or euc-jp' , 'shiftjis or euc-jp';
}            
             
             
done_testing();

=================================================================
2011.02.21追記
nihenさんより、ブクマコメントいただきまして、以下のリンクを見ました。
http://subtech.g.hatena.ne.jp/miyagawa/20080218/1203312527
同じ事はこちらにもありました。
http://perl-users.jp/articles/advent-calendar/2010/casual/4
先人の知恵を活かしきれずに同じ過ちを犯してしまっていたようです。。。


今回書いた意図としては、日本語文字列変換の際に
One.pm -> Convert.pm
Other.pm -> Convert.pm
Another.pm -> Convert.pm
みたいな呼び出し関係があり、Convert.pmに
文字列を渡すとConvert.pmの中身が
sub utf8_to_euc{
# decode
# ごにょごにょ
# encode
}
となっている。という前提で
フラグがONだと、最初のdecodeで怒られてしまう、
というのが解決したい課題でした。


ここで、Convert.pmの中で
my $enc = encode_utf8($str) if is_utf8($str);
を挟むことによって、decodeが通る、という理解を残したかったのです。


理解できていなかったのは、日本語以外のケースとモジュールの立ち位置でしょうか。
latin-1で扱われる文字があることと、この処理をするのがCPANモジュールなのか
特定サービスの限られた呼び出しのみを想定するのか。が把握できていませんでした。

また上のテストスクリプトがフラグOFFの時にdecodeするようになってるので、
残したかった事と合ってない、と今更気づきました。


まとめると、対象が文字列であるか否かを意識した上で処理をすること、でしょうか。
(まだ混乱してるかも・・・、時間を空けて読み直す)

それにしてもやっぱりAdvent Calendar(2009も2010も)++でした。

今さらですが

あけおめ、ことよろです。
今年の抱負なんぞ書いてみたいところですが、
そもそも去年は沈黙な1年でした。


前半は主にクローズドソースなコードを書いておりまして、
オープンソースに貢献できてませんでした。
後半はYAPCトークできたことは非常に貴重な経験でしたが、逆に言うとそれだけだったかなと。


さて、今年に至っては仕事内での立ち位置も微妙に変わって、クローズドソースなコードすら書けておりませぬ。。
今まではやっぱりソースで語る事がエンジニアとしての役目かなと思っていたんですが、一向にアウトプットできそうにないのでちょっと取り組み方を変えようかなと思っています。


本の感想を書いてみるもよし、コードリーディングの結果を書いてみるもよし、業務でやったこともをもう少しスマートに公開していけたら幅広がるんじゃないかなとかとか。


そんな色々を試してみるために・・・


MacBook Air 11インチ欲しい!


前振りが長くてすみません…
でも前振り部分も本音だったりしますので、今年もよろしくお願いします。

YAPC::Asia 2010で発表しました(反省会場)


あけましておめでとうございます(今年初のエントリ的な意味で)
昨日・今日と開催されたYAPC::Asia 2010でQudoについて発表してきました。



発表資料は↓にアップしました
http://masartz.github.com/presentation/yapcasia_2010/start.html



ということで、反省内容を列挙します、、、


思った以上に緊張した

まぁ緊張するだろうとは思ってたんですが、正直手は震えるは、詰まって頭が真っ白になるは、尋常じゃなかったのが自分でも驚き。。お聞き苦しいかったろうと猛省。

ターミナル見えてなかったですよね

えぇ、薄々気づいていました。準備不足ですみません。
ブラウザの文字サイズとかは気を使って発表前から微調整していたんですが、
デモは「もしかしたらするかも」程度に思っていたので、ぬかりました。
お詫びにデモスクリプト群もgithubにアップいたしました↓
http://gist.github.com/630119
http://gist.github.com/630120

使いこんでいない部分はやっぱり詰まる

Plugin:::LoggerとHook::Notifyのあたりでテンパりましたが、予想通りでした、、
今回の発表内容を決めた時から自分が関わっているプロダクトのようで実は触ってない部分がたくさんあって、他人のふんどしで勝負するように
認識されることは覚悟してましたが、この辺を上手く説明出来なかったのは反省要因。

ベンチの結果が誰得だった

公正なベンチの結果を貼った訳ですが、標準Qudoのイメージが上がらない、という自虐的な内容になっちゃいましたがDBI側の利点を言っておきたいなという気持ちの表れでした。
ちなみに手元ではGearman::XSがうまくインストールがひっかかったので、
精度の問題から採用しませんでしたが、一応自分のマシンで実行した結果も貼っておきます。

                             Rate qudo_skinny the_schwartz qudo_dbi qudo_skinny_cached the_schwartz_cached the_schwartz_simple qudo_dbi_cached gearman gearman_cached the_schwartz_simple_cached
qudo_skinny                 386/s          --         -19%     -54%               -56%                -59%                -75%            -84%    -88%           -89%                       -95%
the_schwartz                476/s         23%           --     -43%               -46%                -50%                -69%            -80%    -86%           -86%                       -93%
qudo_dbi                    840/s        118%          76%       --                -5%                -11%                -45%            -66%    -75%           -76%                       -88%
qudo_skinny_cached          885/s        129%          86%       5%                 --                 -6%                -42%            -64%    -73%           -74%                       -88%
the_schwartz_cached         943/s        144%          98%      12%                 7%                  --                -39%            -61%    -72%           -73%                       -87%
the_schwartz_simple        1538/s        298%         223%      83%                74%                 63%                  --            -37%    -54%           -55%                       -78%
qudo_dbi_cached            2439/s        532%         412%     190%               176%                159%                 59%              --    -27%           -29%                       -66%
gearman                    3333/s        763%         600%     297%               277%                253%                117%             37%      --            -3%                       -53%
gearman_cached             3448/s        793%         624%     310%               290%                266%                124%             41%      3%             --                       -52%
the_schwartz_simple_cached 7143/s       1750%        1400%     750%               707%                657%                364%            193%    114%           107%                         --

そもそも資料は余裕を持って作る

直前の連休を使っても完成しないようなクォリティがあかんかった。
やっぱりなるべく早く作って、少しでもまともなものにしたい。

反省ここまで、YAPC::Asia2010全体の感想

振り返ればyokohama.pm(#3)で発表させていただいたのがperlコミュニティでのデビューでした。
今日のPMグループディスカッションのセッションでも触れられていましたが、
yokohama.pmが「shibuya.pmの申し込みに漏れてしまったり、発表をためらう人も歓迎」というスタンスで開催されていたのが大きかったです。
それがきっかけとなって、今回(内容はダメダメだったんですが形として)YAPC::Asiaで発表が出来たというのは素直に嬉しかったです。


グループディスカッションでは、他の地方pmの大変さが伺い知れましたが、
perl-casual同様こういう所から盛り上がって行くのは今後ともあって欲しいなと思いましたし、自分もお手伝いしていきたいなと思いました。

また・・・発表してみたいかも

そして、やってみて思ったのは「また発表したい」でした。
年1回のイベントだと思うので、次は来年になってしまうんですが
せっかくの貴重な機会だからこそまたやってみたいなと思います。っていうかリベンジしたい。
実は思う所があって、今回は「最初で最後のYAPC発表」のつもりで臨んだんですが、ちょっとその考えも揺らぎました。
やってみた事以外に、もう一つの要因は他の方のセッションを聞いたり、実際話してみて影響を受けた部分だったりします。


今回振り返ってみると2008年のMoose、2009年のPlack/PSGIのような目玉となる技術(のセッション)がなかったんじゃないかな?と。
今回一番感じたのはPerlの技術力の話より、webの知識、もっというとシステムの知識について個人的に考えさせられるセッションが多かった気がします。
ネットワークの知識だったり、言語間の差異よりももっと大切な事だったり、起業することだったり、大規模システムだけじゃないことだったり。
Perl言語そのもののメンテに関する話でさえ、本質的にはどの仕事にも通じる「働き方」に関して学ぶべき事がありました。


Perlカンファレンスっぽくはないかもしれないけど、Perlという言語がハブになってそういう事を色々見られたのは良かったなと思います。でも、それだけの様々な人が集まるっていうのがやっぱりYAPCっぽいですかね。


運営陣のスムーズな進行により、快適に過ごさせていただきました。ありがとうございました。


YAPC::Asia2010 お疲れさまでした。来年も楽しみにしています。

JPerl Advent Calendar 2009 にQudoの記事を書きました

12月1日より、日本のPerl界の有志によって実施されている
「JPerl Advent Calendar 2009」のhacker trackに
「Qudo」についての記事を書いてみました。


http://perl-users.jp/articles/advent-calendar/2009/hacker/13.html


正直hacker trackは名だたる有名なギークさんばっかりで場違い感が否めないのですが、、
数少ない自己モジュールからひねり出してみました。


内容としては、せっかくのadvent calerndarなのでクリスマスネタを入れてみました。


結果としては、オブジェクト指向入門書の第1章の
動物から馬が出来たり、乗り物から車が出来る、みたいな
読んでて違和感を感じるノリになってるかも知れません。


この記事自体はさらっと読み流していただいて、
その他のhacker trackや、casual trackにもカジュアル以上の
気合い入ったエントリがたくさん投稿されているので合わせて
ご覧ください。


同じくQudoの開発者のid:nekokakさんのDBIx::Skinny track(1人舞台)も展開中ですので、そちらもどうぞ。


さて、とは言ったもののインデックスページからの
リンクがない件が、nim のソースとかもチラっと見たんですが
わかりませんでした。。運営に支障をきたすような、なんか悪い事してなければいいんですが・・・
大丈夫っぽい。
http://perl-users.jp/articles/advent-calendar/2009/hacker/

Params::Validate覚書き

Params::Validateを触ってみようと思い、色々ソースを見たんですが、イマイチわからなかったです。。そんな時に限って、ググっても意外にヒットしない・・・


普通の人は解読して、何かを残すほど難しいモジュールじゃないのかな、、と思いつつ
ドキュメント見るのは正直いまだに苦手なので、とりあえずサンプル書きながら体で覚えようとしてみました。


なんか落ち着いて読んでるうちに理解出来たと思う部分もあるけど、
まぁせっかく試したので貼っておきます。


必須項目のテストコード(test_mandatory.pl)

#!/usr/bin/perl 

use strict;
use warnings;
use Params::Validate;

my %test = (
    foo => 'hoge',
    bar => 'moge',
    baz => 'tete'
);

&test_func( %test );

delete $test{baz};
&test_func( %test );

delete $test{foo};
eval { &test_func( %test ); };
print $@ if $@;

sub test_func{
    Params::Validate::validate( @_,
        {
            foo => 1,
            bar => 1,
            baz => 0,
        }
    );
    return 1;
}


上の実行結果

Mandatory parameter 'foo' missing in call to main::test_func
at test_mandatory.pl line 23
main::test_func('bar', 'moge') called at test_mandatory.pl line 19
eval {...} called at test_mandatory.pl line 19


一番単純なパターンですね。


対象のキー値に対して1を渡せば必須。0を渡せばnot必須。
だから「delete $test{baz};」しても怒られないけど、
「delete $test{bar};」したら怒られる。


これだけで、済ませるっていうのはさすがに少ないかも知れません。




型チェックのサンプル(test_type.pl)

#!/usr/bin/perl 

use strict;
use warnings;
use Params::Validate qw/:all/;

my $scalar = 'scalar_ref';
my %test = (
    'scalar'    => 'abcde',
    'scalarref' => \'scalar_ref',
    'arrayref'  => [qw/ 1 2 3 4 5 /],
    'hashrref'  => { 'key1' => 'value1','key2'=>'value2' },
    'coderref'  => sub{ return 'test_code'.'ref_test';},
    'boolean'   => '1a2b',
);

# All OK
&test_func( %test );

# Scalar Error
$test{'scalar'} = {key => 'value'};
eval { &test_func( %test ); };
print $@."\n" if $@;

# ScalarRef Error
delete $test{'scalar'};
$test{'scalarref'} = [qw/6 7 8/];
eval { &test_func( %test ); };
print $@."\n" if $@;

# ArrayRef Error
delete $test{'scalarref'};
$test{'arrayref'} = 9;
eval { &test_func( %test ); };
print $@."\n" if $@;

# HashRef Error
delete $test{'arrayref'};
$test{'hashref'} = 9;
eval { &test_func( %test ); };
print $@."\n" if $@;

# CodeRef Error
delete $test{'hashref'};
$test{'coderef'} = {'key' => 'value'};
eval { &test_func( %test ); };
print $@."\n" if $@;

# Boolean Error
delete $test{'coderef'};
$test{'boolean'} = [qw/ 10 11 12/];
eval { &test_func( %test ); };
print $@."\n" if $@;

sub test_func{
    Params::Validate::validate( @_,
        {
            'scalar'    => {type => SCALAR},
            'scalarref' => {type => SCALARREF},
            'arrayref'  => {type => ARRAYREF},
            'hashrref'  => {type => HASHREF },
            'coderref'  => {type => CODEREF },
            'boolean'   => {type => BOOLEAN },
        }
    );
    return 1;
}


上の実行結果

The 'scalar' parameter ("HASH(0x826670)") to main::test_func was a 'hashref', which is not one of the allowed types: scalar
at test_type.pl line 49
main::test_func('boolean', '1a2b', 'scalar', 'HASH(0x826670)', 'coderref', 'CODE(0x826460)', 'arrayref', 'ARRAY(0x800d80)', 'hashrref', ...) called at test_type.pl line 20
eval {...} called at test_type.pl line 20


The 'scalarref' parameter ("ARRAY(0x82679c)") to main::test_func was an 'arrayref', which is not one of the allowed types: scalarref
at test_type.pl line 49
main::test_func('boolean', '1a2b', 'coderref', 'CODE(0x826460)', 'arrayref', 'ARRAY(0x800d80)', 'hashrref', 'HASH(0x826664)', 'scalarref', ...) called at test_type.pl line 25
eval {...} called at test_type.pl line 25


The 'arrayref' parameter ("9") to main::test_func was a 'scalar', which is not one of the allowed types: arrayref
at test_type.pl line 49
main::test_func('boolean', '1a2b', 'coderref', 'CODE(0x826460)', 'arrayref', 9, 'hashrref', 'HASH(0x826664)') called at test_type.pl line 30
eval {...} called at test_type.pl line 30


The following parameter was passed in the call to main::test_func but was not listed in the validation options: hashref
at test_type.pl line 49
main::test_func('boolean', '1a2b', 'hashref', 9, 'coderref', 'CODE(0x826460)', 'hashrref', 'HASH(0x826664)') called at test_type.pl line 35
eval {...} called at test_type.pl line 35


The following parameter was passed in the call to main::test_func but was not listed in the validation options: coderef
at test_type.pl line 49
main::test_func('boolean', '1a2b', 'coderef', 'HASH(0x8267b4)', 'coderref', 'CODE(0x826460)', 'hashrref', 'HASH(0x826664)') called at test_type.pl line 40
eval {...} called at test_type.pl line 40


The 'boolean' parameter ("ARRAY(0x800eac)") to main::test_func was an 'arrayref', which is not one of the allowed types: scalar undef
at test_type.pl line 49
main::test_func('boolean', 'ARRAY(0x800eac)', 'coderref', 'CODE(0x826460)', 'hashrref', 'HASH(0x826664)') called at test_type.pl line 45
eval {...} called at test_type.pl line 45


実際に多く使いそうなパターンですね。


テストはそれぞれの型が順番にこけるのを確認しつつ、
終わったものはエラーが出ないようにdelete していっています。


「{type => 『hoge』}」のhashrefを対象のキー値に対して渡してやります。
チェックできる型のタイプは上で全部じゃなくて、
GLOBとかOBJECTとかまだまだあるようです。詳しくはドキュメント参照。


OBJECTは後述のisaの方がいいんじゃないかと思いますが、違うかな。



オブジェクトと正規表現のチェック(test_isa_regex.pl)

#!/usr/bin/perl 

use strict;
use warnings;
use Params::Validate;

my %test = (
    object => (bless{},'Test::Object') ,
    regex  => 111
);

&test_func( %test );

# Object Error
$test{object} = bless{}, 'Test::Object2';
eval { &test_func( %test ); };
print $@."\n" if $@;

# REGEX Error
$test{object} = bless{}, 'Test::Object';
$test{regex} .= 'a';
eval { &test_func( %test ); };
print $@."\n" if $@;

sub test_func{
    Params::Validate::validate( @_,
        {
            object => {isa   => 'Test::Object'},
            regex  => {regex => qr/^\d+$/},
        }
    );
    return 1;
}

上の実行結果

The 'object' parameter ("Test::Object2=HASH(0x800e34)") to main::test_func was not a 'Test::Object' (it is a Test::Object2=HASH(0x800e34))
at test_isa_regex.pl line 24
main::test_func('object', 'Test::Object2=HASH(0x800e34)', 'regex', 111) called at test_isa_regex.pl line 15
eval {...} called at test_isa_regex.pl line 15


The 'regex' parameter ("111a") to main::test_func did not pass regex check
at test_isa_regex.pl line 24
main::test_func('object', 'Test::Object=HASH(0x81ffe4)', 'regex', '111a') called at test_isa_regex.pl line 20
eval {...} called at test_isa_regex.pl line 20


ちょっとオマケっぽくやってみました。
ただ、regexは結構使いますね。数値チェックとかそういや各所にある気がします。


使い方は型の時と同じで指定が違うだけです。
regexの方は期待値の部分は当然正規表現になりますな。




まとめると、ドキュメントにあること以上はやってない。。
けど、なんとなくわかった気がするのでこれはこれでOKかと。
(勘違いしてる部分がなければいいのですが・・・)




途中から気づいたというか思い出しましたが、
どっちかって言うと、validationの指定方法より
validate , validate_pos , validate_with あたりが区別ついてなくて混乱してたんじゃないか、という気がしてきました。


「validate_pos」は「validate_posisitional」の事をおそらく指していそう。
引数の渡し方(ハッシュor配列)の違いで、配列を受け取る用かと思われます。


んで、validate_withがやっぱりわからない、、
文字通りvalidateしつつ、何か出来そうなんだけど・・・
というところで眠くなってきたので一旦終了します。