Perlベストプラクティス/Damian Conway_
8章 組み込み関数:
組み込み関数を使いましょう。自分で作成したコードよりも高速できちんとデバックされている可能性が高い。
8.1 ソート:
ソート中にキーを再計算しない。(SHA-512等)
Perl5.8以降のsortのアルゴリズムはマージソート。計算オーダーはO(N log N)。
Orcishマニューバー。計算した結果がハッシュに有ればそれを使い、無ければ||=のor代入で計算してハッシュに入れる。
Perl5.8以降のsortのアルゴリズムはマージソート。計算オーダーはO(N log N)。
Orcishマニューバー。計算した結果がハッシュに有ればそれを使い、無ければ||=のor代入で計算してハッシュに入れる。
my %sha512_of;
@sorted_scripts
= sort { ($sha512_of{$a} ||= sha512($a))
cmp
($sha512_of{$b} ||= sha512($b))
}
@scripts;
Schwartzian変換。(シュワルツ変換)
@sorted_scripts
= map { $_->[0] }
sort { $a->[1] cmp $b->[1] }
map { [$_, sha512($_)] }
@scripts;
cmpと<=>の違い。Plagger/lib/Plagger/Feed.pm sort_entriesの例。一部整形。($self->entries->dateの数値でソートして、entriesを入れ替えている。降順)
my @entries = map { $_->[1] }
sort { $b->[0] <=> $a->[0] }
map { [ $_->date, $_ ] } $self->entries;
$self->{entries} = \@entries;
use Memoizeを使ってサブルーチンの返り値を覚えておく
use Digest::SHA qw( sha512 );
use Memoize;
memoize('sha512');
@sorted_scripts = sort { sha512($a) cmp sha512($b) } @scripts;
どれも一長一短なので、実際のリストでベンチマークを取って決める。
8.2 リストの反転:
reverseを使ってリストを反転する。降順sortが欲しい時は昇順sortをreverseする。
reverse sortは最適化されている。
reverse sortは最適化されている。
8.3 スカラーの反転:
reverseを使ってスカラーを反転する。スカラーコンテキストを明確にするためscalar指定子を付ける。
add_email_addr(scalar reverse $email_address);
8.4 固定幅のデータ:
固定幅のデータを抜き出すにはunpackを使う。substrや正規表現はunpackより重い。
'A6 A10 A8'で6文字、10文字、8文字を取得する。
'@0 A6 @8 A10 @20 A8'で列0から6文字、列8から10文字、列20から8文字。
@の値は昇順じゃなくてもいい。
'A6 A10 A8'で6文字、10文字、8文字を取得する。
'@0 A6 @8 A10 @20 A8'で列0から6文字、列8から10文字、列20から8文字。
@の値は昇順じゃなくてもいい。
8.5 分離されたデータ:
可変幅のデータを抜き出すにはsplitを使う。
第1引数はセパレータ指定。第2引数は文字列。第3引数はフィールドの最大値。
第3引数は必要なフィールド数+1。できるだけ明示的に指定した方が良い。
第1引数はセパレータ指定。第2引数は文字列。第3引数はフィールドの最大値。
第3引数は必要なフィールド数+1。できるだけ明示的に指定した方が良い。
8.6 可変幅のデータ:
可変幅の複雑なデータはText::CSV_XSを使う。
use Text::CSV::Simple;
use Text::CSV::Simple;
8.7 文字列の評価:
文字列形式のevalは使わない。
eval qq{ sub $subname {...} };で変数名サブルーチンを作るぐらいなら、匿名サブルーチンとSub::Installerを使う。
eval qq{ sub $subname {...} };で変数名サブルーチンを作るぐらいなら、匿名サブルーチンとSub::Installerを使う。
8.8 ソートの自動化:
Sort::Makerでソートルーチン構築を検討する。
8.9 部分文字列:
lvalueのsubstrではなく引数4つのsubstrを使う。
substr($addr, $country_pos, $COUNTRY_LEN)
= $country_name($country_code); # 重い!
ではなく
substr $addr, $country_pos, $COUNTRY_LEN, $country_name($country_code); # okにする。代入よりも引数4つのsubstrのほうが高速。
8.10 ハッシュ値:
lvalue方式のvaluesを利用する。
forループでvaluesを使うとエイリアスのリストが返るので、ループ中で代入できる(lvalueにできる)
forループでvaluesを使うとエイリアスのリストが返るので、ループ中で代入できる(lvalueにできる)
8.11 グロブ:
<...>ではなくglobを使う。
入力演算だけで<>を使う。
入力演算だけで<>を使う。
my @files = glob($FILE_PATTERN);
8.12 スリープ:
sleepは整数しか有効ではない。秒単位。Time::HiResを使う。
select undef, undef, undef, 0.5;のhackは使わない。
select undef, undef, undef, 0.5;のhackは使わない。
8.13 mapとgrep:
mapとgrepの第1引数に式を使わない。いつもブロックをつかう。
8.14 ユーティリティ:
標準ライブラリの関数を使う。
Scalar::Util, List::Util, List::MoreUtilsの関数を使う。
Scalar::Util
Scalar::Util, List::Util, List::MoreUtilsの関数を使う。
Scalar::Util
- blessed $scalar
- refaddr $scalar
- reftype $scalar
- readonly $scalar
- tainted $scalar
- openhandle $scalar
- weaken $scalar
- is_weak $scalar
- looks_like_number $scalar
- first {<条件>} @list
- max @list
- maxstr @list
- min @list
- minstr @list
- shuffle @list
- sum @list
- reduce {<$a $bの2項演算>} @list
- all {<条件>} @list (any(), notall(), none()もある)
- first_index {<条件>} @list (last_index()もある)
- apply {<変換>} @list (リストのコピーに変換をかけて新しいリストを返す)
- pairwise {<$a $bの2項演算>} @array1, @array2
- zip @array1, @array2, ...
- uniq @list
9.1 呼び出し構文:
サブルーチン呼び出しではカッコを使う。先頭に&を付けない。
(サブルーチンの参照は\&subnameを使う)
(サブルーチンの参照は\&subnameを使う)
9.2 同音異義語:
組込関数と同じ名前のサブルーチンはダメ。
9.3 引数リスト:
必ず最初に@_を展開する。サブルーチンは引数を@_配列で受け取る。
$_[0], $_[1]は使わない。
$_[0], $_[1]は使わない。
sub hoge {
my ($self, $context, $args) = @_;
#略
}
例外は、@_を1回だけすぐに処理するラッパーサブルーチン。
sub say {
return print @_, "\n";
}
#
say( 'Hello' );
9.4 名前付きの引数:
サブルーチン引数が3つ以上のときは名前付き引数のハッシュを使う。
9.5 欠けている引数:
引数があるかどうかチェックするときは、definedか!undef
引数をif !$argsで検証しない。
引数をif !$argsで検証しない。
9.6 引数のデフォルト値:
@_を展開したらデフォルト値を解決する。デフォルト値を他の文で追加しない。
my $cols = exists $args_ref->{cols} ? $args_ref->{cols} : $DEFAULT_WITDH;
9.7 スカラーコンテキストでの戻り値:
スカラーを戻す時はreturn scalarを使う。
9.8 コンテキストに応じた戻り値:
リストを返すサブルーチンがスカラーコンテキストで呼ばれた時は明白な値を返す。
(配列の数なのか文字列なのかは、Perl組み込み関数でも実はバラバラだったりする。できるだけ分かりやすく想像しやすいスカラーを返す)
(配列の数なのか文字列なのかは、Perl組み込み関数でも実はバラバラだったりする。できるだけ分かりやすく想像しやすいスカラーを返す)
9.9 マルチコンテキストでの戻り値:
スカラーコンテキストで明白な値をしぼれない時はContextual::Returnを検討する。
9.10 プロトタイプ:
サブルーチンプロトタイプは使わない。
9.11 暗黙的なリターン:
省略しないで明示的なreturnを使う。
9.12 失敗のリターン:
失敗状態を返すには裸のreturnを使う。return undefは使わない。
(例外を使う)
(例外を使う)
10.1 ファイルハンドル:
裸のワードをファイルハンドルに使わない。
10.2 間接的なファイルハンドル:
レキシカル変数をファイルハンドルにする。
open my $filehandle, '<', $filename
10.3 ファイルハンドルのローカル化:
パッケージスコープのファイルハンドルを使う場合はlocalする。
(基本的にパッケージスコープは使わない)
(基本的にパッケージスコープは使わない)
10.4 きちんと開く:
IO::Fileを使うか引数3つのopenを使う。
use IO::File;
my $active = IO::File->new($ACTIVE_LOG, '<')
or croak "Can't open '$ACTILE_LOG': $OS_ERROR";
open my $stdin, '<', '-' or croak "Can't open stdin: $OS_ERROR";
10.5 エラーチェック:
ファイルへのopen, close, printをするときは結果をチェックする。
10.6 クリーンアップ:
ファイルハンドルは出来るだけ速く明示的に閉じる。
open my $fh, '<', $config_file
or croak "Can't open '$config_file': $OS_ERROR";
my @lines = <$fh>; # 読み込んだらすぐ閉じる
close $fh
or croak "Can't close '$config_file' after reading: $OS_ERROR";
10.7 入力ループ:
for (<>)ではなくwhile (<>)を使う。
forはファイルを最後まで読み込んでからループする。whileは1行づつループする。
ただしfor my $n (2..1_000_000_000) {}のような大きな範囲のforループは、実行時評価に最適化されて、999999999個の整数のリストを生成しないので問題は出ない。
forはファイルを最後まで読み込んでからループする。whileは1行づつループする。
ただしfor my $n (2..1_000_000_000) {}のような大きな範囲のforループは、実行時評価に最適化されて、999999999個の整数のリストを生成しないので問題は出ない。
10.8 行ベースの入力:
ファイル全体を<>で読み込まず、1行ごとのI/Oを使う。
全体を読み込むのはスナップショットが必要な場合や、ファイルが不安定な時や、テキスト処理が複数行に渡る場合だけにする。
全体を読み込むのはスナップショットが必要な場合や、ファイルが不安定な時や、テキスト処理が複数行に渡る場合だけにする。
10.9 単純な丸呑み:
ファイルハンドルをdo{ }ブロックで囲む。
ファイル全体をどうしても一度に読み込む場合はFile::Slurp, sysread, do{ local $/; <$fh> };を使う。
ファイル全体をどうしても一度に読み込む場合はFile::Slurp, sysread, do{ local $/; <$fh> };を使う。
my $code = do { local $/; <$in> };
sysread $fh, $text, -s $fh;
10.10 強力な丸呑み:
Perl6::Slurpを使ってストリームを一気に読む。
use Perl6::Slurp; my $text = slurp $file_handle;
my @lines = slurp $file_name;
my @lines = slurp $file_name, {chomp => 1};
10.11 標準入力:
*STDINは使用しない。*ARGVを使う。(<>はデフォルトで<ARGV>になる)
10.12 ファイルハンドルへの出力:
printではファイルハンドルを中カッコ{ }で囲む。
print {$file} $name, $rank, $serial_num, "\n";
print {*STDERR} $name, $rank, $serial_num, "\n";
use IO::Handle $file->print( $name, $rank, $serial_num, "\n" ); *STDERR->print( $name, $rank, $serial_num, "\n" );
10.13 単純なプロンプト:
対話形式で入力するときはプロンプトを表示する。
10.14 対話性:
プロンプト周りはややこしいので自分で書かない。IO::Interactiveを使う。
10.15 強力なプロンプト:
プロンプト表示はIO::Promptを使う。
10.16 プログレスインジケータ:
待つ処理が続く時は進行状況を伝える。
print {*STDERR} 'Connecting to server...';
10.17 自動プログレスインジケータ:
Smart::Commentsモジュールで###に続けて書いたコメントが自動的に表示されるのを使う。
10.18 自動フラッシュ:
selectを使った自動フラッシュは使わない。
自動フラッシュはIO::Handleのautoflush()を使う。
自動フラッシュはIO::Handleのautoflush()を使う。
use IO::Handle; *STDOUT->autoflush();
11.1 逆参照:
可能な限り矢印->で逆参照する。
スライスの時は->は使えない。
${$list_ref}[0] # NG
ではなく
$list_ref->[0] # Okにする。
スライスの時は->は使えない。
@{$list_ref}[0, -1]; # ok
矢印を使うと[ ... ]がスカラーコンテキストになり最後のインデックスだけになる。
$list_ref->[0, -1]; # same ($list_ref->[-1], undef);
11.2 中かっこで囲まれた参照:
基本的に参照は中カッコ{ }で囲む。
11.3 シンボリック参照:
シンボリック参照は決して使わない。
(myによるレキシカル変数を使ってパッケージ変数は基本的に使わないので、シンボリック参照も使う必要がない)
(myによるレキシカル変数を使ってパッケージ変数は基本的に使わないので、シンボリック参照も使う必要がない)
11.4 循環参照:
weakenを使って循環データ構造からくるメモリリークを回避する。
use Scalar::Util qw( weaken );
12章 正規表現:
正規表現はPerlとは別のもう一つの言語だと思え。
12.1 拡張フォーマット:
いつも/xフラグを使う。
/xフラグが有効だと、正規表現でスペースや改行やインデントによる整形が使えるようになる。#コメントも使える。
/xフラグが有効だと、正規表現でスペースや改行やインデントによる整形が使えるようになる。#コメントも使える。
12.2 行の境界:
いつも/mフラグを使う。
12.3 文字列の境界:
文字列の境界アンカーとして\Aと\zを使う。
「文字列の先頭」には\Aを使う。/mフラグで^を使わない。「文字列の末尾」には\zを使う。/mフラグで$を使わない。
「文字列の先頭」には\Aを使う。/mフラグで^を使わない。「文字列の末尾」には\zを使う。/mフラグで$を使わない。
12.4 文字列の末尾:
「文字列の末尾」には\Zでは無く\zを使う。
\Zのかわりに\n?\z。
\Zのかわりに\n?\z。
12.5 任意の文字とのマッチ:
いつも/sフラグを使う。
/sフラグを使えばドット(.)は改行を含むすべての文字とマッチする。
「改行以外の文字とマッチ」は[^\n]を使う。
/sフラグを使えばドット(.)は改行を含むすべての文字とマッチする。
「改行以外の文字とマッチ」は[^\n]を使う。
12.6 遅延フラグ:
Regexp::Autoflagsの義務化を検討する
12.7 中かっこのデリミタ:
正規表現が複数行になるときは/.../ではなくm{...}を使う。
12.8 その他のデリミタ:
/.../かm{...}以外のデリミタをいっさい使わない。
12.9 メタ文字:
エスケープされたメタ文字ではなく単数文字クラスを使う。
m/ \{ . \. \d{2} \} /xms; # NG
m/ [{] . [.] \d{2} [}] /xms; # Ok
12.10 名前付き文字:
エスケープされたメタ文字ではなく名前付き文字を使う。
use charnames qw( :full );
use charnames qw( :full );
12.11 プロパティ:
[a-zA-Z]などではなく\p{Alphabetic}などのプロパティを使う。
perldoc perlunicode
perldoc perlunicode
12.12 ホワイトスペース:
特定の空白ではなく任意の空白をマッチさせる。
空白が要求される場所では\s+
空白を使用出来る場所では\s*
空白が要求される場所では\s+
空白を使用出来る場所では\s*
12.13 制約なしの繰り返し:
出来るだけ多くマッチするときは具体的に書く。
(.*)&よりも(.*?)&
(.*)&よりも([^&]*)
(.*)&よりも(.*?)&
(.*)&よりも([^&]*)
12.14 捕捉のためのかっこ:
カッコ( )はキャプチャーのためだけに使う。
選択のためのカッコは(?: )を使ってキャプチャーしない。
選択のためのカッコは(?: )を使ってキャプチャーしない。
12.15 捕捉された値:
キャプチャーが成功して$1や$2に値が入ったかどうかはdefined $1を判定しない。
$1などには他の場所でキャプチャーされた値が入っているかもしれない。
$1などには他の場所でキャプチャーされた値が入っているかもしれない。
$full_name =~ m/\A (Mrs?|Ms|Dr) \s+ (\S+) \s+ (\S+) \z/xms;
if (defined $1) { # NG!
($title, $first_name, $last_name) = ($1, $2, $3);
}
こうじゃなくて
if ($full_name =~ m/\A (Mrs?|Ms|Dr) \s+ (\S+) \s+ (\S+) \z/xms) {
($title, $first_name, $last_name) = ($1, $2, $3); # Ok
}
こうする
12.16 捕捉変数:
キャプチャーしたらすぐに適切な名前の変数に代入する。
my ($opt_name, $operator, $opt_val, $comment)
= $config =~ m/ \A (\S+) \s* (=|[+]=) \s* ([^;]+) ; \s* \# (.*)/xms;
12.17 トークンごとのパターンマッチ:
/gcフラグでトークンに分解する。
\Gで「前回のパターンマッチの終わり」
\Gで「前回のパターンマッチの終わり」
12.18 表形式の正規表現:
配列から正規表現をjoin '|', map {quotemeta $_} reverse sort @_;で生成する
12.19 正規表現の生成:
複雑な正規表現は単純な要素に分解して定数に入れる
12.20 既製の正規表現:
Regexp::Commonを使う
12.21 選択肢:
一文字の選択(a|b|c)のかわりに文字クラス([abc])を使う
12.22 選択肢のリファクタリング:
前後の共通部分をまとめる
12.23 バックトラック:
バックトラックしない場所は(?>...)をつかう。
my $str = '(foo,bar,baz,hoge,fuga)';
$str =~ m{ [(] $ITEM (?> (?:,$ITEM)* ) [)] }xms;
12.24 文字列比較:
1つの正規表現マッチよりも個別にeqでマッチさせるほうが高速。
大文字と小文字を区別しないためだけに/iフラグ正規表現を使うよりも、lc()を使う方が高速。
大文字と小文字を区別しないためだけに/iフラグ正規表現を使うよりも、lc()を使う方が高速。
13.1 例外:
失敗の時は、特別な値をreturnしたりフラグを使ったりしないで例外を出す
13.2 組み込み関数のエラー:
組み込み関数の失敗でも例外を出す。
Fatalモジュールを使う。
Fatalモジュールを使う。
use Fatal qw( open close );
13.3 コンテキストに応じたエラー:
全てのコンテキストでエラーの例外だす。
Fatalで:voidマーカーは使わない。
Fatalで:voidマーカーは使わない。
13.4 システムエラー:
system関数は成功するとfalse、失敗するとtrueを返すので注意する。
systemを出来るだけ使わずにモジュールを使う。
Perl6::Builtines qw( system )を使う。
systemを出来るだけ使わずにモジュールを使う。
Perl6::Builtines qw( system )を使う。
13.5 回復可能なエラー:
回復可能のエラーを含む全てのエラーで例外を出す。
13.6 エラーの報告:
いつもcroak()を使う。
13.7 エラーメッセージ:
エラー文は受け手が理解出来るように書く。
13.8 エラーの文書化:
13.9 オブジェクト指向例外:
データをハンドラに伝える時は例外オブジェクトを使う。
13.10 揮発性のエラーメッセージ:
エラー文が変化する可能性がある時は例外オブジェクトを使う。
13.11 例外階層:
例外処理が複数の場所にある場合は例外オブジェクトを使う。
13.12 例外処理:
例外オブジェクトは派生先から評価する。
13.13 例外クラス:
例外オブジェクトを自動的に作る。CPANのException::Classを使う。
13.14 例外の展開:
例外変数はレキシカル変数にコピーする。
my $exception = $EVAL_ERRORException::Classのcaught()は$EVAL_ERRORを返すのでそれを代入してもよい。
14.1 コマンドラインの構造:
一貫性のあるコマンドラインオプションと引数を使う。
14.2 コマンドラインの規則:
標準の規則に従う。
14.3 メタオプション:
--helpなどを標準化する。
14.4 上書き処理を指定する引数:
入力と出力に同じファイル名を指定出来るようにする。
「unlink 出力ファイル名」の後に出力ファイルをopenする。
IO::InSituモジュールを使う。
「unlink 出力ファイル名」の後に出力ファイルをopenする。
IO::InSituモジュールを使う。
14.5 コマンドラインの処理:
Getopt::Longを使う。
CPANのGetopt::Cladeを使う。
CPANのGetopt::Cladeを使う。
14.6 インターフェイスの一貫性:
インターフェース、ランタイムメッセージ、ドキュメントの一貫性を保つ。
Getopt::Euclidの=for Euclidを使う。
Getopt::Euclidの=for Euclidを使う。
14.7 プログラム間の一貫性:
コマンドライン処理の共通機能はモジュールにする。
15.1 オブジェクト指向の使用:
オブジェクト指向はデフォルトではなく選択肢にする。
15.2 判断基準:
15.3 擬似ハッシュ:
擬似ハッシュは使用しない。
15.4 制限付きハッシュ:
制限付きハッシュは使用しない。
15.5 カプセル化:
ハッシュベースのオブジェクトではなく匿名スカラーでインサイドアウトオブジェクトを使う。
(Class::Accessor::Fastを使ってアクセサを作るのも有りか)
(Class::Accessor::Fastを使ってアクセサを作るのも有りか)
15.6 コンストラクタ:
すべてのクラスのコンストラクタの名前はnew()にする。
15.7 クローン化:
コンストラクタでオブジェクトを複製しない。
複製が必要ならclone()メソッドを実装する。
複製が必要ならclone()メソッドを実装する。
15.8 デストラクタ:
いつもデストラクタを定義する。
sub DESTROYでdeleteする。
sub DESTROYでdeleteする。
15.9 メソッド:
メソッドはサブルーチンと同じガイドラインに従う。
メソッドの方がパラメータが少ない傾向が有る。
サブルーチンと違い、メソッドには組み込み関数と同じ名前を付けても良い。(組み込み関数と同じような機能のときに違う名前を付けると、類推が難しくなる)
メソッドの方がパラメータが少ない傾向が有る。
サブルーチンと違い、メソッドには組み込み関数と同じ名前を付けても良い。(組み込み関数と同じような機能のときに違う名前を付けると、類推が難しくなる)
15.10 アクセサ:
読み取りと書き込みのアクセサを別々に用意する。
get_とset_を使う。
(Class::Accessor::Fastを使うのがいいんじゃないか?)
get_とset_を使う。
(Class::Accessor::Fastを使うのがいいんじゃないか?)
15.11 lvalueアクセサ:
lvalueアクセサは使用しない。
15.12 間接的なオブジェクト:
間接的なオブジェクト構文は使わない。
new ObjectではなくObject->new()を使う。
new ObjectではなくObject->new()を使う。
15.13 クラスのインターフェイス:
最小限でなく最適なインターフェースを提供する。
15.14 演算子のオーバーロード:
演算子のオーバーロードは代数表記と同じ形のものだけにする。
15.15 型の強制変換:
オブジェクトをブール、数値、文字列に型変換するオーバーロードを検討する。
16.1 継承:
use baseを使う
16.2 オブジェクト:
インサイドアウトオブジェクトを使う。
16.3 オブジェクトのブレス化:
引数1つのblessを使用しない。
16.4 コンストラクタの引数:
コンストラクタの引数にはハッシュ参照を使う。ラベル付きの値を渡す。
sub new {
my ($class, $arg_ref) = @_;
my $new_object = bless anon_scalar(), $class;
$client_num_of(ident $new_object) = $arg_ref->{client_num};
$name_of(ident $new_object) = $arg_ref->{client_name};
return $new_object;
}
16.5 基底クラスの初期化:
ハッシュのハッシュを渡して、ベースクラスの引数をクラス名で指定する。
Class::Std::Utils
Class::Std::Utils
16.6 オブジェクトの生成と破棄:
生成、初期化、破棄のプロセスを分離する。
16.7 クラス階層の自動生成:
Class::Stdを使う。
16.8 属性の破棄:
デストラクタでClass::Stdで:ATTRを使う。
16.9 属性の構築:
初期化にClass::Stdの:ATTR( init_args => 'hoge' );を使う。
16.10 強制的な型変換:
強制的な型変換はClass::Stdの:STRINGIFY、:NUMERIFY、:BOOLIFYメソッドとして指定する。
16.11 累積メソッド:
SUPER::呼び出しのかわりにClass::Stdの:CUMULATIVEメソッドを使う。
16.12 自動的なロード:
AUTOLOAD()を使わない。
Class::StdのAUTOMETHOD()を検討する。
Class::StdのAUTOMETHOD()を検討する。
17.1 インターフェイス:
モジュールのインターフェースを最初に設計する。
17.2 リファクタリング:
重複するコードはサブルーチンにする。重複するサブルーチンはモジュールにする。
17.3 バージョン番号:
v1.0.3のvstringを使ってはダメ。
versionモジュールとqv(...)コンストラクタを使う。
versionモジュールとqv(...)コンストラクタを使う。
use version; our $VERSION = qv('1.0.3');
17.4 バージョン要件:
「このバージョン以上じゃないと動作しない」という指定を書く。
use 5.006001;やuse only q( 5.6.1- !5.8.0 );を使う。
use 5.006001;やuse only q( 5.6.1- !5.8.0 );を使う。
17.5 エクスポート:
エクスポートは慎重に。必要な場合にだけ使う。
@EXPORTと@EXPORT_OKで分ける。
@EXPORTと@EXPORT_OKで分ける。
17.6 宣言によるエクスポート:
宣言的なエクスポートを検討する。Perl6::Export::Attrsモジュールを使う。
17.7 インターフェイス変数:
モジュールのインターフェースの一部としてパッケージ変数を使わない。
17.8 モジュールの作成:
新しいモジュールを作る時はCPANのModule::Starterで自動生成を使う。
Module::Starter::PBPも使う。
Module::Starter::PBPも使う。
17.9 標準ライブラリ:
自分でコードを1から書かずに、可能な限り標準ライブラリを使う。
perldoc perlmodlib
perldoc perlmodlib
17.10 CPAN:
CPANモジュールを使用する。
18.1 テストケース:
最初にテストケースを作る。
コード本体を書く前にテストコードを書く。
コード本体を書く前にテストコードを書く。
18.2 モジュール型のテスト:
Test::Simple、Test::Moreを使ってテストを標準化する。
(今どきだったらTest::Baseか?)
(今どきだったらTest::Baseか?)
18.3 テストスイート:
Test::Harnessを使ってテストスイートを標準化する。
proveコマンドが使える。
proveコマンドが使える。
18.4 失敗:
失敗するテストスイートを作る。
18.5 何をテストするか:
起こりそうな事と、起こらなそうな事を両方テストする。
不正な動作を検出するのにふさわしい場所。
不正な動作を検出するのにふさわしい場所。
- 有効範囲の最大値と最小値
- 最小値よりも少し小さい値と、最大値よりも少し大きい値
- 負数値、正数値、0
- 非常に小さい負数値、正数値
- 空の文字列と複数行の文字列
- "\0"などの制御文字が含まれた文字列
- ASCII以外の文字列(Latin-1、Unicode)
- undefとundefのリスト
- '0', '0E0', '0.0', '0 but true'
- 空のリスト、空の配列、空のハッシュ
- 重複する値が含まれたリスト
- 決して入力される事の無い入力値
- 必ず利用出来るはずのリソースとのやりとり
- 数値が期待される場所への数値でない入力、数値が期待されない場所への数値の入力
- 参照が期待される場所への非参照値。参照が期待されない場所への参照値
- サブルーチン、メソッドへの引数の不足
- サブルーチン、メソッドへの余分な引数
- 順序がバラバラと位置指定の引数
- 不正なラベルが付いたキーと値の引数
- モジュールの不適切なバージョンのロード
- これまで遭遇したことのあるすべてのバグ
18.6 デバッグとテスト:
デバッグの前に新しいテストケースを追加する。
18.7 制約:
いつもuse strictを使う。
18.8 警告:
いつも警告を明示的に表示する。
use warningsを使う。
use warningsを使う。
18.9 正確さ:
use strictとuse warningsを使っていて警告が出なくても、正確であると決めつけない。
18.10 制約の無効化:
no strict 'refs'などを使う時は最も狭いスコープで使う。
18.11 デバッガ:
perlデバッガを習得する。
18.12 手動でのデバッグ:
手動でのデバッグはシリアライズされた出力をwarnする。
use Data::Dumper qw( Dumper ); warn Dumper ($results);
18.13 半自動デバッグ:
warnではなくSmart::Commentsの###も検討する。



コメントを読む(2) [ コメントする ]