メタプログラミング
Perl編
Japan Perl Association
株式会社ライブドア
牧 大輔

• @lestrrat• 12 yrs of writing perl
• Internal Tools Guy• JP→BR→JP→PT→US→JP

特にこれが専門というわけではないので

調べてみた要約：プログラムを生成するプログラムね？

なんとなく探った結果evalとかも入るけど、DSL作るとかメタオブジェクトプログラミングとかがうけるらしいまず簡単なeval系
my $str = “sub {\n”;
foreach my $word ( qw(foo bar baz) ) {$str .= “return 1 if \$_[0] =~ /$word/;\n”;}$str .= “return;\n}\n”;
my $code = eval $str;$code->(“foo”); # TRUE
$code->(“bar”); # TRUE
$code->(“fuga”); # FALSE

動的に任意の文字列にだけマッチする関数を作る、とかまず簡単なeval系
my $str = <<EOM;
sub {return 1 if \$_[0] =~ /foo/;
return 1 if \$_[0] =~ /bar/;
return 1 if \$_[0] =~ /baz/;return;}EOM
my $code = eval $str;$code->(“foo”); # TRUE
$code->(“bar”); # TRUE$code->(“fuga”); # FALSE

動的に任意の文字列にだけマッチする関数を作る、とか普通のクラス
package MyClass;use strict;use base qw(Class::Accessor::Fast);
sub foo { ... }sub bar { ... }皆さんの大好きなPerlクラスのテンプレート

めたぷろぐらみんぐ
してみたい！

eval()でよくね（ｒｙmy $classname = “MyClass”;
my @superclasses = qw(Class::Accessor::Fast);
eval <<EOM;
package $classname;use base qw(@superclasses);
EOM

考え方は一番ストレート
メソッド定義あたりでエスケープの嵐で破綻する

グロブ・グローバル変数制御@MyClass::ISA = qw( Class::Accessor::Fast );# 継承*MyClass::foo = sub { ... }; # メソッド宣言
sub MyClass::bar { ... } # また違うメソッド宣言

名前空間に関数、変数をくっつける事は自由
これだけでほぼ全ての事ができるえ、そんなMOP嫌だ？

でもPerlはその辺りが可愛いのに・・・わがままさん☆

Moosepackage MyClass;use Moose;# 継承
extends ‘FooBar’;# ロール適用
with ‘WithHoge’;# アトリビュート宣言。初期化用のコードやアクセサーも作成
has foo => ( is => ‘ro’, isa => ‘Int’ );クラスを定義するためのDSLの塊
言語にないものはライブラリで作る！それがPerl!

MooseでMOP
my $meta = Moose::Meta::Class->create(“MyClass”,superclasses => [ “FooBar” ]);$meta->add_method( “hoge” => sub { ... } );$meta->add_attribute( “foo” => (is => ‘ro’isa => ‘Int’,) );my $object = $meta->new_object();

クラスを定義するためのDSLの塊

無名クラス（テストとかに結構便利）# MyClassを継承する無名クラスを作成
my $meta = Moose::Meta::Class->create_anon_class(superclasses => [ “MyClass” ]);# 親クラスのhogeメソッドをラップしたメソッドを定義$meta->add_around_method_modifier( hoge => sub { ... } );特異クラス等の実装に！

あ、DSLのほうがいいんでしたっけ？

PerlでDSL（簡単編）
sub declare_as ($@) { # <--- “prototype”...
}
sub bar ($) { ... }他のどこでもほぼ使うアテの内Perlの”prototype”を使うとちょっと楽しいPerlでDSL（基本）declare_as ‘hoge’, ( opt => “val”, opt2 => “val” );bar ‘fuga’, ‘fuga’; # 一応これでもOK・・・# ただし、($)としか指定していないので、# bar(‘fuga’), ‘fuga’ とパースされる$や@で引数のコンテキスト・構文が曖昧な時の結びつきを指定できる

PerlでDSL（飛翔編）# こういうのつくりたい！
map { ... コード ... } @list;

PerlでDSL（飛翔編）
sub mymap { ... }# syntax error “} @list”
mymap { ... コード ... } @list;

PerlでDSL（飛翔編）
sub mymap { ... }# syntax error “} @list”
mymap { ... コード ... }, @list;

ちなみにカンマをいれると、{}はコードブロックではなく、無名ハッシュとして認識される

PerlでDSL（飛翔編）# prototype ‘&’
sub mymap (&@) { ... }# OK!
mymap { ... コード ... } @list;

PerlでDSL（飛翔編）
sub mymap (&@) {my ($code, @list) = @_;my @result;foreach my $arg (@list) {push @result, $code->($arg);}
return @result;}&を指定すると、subキーワードを使わずにコードブロックを指定することが可能

PerlでDSL（飛翔編）
use Teng::Schema::Declare;
my $schema = schema { # Start block
table { # Another blockname ‘tablename’;pk ‘primary_key’;columns qw(hoge fuga moga);}} “MySchema”;
なんかかっこいい！
無名コードブロックでコードをネストしていける注意事項

&指定は第一引数に指定した時のみ、sub宣言を省略できる。また@を第一引数として指定してしまうとそれが残りの引数を全て食ってしまうので+という表現を使わな
いとpushのような形の引数宣言はできないので、これを使う際には@̲の中身に充分注意すること要約：perldoc perlsubを良く読めPerlでDSL（変態編）
use 5.10;

use Moose;use MooseX::Method::Signatures;# !!! method宣言？？ 引数の型指定？
method hello ( Int $howmany ) {$self->log_info( join “ “, (“hello”) x $howmany );}method log_info ( Str $message ) {say $message;}

Perlにmethodなんてないんだけど！

PerlでDSL（変態編）•Devel::Declare• Perlのパーサーにフック• PerlだけでPerlの構文を変えられる• 究極のDSL作成ツール！

PerlでDSL（変態編）•Devel::Declare
• 重い
• きもい
• 某氏：「Devel::Declare のソースよめない人はつかわない」• 詳細は自分でみてね！
•

http://api.metacpan.org/source/FLORA/Devel-Declare-0.006005/t/method.t結論１：Perlは言語がそもそもメタPerlは言語の構文を変えてまでDSLやらメタな事ができる

結論2：普通に書けメタプログラミングやっててPerlの事を悪く言っちゃ駄目メタプログラミングやっててPerlの事を悪く言っちゃ駄目
YOU ASKED FOR IT.

細かい所はPerlハッカー達にYAPCで聞いてね！

2011 10.13 ~ 10.15
http://yapcasia.org
please book your ﬂights!

ありがとうございました