経験は何よりも饒舌

10年後に真価を発揮するかもしれないブログ 

Class::Enumemon の中身をちょっとのぞいてみる

使う機会があってRailsのActive Recordっぽくて便利だと思ったけど、中身があまり想像できなかったのでちょっとだけ調べてみた。

metacpan.org

package IdolType;
use Class::Enumemon (
    values => 1,
    getter => 1,
    indexer => {
        by_id     => 'id',
        from_type => 'type',
    },
    {
        id   => 1,
        type => 'cute',
    },
    {
        id   => 2,
        type => 'cool',
    },
    {
        id   => 3,
        type => 'passion',
    },
);
 
1;
 
package My::Pkg;
use IdolType;
 
# `values`: defines a method for getting all values
IdolType->values; #=> [ bless({ id => 1, type => 'cute' }, 'IdolType'), ... ]

これはcpanに載っていたサンプルコードで、とりあえず IdolType->valuesでなぜ [ bless({ id => 1, type => 'cute' }, 'IdolType'), ... ]が返ってくるのかを調べてみる。

コードを見ると、100行程度でそこまで長くはなかった。
p5-Class-Enumemon/Enumemon.pm at master · pokutuna/p5-Class-Enumemon · GitHub


valuesに注目すると、36行目で作られていた。
p5-Class-Enumemon/Enumemon.pm at 0b7f39e89379c4be478fb88a607aca4db9480eeb · pokutuna/p5-Class-Enumemon · GitHub

$data->{values} = [ map { bless $_, $pkg } @$defs ];


blessが何をしているのかパッと説明できなかったので
Hatena-Textbook/foundation-of-programming-perl.md at master · hatena/Hatena-Textbook · GitHub
あたりを見直す必要があると痛感。

IdolType->valuesで呼び出される処理は52行目から書かれている。

p5-Class-Enumemon/Enumemon.pm at 0b7f39e89379c4be478fb88a607aca4db9480eeb · pokutuna/p5-Class-Enumemon · GitHub

sub _mk_values {
    my ($pkg, $data) = @_;
    no strict 'refs';
    *{"$pkg\::values"} = sub {
        my $values = $data->{values};
        wantarray ? @$values : [ @$values ];
    };
}

*{"$pkg\::values"}が、「IdolType->valuesでなぜ [ bless({ id => 1, type => 'cute' }, 'IdolType'), ... ]が返ってくるのか」の核となっていそう。
「*」について『初めてのPerl』で引いてみても正規表現についてしか出てこない。
『続・初めてのPerl』で調べると、p91に以下の文言があった。

ここでは型グロブの説明はしませんが、*プリフィックスを使って、リファレンスを見て文字列内でどの変数型を使うべきかを判断せよとData::Dumperに指示するという意味になっています。

型グロブについて調べてみると、以下のブログに次のような説明があった。

blog.livedoor.jp

型グロブでシンボルテーブルにアクセス出来ます。シンボルテーブルでは、各データ型ごとに1つのスロットがあって、各スロットは各データ型のリファレンスを参照しています。

とりあえず型グロブっていう概念を使ってやっているんだなー、という感じで今日は終わっておく。
Perlむずかしい。