1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
|
=encoding utf-8
=head1 NAME
Getopt::EX::Hashed - Getopt::Long 用ハッシュ格納オブジェクトの自動化
=head1 VERSION
Version 1.0601
=head1 SYNOPSIS
# script/foo
use App::foo;
App::foo->new->run();
# lib/App/foo.pm
package App::foo;
use Getopt::EX::Hashed; {
Getopt::EX::Hashed->configure( DEFAULT => [ is => 'rw' ] );
has start => ' =i s begin ' , default => 1;
has end => ' =i e ' ;
has file => ' =s@ f ' , any => qr/^(?!\.)/;
has score => ' =i ' , min => 0, max => 100;
has answer => ' =i ' , must => sub { $_[1] == 42 };
has mouse => ' =s ' , any => [ 'Frankie', 'Benjy' ];
has question => ' =s ' , any => qr/^(life|universe|everything)$/i;
} no Getopt::EX::Hashed;
sub run {
my $app = shift;
use Getopt::Long;
$app->getopt or pod2usage();
if ($app->answer == 42) {
$app->question //= 'life';
...
=cut
=head1 DESCRIPTION
B<Getopt::EX::Hashed>は、B<Getopt::Long>およびB<Getopt::EX::Long>を含む互換モジュールのコマンドラインオプション値を格納するハッシュオブジェクトを自動化するモジュールです。モジュール名は B<Getopt::EX> と同じですが、今のところ B<Getopt::EX> の他のモジュールとは独立して動作します。
このモジュールの主な目的は、初期化と仕様を一箇所に統合することです。また、シンプルな検証インターフェイスも提供します。
C<is>パラメータが与えられると、アクセサメソッドが自動的に生成されます。同じ関数がすでに定義されている場合、プログラムは致命的なエラーを引き起こします。アクセサはオブジェクトが破棄されると削除されます。複数のオブジェクトが同時に存在する場合、問題が発生する可能性があります。
=head1 FUNCTION
=head2 B<has>
オプション・パラメータを以下の形式で宣言します。括弧はわかりやすくするためのもので、省略してもよい。
has option_name => ( param => value, ... );
たとえば、整数値をパラメータとしてとり、C<-n>としても使えるオプションC<--number>を定義するには、次のようにします。
has number => spec => "=i n";
アクセサは最初の名前で作成されます。この例では、アクセサは C<< $app->number >> と定義されます。
配列参照が与えられている場合、一度に複数の名前を宣言することができます。
has [ 'left', 'right' ] => ( spec => "=i" );
名前がプラス(C<+>)で始まる場合、与えられたパラメータは既存の設定を更新します。
has '+left' => ( default => 1 );
C<spec>パラメータは、最初のパラメータであればラベルを省略できます。
has left => "=i", default => 1;
パラメータの数が偶数でない場合、デフォルトのラベルが先頭にあるとみなされます:最初のパラメータがコード参照であればC<action>、そうでなければC<spec>となります。
以下のパラメータが利用可能です。
=over 7
=item [ B<spec> => ] I<string>
オプション指定C<< spec => >> ラベルを省略できるのは、それが最初のパラメータである場合だけです。
I<string> では、オプションの仕様とエイリアスの名前は空白で区切られ、どのような順番でも表示できます。
C<--start>というオプションを持ち、その値として整数を取り、C<-s>とC<--begin>という名前でも使えるようにするには、次のように宣言します。
has start => "=i s begin";
上記の宣言は、次の文字列にコンパイルされます。
start|s|begin=i
にコンパイルされ、C<Getopt::Long>の定義に従います。もちろん、このように書くこともできます:
has start => "s|begin=i";
名前とエイリアスにアンダースコア(C<_>)が含まれている場合、アンダースコアの代わりにダッシュ(C<->)を使った別のエイリアスが定義されます。
has a_to_z => "=s";
上記の宣言は、次の文字列にコンパイルされます。
a_to_z|a-to-z=s
特に何もする必要がない場合は、空文字列(または空白のみ)を値として与えます。そうでない場合は、オプションとはみなされません。
=item B<alias> => I<string>
B<alias>パラメータで、追加のエイリアス名を指定することもできます。C<spec>パラメータのものと違いはありません。
has start => "=i", alias => "s begin";
=item B<is> => C<ro> | C<rw>
アクセサメソッドを生成するには、C<is>パラメータが必要です。読み込み専用ならC<ro>、読み書きならC<rw>を指定します。
読み書き可能なアクセサはlvalue属性を持っているので、それを代入することができます。このように使えます:
$app->foo //= 1;
これは、次のように書くよりずっと簡単です。
$app->foo(1) unless defined $app->foo;
以下のすべてのメンバにアクセッサを作りたい場合は、C<configure>でC<DEFAULT>パラメータを設定します。
Getopt::EX::Hashed->configure( DEFAULT => [ is => 'rw' ] );
C<configure>でC<DEFAULT>パラメータを設定します。アクセサはC<new>時に生成されるので、この値はすべてのメンバに有効です。
=item B<default> => I<value> | I<coderef>
デフォルト値を設定します。デフォルト値が指定されない場合、メンバはC<undef>として初期化されます。
値が ARRAY または HASH の参照の場合、同じメンバを持つ新しい参照が割り当てられます。つまり、メンバ・データは複数のC<new>呼び出しで共有されます。C<new>を複数回呼び出してメンバ・データを変更する場合は注意してください。
コード・リファレンスが与えられると、B<new>の実行時に呼び出され、デフォルト値が得られます。これは、宣言ではなく実行時に値を評価したい場合に有効です。デフォルトのアクションを定義したい場合は、B<action>パラメータを使用します。
SCALARへの参照が与えられた場合、オプション値はハッシュオブジェクトメンバではなく、参照が示すデータに格納されます。この場合、ハッシュ・メンバにアクセスしても期待値は得られません。
=item [ B<action> => ] I<coderef>
パラメータ C<action> は、オプションを処理するために呼び出されるコード参照をとます。C<<action =>> ラベルは、それが最初のパラメータである場合に限り、省略することができます。
呼び出されたとき、ハッシュオブジェクトは C<$_> として渡されます。
has [ qw(left right both) ] => '=i';
has "+both" => sub {
$_->{left} = $_->{right} = $_[1];
};
これを C<< "<>" に使用することができます。">>ですべてを捕らえることができます。その場合、specパラメータは重要ではなく、必須でもないです。
has ARGV => default => [];
has "<>" => sub {
push @{$_->{ARGV}}, $_[0];
};
=back
以下のパラメータはすべてデータ・バリデーションのためのものです。最初の C<must> は汎用バリデータで、何でも実装できます。その他は一般的なルールのショートカットです。
=over 7
=item B<must> => I<coderef> | [ I<coderef> ... ]
パラメータ C<must> は、オプション値を検証するためのコードリファレンスを受け取ります。C<action> と同じ引数をとり、真偽値を返します。次の例では、オプションB<--answer>は有効な値として42だけを取ります。
has answer => '=i',
must => sub { $_[1] == 42 };
複数のコード参照が与えられた場合、すべてのコードが真を返さなければなりません。
has answer => '=i',
must => [ sub { $_[1] >= 42 }, sub { $_[1] <= 42 } ];
=item B<min> => I<number>
=item B<max> => I<number>
引数の最小値と最大値を設定します。
=item B<any> => I<arrayref> | qr/I<regex>/
有効な文字列パラメータリストを設定します。各項目は文字列または正規表現参照です。引数は、指定されたリストのいずれかの項目と同じか一致する場合に有効です。値がarrayrefでない場合は、単一の項目リスト(通常は正規表現)とみなされます。
以下の宣言はほぼ等価ですが、2番目の宣言は大文字小文字を区別しません。
has question => '=s',
any => [ 'life', 'universe', 'everything' ];
has question => '=s',
any => qr/^(life|universe|everything)$/i;
オプションの引数を使用する場合は、リストにデフォルト値を含めることを忘れないでください。そうしないとバリデーション・エラーになります。
has question => ':s',
any => [ 'life', 'universe', 'everything', '' ];
=back
=head1 METHOD
=head2 B<new>
初期化されたハッシュオブジェクトを取得するクラスメソッド。
=head2 B<optspec>
C<GetOptions>関数に渡すことができるオプション指定リストを返します。
GetOptions($obj->optspec)
C<GetOptions>は、ハッシュ参照を第1引数に与えることで、ハッシュに値を格納する機能を持っていますが、これは必要ありません。
=head2 B<getopt> [ I<arrayref> ]
オプションを処理するために、呼び出し元のコンテキストで定義された適切な関数を呼び出します。
$obj->getopt
$obj->getopt(\@argv);
上記の例は、以下のコードのショートカットです。
GetOptions($obj->optspec)
GetOptionsFromArray(\@argv, $obj->optspec)
=head2 B<use_keys> I<keys>
ハッシュキーはC<Hash::Util::lock_keys>によって保護されているため、存在しないメンバにアクセスするとエラーになります。この関数を使用して、新しいメンバー・キーを宣言してから使用してください。
$obj->use_keys( qw(foo bar) );
任意のキーにアクセスしたい場合は、オブジェクトのロックを解除してください。
use Hash::Util 'unlock_keys';
unlock_keys %{$obj};
この動作はC<configure>のC<LOCK_KEYS>パラメータで変更できます。
=head2 B<configure> B<label> => I<value>, ...
オブジェクトを作成する前に、クラスメソッドC<< Getopt::EX::Hashed->configure() >>を使用します。C<new()>を呼び出すと、パッケージ固有の設定がオブジェクトにコピーされ、以降の操作に使用されます。オブジェクト固有の設定を更新するには、C<< $obj->configure() >> を使用します。
以下の構成パラメータがあります。
=over 7
=item B<LOCK_KEYS> (default: 1)
ハッシュ・キーをロックします。これは、存在しないハッシュ・エントリへの偶発的なアクセスを避けるためです。
=item B<REPLACE_UNDERSCORE> (default: 1)
アンダースコアをダッシュに置き換えたエイリアスを生成します。
=item B<REMOVE_UNDERSCORE> (default: 0)
アンダースコアを削除したエイリアスを生成します。
=item B<GETOPT> (default: 'GetOptions')
=item B<GETOPT_FROM_ARRAY> (default: 'GetOptionsFromArray')
C<getopt> メソッドから呼び出される関数名を設定します。
=item B<ACCESSOR_PREFIX> (default: '')
指定されると、メンバ名の前に付加されてアクセサ・メソッドとなります。C<ACCESSOR_PREFIX> が C<opt_> と定義されている場合、メンバ C<file> のアクセサは C<opt_file> になります。
=item B<ACCESSOR_LVALUE> (default: 1)
trueを指定すると、読み書き可能なアクセサはlvalue属性を持ちます。この振る舞いを好まない場合はゼロを設定してください。
=item B<DEFAULT>
デフォルト・パラメータを設定します。C<has>の呼び出しでは、DEFAULTパラメータが引数パラメータの前に挿入されます。そのため、同じパラメータが両方に含まれている場合は、引数リストで後の方が優先されます。C<+>によるインクリメンタルコールは影響を受けないです。
DEFAULTの典型的な使い方はC<is>で、以下のすべてのハッシュ・エントリーのアクセサ・メソッドを用意することです。C<< DEFAULT => [] >>を宣言してリセットします。
Getopt::EX::Hashed->configure(DEFAULT => [ is => 'ro' ]);
=back
=head2 B<reset>
クラスを元の状態にリセットします。
=head1 SEE ALSO
L<Getopt::Long>
L<Getopt::EX>, L<Getopt::EX::Long>
=head1 AUTHOR
Kazumasa Utashiro
=head1 COPYRIGHT
The following copyright notice applies to all the files provided in
this distribution, including binary files, unless explicitly noted
otherwise.
Copyright 2021-2024 Kazumasa Utashiro
=head1 LICENSE
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
|