Perl App Engine状況報告、Protocol BufferのPerl対応 | エンタープライズ | マイコミジャーナル
Perl App Engineに関連したコードベースにはおもに次の3つがある。
http://journal.mycom.co.jp/news/2008/07/29/042/index.html
- Perl App Engine
Perl XS moduleSys::Protect- Protocol Buffers for Perl
protobuf-perl - Google Codeさっそく遊んでみました。
Protocol Buffers for Perl.
http://code.google.com/p/protobuf-perl/
まず、protobuf-perlはオリジナルの改造として作られており、スケルトンクラス生成ツール「protoc」をビルドする所からの導入となります。
通常はprotobufディレクトリで
# make -j2 protoc
とすれば出来上がります。ただVisual Studioの場合はlibprotocプロジェクトのソース一覧からperlのgeneratorソースである「perl_generator.cc」が外れてしまっているので、追加してからビルドする必要があります。出来上がれば、「libprotobuf.dll」と「libprotoc.dll」、「protoc.exe」をパスの通った位置にコピーします。
"main.cc"のソースを見て頂ければ分かりますが、protocol buffersのgeneratorはソースが分離されており、main実行時にプラグインを読み込む様な形で登録されています。
int main(int argc, char* argv[]) {
google::protobuf::compiler::CommandLineInterface cli;
// Proto2 C++
google::protobuf::compiler::cpp::CppGenerator cpp_generator;
cli.RegisterGenerator("--cpp_out", &cpp_generator,
"Generate C++ header and source.");
// Proto2 Java
google::protobuf::compiler::java::JavaGenerator java_generator;
cli.RegisterGenerator("--java_out", &java_generator,
"Generate Java source file.");
// Proto2 Python
google::protobuf::compiler::python::Generator py_generator;
cli.RegisterGenerator("--python_out", &py_generator,
"Generate Python source file.");
// Proto2 Perl
google::protobuf::compiler::perl::Generator perl_generator;
cli.RegisterGenerator("--perl_out", &perl_generator,
"Generate Perl source file.");
return cli.Run(argc, argv);
}
別の言語でgeneratorを作る場合、"XXX_generator.h"と"XXX_generator.cc"を作り、"main.cc"でincludeとRegisterGeneratorを実行すれば動き出す仕組みになっています。キレイな作りですね。さて出来上がった"protoc"でperlのラッパクラスを作ります。
先日ご紹介した際に使った"person.proto"を使います。ここで注意しなければならないのが、"--perl_out"オプションを使用する際の引数で指定するファイル名がパッケージ名として使われてしまう点です。
perlパッケージ名称がそれっぽくなる様に以下の様に実行します。
# protoc --perl_out=. Person.proto
UNIX系の方は"person.proto"から"Person.proto"にリネームしてから実行して下さい。Windowsならばそのまま実行出来ます。出来上がった"ProtoBuf::Person"は以下の様になりました。
## Boilerplate:
# Auto-generated code from the protocol buffer compiler. DO NOT EDIT!
use strict;
use warnings;
#use 5.6.1;
use Protobuf;
package ProtoBuf::Person;
use constant TRUE => 1;
use constant FALSE => 0;
## Top-level enums:
## Top-level extensions:
## All nested enums:
## Message descriptors:
our $_PERSON = Protobuf::Descriptor->new(
name => 'Person',
full_name => 'protocol.Person',
containing_type => undef,
fields => [
Protobuf::FieldDescriptor->new(
name => 'name', index => 0, number => 1,
type => 9, cpp_type => 9, label => 2,
default_value => "",
message_type => undef, enum_type => undef, containing_type => undef,
is_extension => FALSE, extension_scope => undef),
Protobuf::FieldDescriptor->new(
name => 'age', index => 1, number => 2,
type => 5, cpp_type => 1, label => 2,
default_value => 0,
message_type => undef, enum_type => undef, containing_type => undef,
is_extension => FALSE, extension_scope => undef),
],
extensions => [
],
nested_types => [], # TODO(bradfitz): Implement.
enum_types => [
],
options => Protobuf::MessageOptions->new(
),
);
## Imports:
## Fix foreign fields:
## Messages:
Protobuf::Message->GenerateClass(__PACKAGE__ . '::Person', $_PERSON);
## Fix foreign fields in extensions:
## Services:
実装はMooseを使っており、アクセサに対する制御も行っています。次にサンプルコード
use strict;
use warnings;
no warnings qw(deprecated);
use Protobuf::Decoder;
use ProtoBuf::Person;
my $person = ProtoBuf::Person::Person->new;
$person->set_name('mattn');
$person->set_age(18);
open my $out, '>', 'person_perl.txt';
print $out $person->serialize_to_string();
close $out;
my $other = ProtoBuf::Person::Person->new;
open my $in, '<', 'person_perl.txt';
$other->parse_from_string( do { local $/;<$in> } );
close $in;
printf "name:%s\nage:%d\n", $other->name(), $other->age();
前回と同様にファイルに書き出し、ファイルから読み込んでparse_from_stringで実体化します。結果は前回と同様です。cppは別として、pythonの場合はpickleが、javaの場合はSerializableがあり、Google Protocol Buffersの使い所が難しい気もしましたが、色々な言語がサポートされてくると言語をまたいだデータ共有という形で使えそうな気がして来ました。特にmemcachedを使ったダイナミックインスタンスエクスポートとか面白いかもしれませんね。
またperl版がMooseと絡んでいる所がとても通ぽくて良いですね。:-)
どうせなら、PerlIOでシリアライズ出来たらな...と思ってしまいましたが、もしかしたら今後サポートされるかもしれませんね。
他にもprotocol buffersはいろんな言語でインプリメンツされているので、皆さんもお好きな言語で遊んでみてはいかがでしょうか。