perl版もあったんですね。
Perl App Engine状況報告、Protocol BufferのPerl対応 | エンタープライズ | マイコミジャーナル
Perl App Engineに関連したコードベースにはおもに次の3つがある。
- Perl App Engine
Perl XS module Sys::Protect
- Protocol Buffers for Perl
http://journal.mycom.co.jp/news/2008/07/29/042/index.html
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;
google::protobuf::compiler::cpp::CppGenerator cpp_generator;
cli.RegisterGenerator("--cpp_out", &cpp_generator,
"Generate C++ header and source.");
google::protobuf::compiler::java::JavaGenerator java_generator;
cli.RegisterGenerator("--java_out", &java_generator,
"Generate Java source file.");
google::protobuf::compiler::python::Generator py_generator;
cli.RegisterGenerator("--python_out", &py_generator,
"Generate Python source file.");
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"は以下の様になりました。
use strict;
use warnings;
use Protobuf;
package ProtoBuf::Person;
use constant TRUE => 1;
use constant FALSE => 0;
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
enum_types => [
],
options => Protobuf::MessageOptions->new(
),
);
Protobuf::Message->GenerateClass(__PACKAGE__ . '::Person', $_PERSON);
実装は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は
いろんな言語でインプリメンツされているので、皆さんもお好きな言語で遊んでみてはいかがでしょうか。