Perl 引数チェック
こんにちは!
皆さんPerl書いてますか?
今日は関数の引数のチェックについてのお話をしていきます。
とはいえ便利なモジュールがあるのでそのご紹介です。
Smart::Args
今回はこのモジュールを使って値をチェックしていきたいと思います。
インストール
いつものcpanmを実行してpackageを入れて使えるようにしましょう。
$ cpanm -v Smart::Args
最初はいろいろ入るので長いですが気長に待ちましょう。。。
使い方
使い方は簡単。
主に下記の2つを使用します。
-
args
- 名前つきの引数をチェックしたいとき
-
args_pos
- 名前つきではないとき
パッと説明してもわからないと思いますので、実際のコードを見ていきたいと思います。
args
名前つきの引数をチェックする
使い方は簡単で、引数を受け取るところにargsを付けるだけ。
受け取る側の変数名 が 引数のキー として利用できます。
use Smart::Args;
&hoge{piyo => 1};
sub hoge {
args my $piyo;
print $piyo;
}
引数が複数あるときは、並べて書いていく。
use Smart::Args;
&hoge(piyo => 1, fuga => 2); # OK
sub hoge {
args my $piyo, my $fuga;
printf "piyo: %d, fuga: %d\n", $piyo, $fuga;
}
piyoとfugaが渡されているかチェックできます。
問題なければ正常終了します。
piyo: 1, fuga: 2
引数が足りないとき
use Smart::Args;
&hoge(piyo => 1); # 引数が足りない(fuga)
sub hoge {
args my $piyo, my $fuga;
printf "piyo : %d, fuga; %d\n", $piyo, $fuga;
}
missing mandatory parameter named '$fuga' at sample.pl line 6.
main::hoge("piyo", 1) called at sample.pl line 3
エラーがでてますね。
ちなみに 引数が多いとき は正常終了します。
use Smart::Args;
&hoge(piyo => 1, fuga => 2, foo => 3); # 引数が多い(foo)
sub hoge {
args my $piyo, my $fuga;
printf "piyo: %d, fuga: %d\n", $piyo, $fuga;
}
piyo: 1, fuga: 2
型のチェック
use Smart::Args;
&hoge(piyo => 1, fuga => "fuga"); # 文字を渡している(fuga)
sub hoge {
args my $piyo, my $fuga => 'Int';
printf "piyo: %d, fuga: %d\n", $piyo, $fuga;
}
'fuga': Validation failed for 'Int' with value fuga at C:/Strawberry/perl/site/lib/Smart/Args.pm line 179.
Smart::Args::_validate_by_rule("fuga", 1, "fuga", "Int", SCALAR(0x29fd990)) called at C:/Strawberry/perl/site/lib/Smart/Args.pm line 63
Smart::Args::args(1, undef, "Int") called at sample.pl line 6
main::hoge("piyo", 1, "fuga", "fuga") called at sample.pl line 3
どのような型がチェックできるかというと・・・
Any
Item
Bool
Maybe[`a]
Undef
Defined
Value
Str
Num
Int
ClassName
RoleName
Ref
ScalarRef
ArrayRef[`a]
HashRef[`a]
CodeRef
RegexpRef
GlobRef
FileHandle
Object
いろいろありますね!
さきほどまでの例だと第2引数しか型チェックできていません。
すべての引数をチェックしたいときは、それぞれに型の指定が必要です。
args my $hoge => 'Int', my $fuga => 'Int';
任意なキー
渡すかどうかわからない引数ってありますよね。
そんなときに使えるoptionalというのが用意されています。
use Smart::Args;
&hoge(fuga => 1, piyo => 2); # ok
&hoge(fuga => 1); # ok
sub hoge {
args my $fuga, my $piyo => {optional => 1};
printf "ok\n";
}
ok
ok
引数が渡されなかった変数(上の場合だと2回目の$piyo)、値はundefとなります。
初期値
指定されなかったら初期値入れておいてほしいというときもあると思います。
そんなときにはdefaultを使います。
use Smart::Args;
&hoge(fuga => 1, piyo => 3); # fuga: 1, piyo: 3
&hoge(fuga => 1); # fuga: 1, piyo: 2
sub hoge {
args my $fuga, my $piyo => {default => 2};
printf "fuga: %d, piyo: %d\n", $fuga, $piyo;
}
fuga: 1, piyo: 3
fuga: 1, piyo: 2
defaultを使用した場合、常に値が入った状態になるので指定しなくても大丈夫になります。
型の指定
my $hoge => 'Int'というように型をチェックしていましたが、
他のオプションと一緒に値の型チェックもしたいというときは、isaを使います。
use Smart::Args;
&hoge(fuga => 1, piyo => "foo"); # piyoが文字になっている
sub hoge {
args my $fuga, my $piyo => {isa => 'Int', default => 2};
printf "piyo: %d, fuga: %d\n", $piyo, $fuga;
}
'piyo': Validation failed for 'Int' with value foo at C:/Strawberry/perl/site/lib/Smart/Args.pm line 179.
Smart::Args::_validate_by_rule("foo", 1, "piyo", HASH(0xf3bec0), SCALAR(0x2a7e9c0)) called at C:/Strawberry/perl/site/lib/Smart/Args.pm line 63
Smart::Args::args(1, undef, HASH(0xf3bec0)) called at sample.pl line 6
main::hoge("fuga", 1, "piyo", "foo") called at sample.pl line 3
ハッシュ
# HashRef
&ex_hash(hoge => {});
sub ex_hash {
args my $hoge => {isa => 'HashRef'};
}
# ArrayRef
&ex_hash_array(piyo => []);
sub ex_hash_array {
args my $piyo => {isa => 'ArrayRef'};
}
配列内の型をチェック
&hash_array(fuga => ['Hoge', 'Piyo']);
sub hash_array {
args my $fuga => {isa => 'ArrayRef[Str]'};
}
package名をチェック
my $hoge = Hoge->new;
$hoge->piyo;
package Hoge;
sub piyo {
args my $self => {isa => 'Hoge'};
}
値が undef or 型 なとき
my $value = "abc";
# my $value = undef;
&fuga(hoge => $value);
sub fuga {
args my $hoge => {isa => 'Maybe[Str]'}; # Str or undef
}
args_pos
名前つきでない引数をチェックする
use Smart::Args;
&hoge(1, 2);
sub hoge {
args_pos my $piyo, my $fuga;
printf "piyo: %d, fuga: %d\n", $piyo, $fuga;
}
piyo: 1, fuga: 2
先程のコードと変わったところはあまりないですねw
これも先程と同じような型チェックなどができます。
もちろんご紹介したoptional・defalut・isaも同じように使用できます。
型チェックでオブジェクトから呼ばれているかチェックするなら・・・
{
package Hoge;
use Smart::Args;
use Object::Simple -base;
sub piyo {
args_pos my $self => 'Object', my $fuga => 'Str';
printf "%s\n", $fuga;
}
}
my $hoge = Hoge->new;
$hoge->piyo("fuga!"); # OK
Hoge::piyo("fuga!") # NG
fuga!
'self': Validation failed for 'Object' with value fuga! at C:/Strawberry/perl/site/lib/Smart/Args.pm line 179.
Smart::Args::_validate_by_rule("fuga!", 1, "self", "Object") called at C:/Strawberry/perl/site/lib/Smart/Args.pm line 107
Smart::Args::args_pos("fuga!", "Object", undef, "Str") called at sample.pl line 7
Hoge::piyo("fuga!") called at sample.pl line 15
とこんな感じでObjectと指定してあげれば、
オブジェクト経由で呼ばれているのをチェックできます。
まとめ
Smart::Argsを使って簡単&楽に引数チェックをいれていきましょう!