2010年8月30日月曜日

Perl best practices[Perlベストプラクティス] 2章 コードのレイアウト


このエントリーをはてなブックマークに追加


自分用なので、
自分が普段からすでに習慣にしていることは記述しない。


if,forなどの制御キーワードとサブルーチン呼び出し、変数名を区別し易くする



制御キーワードの後と、{ の前はスペースを入れる。
while[一つスペース](....)[ひとつスペース]{
}


サブルーチン呼び出しや、変数は後続の括弧との間にスペースを入れない。
ただし、配列のインデックスが定数かスカラー変数以外のときは、インデックス式とそれを囲む括弧との間にスペースを入れる。



my @candidates = get_candidates($marker);

CANDIDATE:
for my $i (0..$#candidates) {
next CANDIDATE if open_region($i);

$candidate[$i]
= $incumbent{ $candidates[$i]{region} }; #<-インデックスはスペース有り
}





組み込み関数とサブルーチンを区別し易くする


組み込み関数は優先度を指定する必要がない場合は、括弧を使わないことで、サブルーチンと見分ける。
括弧を使用する場合は、サブルーチンと同じく、括弧との間にスペースを入れない。
○ split("\t", $record);
× split ("\t", $record);

また、事実上、組み込み関数と呼べる名誉組み込み関数にもこのルールを適用する。
例えば、carp,croak(Carp標準モジュール)、first,max(List::Util標準モジュール)、prompt(IO::Prompt)が挙げられる。


リストには必ず、コンマを入れる。


順序を入れ替えた際にバグになるから。



my @dwarves = (
'Happy' ,
'Sleepy' ,
'Dopey' , #<=ここ注意
);



行の長さ、インデント、タブ


古いディスプレイや印刷文書のことを考えて、行の長さは78文字。
emacsでの設定は、



(setq fill-column 78)
(setq auto-fill-mode t)



インデントの深さは、一長一短。4文字くらいにしておく。
タブとスペースを混ぜるのは良くないので、タブを押したら、スペース4文字になるように設定する。
emacsでの設定は、



(defalias 'perl-mode 'cperl-mode)

;; cperlモードでのスペース4つのインデント
'(cperl-close-paren-offset -4)
'(cperl-continued-statement-offset 4)
'(cperl-indent-level 4)
'(cperl-indent-parens-as-block t)
'(cperl-tab-always-indent t)



タブがコード上に存在しないのが望ましい。
文字リテラルでは、\tを使って指定する。


複数文を1行にまとめない。


当たり前のようだが、注意したいのがmapを使用する場合。



my @clean_words
= map { my $word = $_; $word =~ s/$EXPLETIVE/[DELETED]/gxms; $word }
@raw_word;




my @clean_words
= map {
my $word = $_;
$word =~ s/$EXPLETIVE/[DELETED]/gxms;
$word
} @raw_word;



コードを段落に分ける。


これは無意識にみんなやってる気がする。
コードとコードの間には一行分隙間を設ける。


'}'とelseを同列に並べない


コードが段落としてきっちり分かれるようにする。



if () {

}
else {

}



対の項目は縦に整列させる。



my @months = wq(
January February March
April May June
July August September
);

my %expansion_of = (
q{it's} => q{it is},
q{we're} => q{we are},
q{must've} => q{must have},
)

$name = standardize_name($name);
$age = time - $birth_date;
$status = 'active';

$indent{ name } = standardize_name($name);
$indent{ age } = time -$birth_date;
$indent{ status } = 'active';



長い分の分割


長い式は、演算子の前で分割する。
また、継続行は、単純なインデントではなく、それが属している式の1列目でインデントする。
pushの2つの引数が横方向で分離されているため、見やすいコードになる。
またセミコロンだけで1行使う。読み手の視線は各行の先頭にそって、下へ移動するため、
式がそこで完了することがはっきりわかる。



push @steps, $step[-1]
+ $radial_velocity * $elapsed_time
+ $orbital_velocity * ($phase + $phase_shift)
- $DRAG_COEFF * $altiude
;



優先度が低い演算子で式を分割


優先順位が低い演算子で改行することで、1行ごとの式を、優先度の高い式のグループとして見ることができる。



push @steps, $step[-1]
+ $radial_velocity * $elapsed_time
+ $orbital_velocity
* ($phase + $phase_shift) #<= 優先順位が低くない演算子で改行する場合はインデント
- $DRAG_COEFF * $altitude
;



長い代入式は、代入演算子の前で分割する



$predicted_val[$current_data_set]{$next_iteration} =
$average + $predicted_change * fudge_factor;


代入先の変数名が長いと、右端までみないと代入演算子がない。
代入演算子で改行することで、代入先と代入演算子が視覚的に近くにくる。



$predicted_val[$current_data_set]{$next_iteration}
= $average + $predicted_change * fudge_factor;


のようにする。
演算子で分割する場合は



$predivted_val[$current_data_set]{$next_iteration}
= ($minimum + $maximum) / 2
+ $predicted_change * max($fudge_factor, $local_epsilon);



3項演算子はテーブルっぽく列でフォーマットする



my $salute = $name eq $EMPTY_STR ? 'Customer'
;


if-else文と比べた際のメリットは、
1、代入文が1つですむこと。代入先変数の名前の確認が一ヶ所ですむ。
2、if文よりも厳格な構文。必ずelse文が必要とされる。
3、テーブルのように見える。?と:が列の境界線のように見える。


長いリストはコンマでくくる。



for my $item (@requested_items) {
push @items, (
"A brand new $item",
"A fully refurbished $item",
);
}


リストのコンマは演算子ではないため、演算子の直前で改行するルールを適用しないこと。


自動レイアウト


perltidyを用いて、レイアウトを変換することができる。
設定例は、P37参照





0 件のコメント:

コメントを投稿