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 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
|
=encoding utf-8
=head1 NAME
Getopt::EX::Hashed - Getopt::Long のためのハッシュオブジェクト自動化
=head1 VERSION
Version 1.0602
=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<--number> を定義し、C<-n> としても使えるようにするには、次のようにします。
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
オプション spec が不要な場合は、空文字列(または空白のみの文字列)を値として与えてください。spec 文字列がなければ、そのメンバーはオプションとして扱われません。
=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<ACCESSOR_LVALUE> パラメータを 0 に設定してください。アクセサは C<new> の時点で生成されるため、この値はすべてのメンバーに対して有効です。
=item B<default> => I<value> | I<coderef>
デフォルト値を設定します。デフォルトが与えられない場合、メンバーは C<undef> として初期化されます。
値が ARRAY または HASH へのリファレンスである場合、各 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>/ | I<coderef>
有効な文字列パラメータのリストを設定します。各項目は文字列、正規表現リファレンス、またはコードリファレンスにできます。引数が、与えられたリストのいずれかの項目と同一、または一致する場合に有効です。値が arrayref でない場合は、単一項目のリスト(通常は regexpref か coderef)として扱われます。
以下の宣言はほぼ同等ですが、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>
新しいハッシュオブジェクトを作成するクラスメソッド。すべてのメンバーをデフォルト値で初期化し、設定に従ってアクセサメソッドを作成します。bless されたハッシュリファレンスを返します。LOCK_KEYS が有効な場合、ハッシュキーはロックされます。
=head2 B<optspec>
C<GetOptions> 関数に渡すことができるオプション仕様のリストを返します。
GetOptions($obj->optspec)
C<GetOptions> は、最初の引数としてハッシュリファレンスを与えることで値をハッシュに格納する機能を持ちますが、必須ではありません。
=head2 B<getopt> [ I<arrayref> ]
オプションを処理するために、呼び出し元のコンテキストで定義された適切な関数を呼び出します。
$obj->getopt
$obj->getopt(\@argv);
上記の例は、以下のコードに対するショートカットです。
GetOptions($obj->optspec)
GetOptionsFromArray(\@argv, $obj->optspec)
=head2 B<use_keys> I<keys>
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)
真の場合、読み書きアクセサに lvalue 属性が付きます。その挙動が好みでない場合は 0 に設定してください。
=item B<DEFAULT>
デフォルトパラメータを設定します。C<has> が呼ばれると、DEFAULT パラメータは明示的なパラメータの前に挿入されます。両方に同じパラメータがある場合は、明示的なものが優先されます。C<+> を用いる増分呼び出しには影響しません。
DEFAULT の典型的な使い方は、以降のすべてのハッシュエントリに対するアクセサメソッドを用意するための C<is> です。リセットするには C<< DEFAULT => [] >> を宣言してください。
Getopt::EX::Hashed->configure(DEFAULT => [ is => 'ro' ]);
=begin comment
=item B<INVALID_MSG> (default: built-in error message generator)
検証失敗時のエラーメッセージを生成するコードリファレンスを設定します。コードリファレンスはオプションハンドラと同じ引数を受け取ります($_[0] はオプション名、単純なオプションでは $_[1] が値、ハッシュオプションでは $_[1] と $_[2])。デフォルトの関数は「--option=value: option validation error」のようなメッセージを生成します。
Getopt::EX::Hashed->configure(
INVALID_MSG => sub {
my $opt = shift;
"Invalid value for --$opt: @_\n";
}
);
=end comment
=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-2025 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
|