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しつつ、何か出来そうなんだけど・・・
というところで眠くなってきたので一旦終了します。