Masteries

技術的なことや仕事に関することを書いていきます.

Class::Accessor::Typedで独自の型を使う

Class::Accessor::LiteやClass::Accessor::Lite::Lazyのように使えて, 型の恩恵を受けられる, Class::Accessor::Typedというモジュールを昔書きました.

metacpan.org

詳しくは, 昔Kichijoji.pmで紹介した時に使った資料をまとめたものがあるので, こちらをご覧頂ければと思います.

papix.hatenablog.com

このモジュールは大変便利なんですが, 1つ課題がありました. それは独自の型をうまくいい感じに使う方法が当時の自分には思い浮かばなかった... ということです.

例えば, 次のような Types.pm があり, ここで「正の整数」であるPositiveIntという型を定義していたとします.

package Types;
use strict;
use warnings;

use Mouse::Util::TypeConstraints;

subtype 'PositiveInt',
    as 'Int',
    where { $_ > 0 },
    message { '0以上の整数でなければなりません' };

Class::Accessor::TypedでこのPositiveIntを使うには, 常にTypesを一緒にuseしないといけません(そうしなければ, Class::Accessor::TypedがPositiveIntの定義を見つけられないからです).

package Pkg;
use strict;
use warnings;

# これがないと, 次のようなエラーが発生する:
# 'baz': Validation failed for 'PositiveInt' with value 1 at
# ...
use Types;

use Class::Accessor::Typed (
    rw => {
        baz => 'PositiveInt',
    },
    new => 1,
);

1;

ちょっと面倒ですね. この辺りで悩んでいて, プロダクト開発に導入するにあたって悩んでいたのですが, ふと思いつきました. それは, 次のようなパッケージを用意して, これを使うようにするというアイデアです:

package MyClassAccessorTyped;

use Types;
use Class::Accessor::Typed;

sub import {
    goto \&Class::Accessor::Typed::import
}

1;

こうすると, MyClassAccessorTyped をuseするだけで事足りるようになります(use Types;しなくても意図通りに動作する).

package Pkg;
use strict;
use warnings;

use MyClassAccessorTyped (
    rw => {
        baz => 'PositiveInt',
    },
    new => 1,
);

1;

本来はClass::Accessor::Typed単体で綺麗に扱えるようにするべきなのでしょうが, 今のところかっこいい解決策が思いついていないので, この手で回避するのがいいのではないか, と思っています. ちょっとダサい(?)感じもしますが, Class::Accessor::LiteやClass::Accessor::Lite::Lazyで型の恩恵を受けられるのはそのダサさ(?)を超えるメリットがある... と思っています. この機会に是非Class::Accessor::Typedをお試し頂ければ幸いです.

また, Class::Accessor::Typedから独自の型をいい感じに使えるようにする問題について, 良いソリューションがありましたら, TwitterやPull Requestでご意見をお寄せ頂けると幸いです. よろしくおねがいします.