Mo.pmを読んだ
こんばんは。
面白そうだったのでMoを読んでみた。
http://search.cpan.org/~ingy/Mo-0.30/lib/Mo.pod
Moとは
Moose is huge. Moose led to Mouse led to Moo led to Mo. M is nothing. Mo is more. Not much.
Moose、Mouse、Mooからできたlessなやつ。
VERSIONは0.30だった。
コード
Mo.pm
package Mo; $VERSION='0.30'; no warnings;my$M=__PACKAGE__.::;*{$M.Object::new}=sub{bless{@_[1..$#_]},$_[0]};*{$M.import}=sub{import warnings;$^H|=1538;my($P,%e,%o)=caller.::;shift;eval"no Mo::$_",&{$M.$_.::e}($P,\%e,\%o,\@_)for@_;return if$e{M};%e=(extends,sub{eval"no $_[0]()";@{$P.ISA}=$_[0]},has,sub{my$n=shift;my$m=sub{$#_?$_[0]{$n}=$_[1]:$_[0]{$n}};$m=$o{$_}->($m,$n,@_)for sort keys%o;*{$P.$n}=$m},%e,);*{$P.$_}=$e{$_}for keys%e;@{$P.ISA}=$M.Object};
詰めてるなー。golfでもやってるのか。457byte。
ばらしてみる。
$ perl -MO=Deparse perl5/perlbrew/perls/perl-5.14.2/lib/site_perl/5.14.2/Mo.pm
package Mo; $VERSION = '0.30'; # いきなりnoで読み込む no warnings; # 「Mo::」まで作る my $M = 'Mo' . '::'; # Mo::Object空間にnewメソッドを作る *{$M . 'Object::new';} = sub { bless {@_[1 .. $#_]}, $_[0]; } ; # Mo::import *{$M . 'import';} = sub { # warningsプラグマをimport 'warnings'->import; # 出た。bitをいじってstrictをimport、だと思う。1538は0b11000000010 $^H |= 1538; # callerの返り値を左辺が受け取っている、のではなくて # callerをスカラコンテキストで評価、つまり呼び出し元のpackage名と # '::'を結合したのを$Pに入れて、あとのハッシュはただの変数宣言。なにこれ怖い。 my($P, %e, %o) = caller . '::'; # @_の第一引数のクラス名を捨てる shift(); # 拡張にあたる機能をなぜかnoで読み込んで、 # eサブルーチンをここの変数のリファレンス渡して呼ぶ eval "no Mo::$_", &{$M . $_ . '::e';}($P, \%e, \%o, \@_) foreach (@_); # $e{M}があったらreturn。$e{M}はいつできる? return if $e{'M'}; # %eにextendsメソッドとhasメソッドを代入 (%e) = ('extends', sub { # 相変わらずのnoで読み込んで eval "no $_[0]()"; # @ISAに直接叩きこんで継承 @{$P . 'ISA';} = $_[0]; } , 'has', sub { my $n = shift(); my $m = sub { # 引数があればセッタ、なければゲッタ $#_ ? $_[0]{$n} = $_[1] : $_[0]{$n}; } ; # defaultとかrequiredとかあったらその分を追加 $m = $o{$_}($m, $n, @_) foreach (sort keys %o); # シンボルテーブルで呼び出し元へインポート *{$P . $n;} = $m; } , %e); # hasとextends(とその他)をシンボルテーブルで呼び出し元へインポート *{$P . $_;} = $e{$_} foreach (keys %e); # このMo.pmをuseしたものは無理矢理Mo::Objectの子供にする @{$P . 'ISA';} = $M . 'Object'; } ; perl5/perlbrew/perls/perl-5.14.2/lib/site_perl/5.14.2/Mo.pm syntax OK
ほむほむ。これだけだとextendsとhasだけがエクスポートされてくるみたい。
他のrequiredなどを使うときには、podにあるように
use Mo qw'build default builder coerce is required';
みたいにする。
知ったこと。
noで読み込む
いきなり
no warnings;
しているけど、その前にuse warnings;しているわけではない。
つまり先のそれを打ち消したいわけではない。
importメソッドを作っているところの
'warnings'->import;
への布石として使っている。
そもそもno MODULE;の役割って
BEGIN { require MODULE; MODULE->unimport; }
だから読み込みもしているんだよね。
さらにUnquoted stringな警告の出力も止めて一石二鳥みたいな感じか。
他には
eval "no Mo::$_"
eval "no $_[0]()";
が出てくるが、こっちは純粋にrequireとかuseでいいと思うんだけど、noが最小の2文字だからnoにしているのだろうか?
よくできてんなー。