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」というアトリビュートなら、コマンドラインオプションにならない。 ↩
