MooseX::Getopt
を使ってCUIアプリを作るとき、ロールに含まれるアトリビュートがコマンドラインオプションと化してしまうので困っていた。例えばこんな感じ。
ソースその1
#!/usr/bin/perl { package MyApp::Role; use Moose::Role; has attr1 => ( is => "ro", default => 5 ); 1; } { package MyApp::CUI; use Moose; with qw! MyApp::Role MooseX::Getopt !; has opt1 => ( is => "ro", required => 1 ); sub run { my $self = shift; print "attr1 => " . $self->attr1 . "\n"; print "opt1 => " . $self->opt1 . "\n"; } __PACKAGE__->meta->make_immutable; } MyApp::CUI->new_with_options->run;
実行結果
$ perl test.pl Required option missing: opt1 usage: test.pl [long options...] --opt1 --attr1
オプションにしたいのはopt1
だけで、attr1
はユーザーに見せたくない。一応、こういう時のために使うメタクラスが用意されている1。
ソースその2
#!/usr/bin/perl { package MyApp::Role; use Moose::Role; with "MooseX::Getopt"; has attr1 => ( metaclass => "NoGetopt", is => "ro", default => 5 ); 1; } { package MyApp::CUI; use Moose; with qw! MyApp::Role MooseX::Getopt !; has opt1 => ( is => "ro", required => 1 ); sub run { my $self = shift; print "attr1 => " . $self->attr1 . "\n"; print "opt1 => " . $self->opt1 . "\n"; } __PACKAGE__->meta->make_immutable; } MyApp::CUI->new_with_options->run;
実行結果
$ perl test.pl Required option missing: opt1 usage: test.pl [long options...] --opt1
attr1
は見えなくなった。でも、MyApp::Role
をCUIアプリ以外から利用する時を考えたらどうだろう? 必要もないのにMooseX::Getopt
をwithしているのは無駄だ。attr1
アトリビュートはCUIアプリで使うときだけ「NoGetopt
」になってくれればいいのだ。
アトリビュートに「+」する
で、やっと本題。これをスマートに解決してくれる方法があった。あったというか、単に僕が勉強不足だっただけなのだが。
has "+$attribute_name" => %option;継承したスーパークラスや消費したロールに存在するアトリビュートの設定を拡張します。
http://perl-mongers.org/2010/02/the-fastest-way-to-mastering-moose-and-mouse.html
ソースその3
#!/usr/bin/perl { package MyApp::Role; use Moose::Role; has attr1 => ( is => "ro", default => 5 ); 1; } { package MyApp::CUI; use Moose; with qw! MyApp::Role MooseX::Getopt !; has opt1 => ( is => "ro", required => 1 ); has "+attr1" => ( metaclass => "NoGetopt" ); sub run { my $self = shift; print "attr1 => " . $self->attr1 . "\n"; print "opt1 => " . $self->opt1 . "\n"; } __PACKAGE__->meta->make_immutable; } MyApp::CUI->new_with_options->run;
実行結果
$ perl test.pl --attr1 a Unknown option: attr1 usage: test.pl [long options...] --opt1
このように、MyApp::Role
を利用するアプリケーション(MyApp::CUI
)の中で、コマンドラインオプションにしたくないアトリビュートを指定している。こっちの方がずっとスマートだね。
-
他に、アトリビュートの名称に「_」を付けるという手もある。今回の例で言えば、「
_attr1
」というアトリビュートなら、コマンドラインオプションにならない。 ↩