sironekotoroの日記

Perl で楽をしたい

MouseX::AttributeHelpers に感動した話

という直感があって、その解が得られるタイミングは往々にして年単位だったりするんですが、割と早く解決できたのでメモ。

いや、今思うとこっちが近いかもしれない。

その君の勘から発した、 君の怒りと苛立ちは理由になる!

こんな例示コードがあります。

package Foo {
    use Mouse;
    use Function::Parameters;

    has List => (
        is       => 'rw',
        isa      => 'ArrayRef[Str]',
        required => 0,
    );

    method add($str) {
        my $array_ref = $self->List();
        push @{$array_ref}, $str;
        $self->List($array_ref);
    }

    __PACKAGE__->meta->make_immutable();
}

package main;
use feature qw/say/;
my $foo = Foo->new();

$foo->add('Web2.0');
$foo->add('Web3');
$foo->add('Web5');

say join " ", @{ $foo->List };    # Web2.0 Web3 Web5

Foo ってクラスを作り、そこに List というアトリビュート(またはプロパティ)と add というメソッドを作ったという図です。

List の中には配列リファレンスが入っており、add でどんどん追加していくという用途です。

で、問題はここ。add メソッド。

単に追加したいだけなのに、一旦配列リファレンスに出力して、それに追加したものを再度設定しているというコード。

    method add($str) {
        my $array_ref = $self->List();  # 今あるリストから取得
        push @{$array_ref}, $str;       # 追加
        $self->List($array_ref);        # 追加した配列リファレンスで置き換え
    }

3行も必要か?

取り出して、処理して、戻す。

いや、絶対もっと楽な方法があるだろ・・・と思いつつ、見つけられなかったのでした。

MouseX::AttributeHelpers

はい。

そこでこのモジュールです。

metacpan.org

メソッドが消えたじゃん・・・書かなくていいじゃん・・・可読性増してるじゃん・・・

package Foo {
    use Mouse;
    use MouseX::AttributeHelpers;

    has List => (
        metaclass => 'Collection::Array',
        is        => 'rw',
        isa       => 'ArrayRef[Str]',
        required  => 0,
        default   => sub { [] },
        provides  => {
            push => 'add',
        }
    );

    __PACKAGE__->meta->make_immutable();
}

package main;
use feature qw/say/;
my $foo = Foo->new();

$foo->add('Web2.0');
$foo->add('Web3');
$foo->add('Web5');

say join " ", @{ $foo->List };    # Web2.0 Web3 Web5

この metaclass => 'Collection::Array', には当然 Collection::Hash など他のデータ構造を設定することが可能で、それぞれのデータ構造を扱う関数も provide で扱うことができます。

すごいなぁ。

コードを書く人の負担を軽減するコードというのは素晴らしいなぁ。

ありがちな処理は全部これで済んじゃう。ひゃー。

久々になんか感動したのでした。