時計を壊せ

駆け出してからそこそこ経ったWebプログラマーの雑記

Mouse::Util::TypeConstraints等を使って新しい型を定義するときのベストプラクティス

更に追記

MouseX::Typesですが、その後検証してみたかんじ、
要素を「=>」で繋げてしまうと左辺が文字列として認識されてしまうようなので、
要素を「,」で繋げなければいけないようです。
等価だと思っていましたが微妙に違うんですね。

package HogeProject::MouseType;
use strict;
use warnings;
use utf8;

use MouseX::Types -declare => [qw/UInt/];
use MouseX::Types::Mouse qw/Int/;
subtype UInt,
    as Int,
    where { $_ >= 0 };

1;

追記

id:gfxさんによるとMo[ou]seX::Typesがまさにそんな機能を持っているとの事。知らなかった!
http://search.cpan.org/~gfuji/MouseX-Types-0.06/
http://search.cpan.org/~drolsky/MooseX-Types-0.31/
こんな感じで書けるようです。

package HogeProject::MouseType;
use strict;
use warnings;
use utf8;

use MouseX::Types -declare => [qw/UInt/];
use MouseX::Types::Mouse qw/Int/;
subtype UInt
    => as Int
    => where { $_ >= 0 };

1;
use strict;
use warnings;
use utf8;

use 5.10.0;
use Data::Validator;

use HogeProject::MouseType qw/UInt/;

sub hogeaddone {
    state $rule = Data::Validator->new(
        hogecount => +{ isa => UInt }
    );
    my $arg = $rule->validate(@_);

    return $arg->{hogecount} + 1;
} 

say+hogeaddone(hogecount => 1); # say 2

どう考えてもこっちの方が便利だしイケてるので、
下の方法はどうしてもMo[ou]seX::Typesが使えない環境とかだけに留めて、
なるべくMo[ou]seX::Typesを使用すると良いでしょう。
gfx++

原文

Mouse::Util::TypeConstraints等を使って新しい型を定義すると、
型はグローバルな名前空間に置かれるので、
複数の場所で名前が衝突してしまった場合に問題がわかりにくい。


プロジェクトの名前空間等、独自のprefixを付ける事によってこの問題は解消出来る。
しかし、prefixがつくと型名が長くなってしまってだるいので、
以下のような感じでprefixを勝手に付けてくれる君を作っておくとよいのではないか。

package HogeProject::MouseType;
use strict;
use warnings;
use utf8;
use parent qw/Exporter/;

my $PREFIX = __PACKAGE__ . '::';
our @EXPORT_OK = qw/local_type lt/;
sub local_type {
    my($type, $inner) = @_;

    my $local_type = $PREFIX . $type;
    return $inner ? "${inner}[${local_type}]" : $local_type;
}
*lt = \&local_type; # shortcut

use Mouse::Util::TypeConstraints;

subtype lt('UInt')
    => as 'Int'
    => where { $_ >= 0 };

no Mouse::Util::TypeConstraints;
1;


これは他のClassからは以下のように使える。

use strict;
use warnings;
use utf8;

use 5.10.0;
use Data::Validator;

use HogeProject::MouseType qw/lt/;

sub hogeaddone {
    state $rule = Data::Validator->new(
        hogecount => +{ isa => lt('UInt') }
    );
    my $arg = $rule->validate(@_);

    return $arg->{hogecount} + 1;
} 

say+hogeaddone(hogecount => 1); # say 2


だいぶすっきりしていますね。
こんな感じで書くと良いのではないでしょうか。


「もっと良い方法があるよ!」とか、「この方法はクソだ!」とか、「既出だわボケが!」とかあれば教えて下さい!
enjoy!