
こんにちは、hachi8833です。
Rubyスタイルガイドを読む: ソースコードレイアウト(1)の続きです。今さらですが、スタイルガイドをただ読むよりも頭に入りますね。
1. ソースコードレイアウト(続)
!
の後ろにはスペースを置かない
No space after !.
他に何にも書いていませんが、これはRubyの単独の否定演算子!
ですね。以下は該当しないと考えることにします。
!=
などの記号の組み合わせによる演算子- 破壊的メソッド名末尾に付ける習慣になっている
!
(例: String#gsub!)
# 不可
! something
# 良好
!something
範囲演算子..
や...
の前後にはスペースを置かない
No space inside range literals.
私の感覚でも、範囲演算子の前後にスペースがあると意味が弱まってしまうように思えます。
# 不可
1 .. 3
'a' ... 'z'
# 良好
1..3
'a'...'z'
case
文内部のwhen
のインデントの深さはcase
と同じにする
Indent when as deep as case. This is the style established in both “The Ruby Programming Language” and “Programming Ruby”.
これは意見が割れそうなスタイルですが、書籍を論拠として利用しています。繰り返しになりますが、重要なのは「どちらかに決める」ことなので。
このスタイルについて、弊社Webチームのkazzさんから以下の記事をお知らせいただきました。Eiffelの影響だったんですね。ありがとうございます!
# 不可
case
when song.name == 'Misty'
puts 'Not again!'
when song.duration > 120
puts 'Too long!'
when Time.now.hour > 21
puts "It's too late"
else
song.play
end
# 良好
case
when song.name == 'Misty'
puts 'Not again!'
when song.duration > 120
puts 'Too long!'
when Time.now.hour > 21
puts "It's too late"
else
song.play
end
変数に条件式の結果を代入する場合、条件式の後続文は条件式と同じ位置になるようインデントする
When assigning the result of a conditional expression to a variable, preserve the usual alignment of its branches.
- 「良好」例の1番目では
case
、when
、if
、else
、end
の縦が揃っていて、見ていてキモチイイですね。このスタイルは多くの言語で採用されているようです。
- 「良好」の2番目では、さらに等号
=
で改行することで、条件式の結果の代入で幅を取りすぎないようにできます。
面白いのは、どちらの場合もcase
やif
に対応するend
まで縦が揃っていることです。深入りはしませんが、Rubyのcase
やif
は例に示されているとおり結果の値を返すので、case
やif
全体で値を返すことを強調するという意図なのだろうと理解しました。
「良好」が2つあるのは、議論で決着がつかなかったのかもしれません。
# 不可 - 文がわかりにくい
kind = case year
when 1850..1889 then 'Blues'
when 1890..1909 then 'Ragtime'
when 1910..1929 then 'New Orleans Jazz'
when 1930..1939 then 'Swing'
when 1940..1950 then 'Bebop'
else 'Jazz'
end
result = if some_cond
calc_something
else
calc_something_else
end
# 良好 - 処理内容が明確
kind = case year
when 1850..1889 then 'Blues'
when 1890..1909 then 'Ragtime'
when 1910..1929 then 'New Orleans Jazz'
when 1930..1939 then 'Swing'
when 1940..1950 then 'Bebop'
else 'Jazz'
end
result = if some_cond
calc_something
else
calc_something_else
end
# 良好 (コードの幅をもう少し節約できる)
kind =
case year
when 1850..1889 then 'Blues'
when 1890..1909 then 'Ragtime'
when 1910..1929 then 'New Orleans Jazz'
when 1930..1939 then 'Swing'
when 1940..1950 then 'Bebop'
else 'Jazz'
end
result =
if some_cond
calc_something
else
calc_something_else
end
morimorihogeコメント:
Ruby styleなcase-whenインデントは、ソフトウェア解析分野での条件分岐命令のネスト深度測定とも一貫する(インデントの深さが条件分岐の深さとそろう)ので、そこがよいですね。
追伸
コメント中の「不可」で使われていたconvolutedは、ここでは「わかりにくい」「込み入っている」程度の意味です。最近だと機械学習方面のConvolutional neural networkなどでよく見かけますね。
メソッド定義とメソッド定義の間には空行を置く、論理上パラグラフとして区切れる部分にも空行を置く
Use empty lines between method definitions and also to break up methods into logical paragraphs internally.
空行がないと一気に読みづらくなるので納得です。「lines」と複数形になっているので、1行より多く空行を置いてもよいということになりますね。
def some_method
data = initialize(options)
data.manipulate!
data.result
end
def some_method
result
end
メソッド呼び出しの末尾パラメーターの後ろにはカンマを置かない(特にメソッド呼び出しが1行の場合)
Avoid comma after the last parameter in a method call, especially when the parameters are not on separate lines.
「不可」のコメントについて詳しくは「ケツカンマ」でググるのがよいと思います。
# 不可
#(末尾にもカンマがあればパラメーターの追加や削除が楽になるのはわかるが、それでも推奨しない)
some_method(
size,
count,
color,
)
# 不可
some_method(size, count, color, )
# 良好
some_method(size, count, color)
メソッドのパラメータでデフォルト値を与える場合、=
の前後にはスペースを置く
Use spaces around the = operator when assigning default values to method parameters:
これも「どちらに決めるか」の話ですね。
# 不可
def some_method(arg1=:default, arg2=nil, arg3=[])
# do something...
end
# 良好
def some_method(arg1 = :default, arg2 = nil, arg3 = [])
# do something...
end
While several Ruby books suggest the first style, the second is much more prominent in practice (and arguably a bit more readable).
1番目はここでは「不可」となっていますが、多くの書籍で使われているのでそれなりに理由があるはずです。
\
で行を継続するのは避ける(文字列の結合での利用のみ認める)
Avoid line continuation \ where not required. In practice, avoid using line continuations for anything but string concatenation.
私は\
で行を分割するというのをやったことがないのですが、特に英語圏にはエディタの行折り返しを好まない開発者が意外にいるので、そうした設定での行分割に使うのではないかと想像しました。
# 不可
result = 1 - \
2
# 良好 (but still ugly as hell)
result = 1 \
- 2
long_string = 'First part of the long string' \
' and second part of the long string'
ドット.
によるメソッドチェーンを行分割する場合は、Option AとOption Bのいずれかに揃える
Adopt a consistent multi-line method chaining style. There are two popular styles in the Ruby community, both of which are considered good—leading . (Option A) and trailing . (Option B).
A discussion on the merits of both alternative styles can be found here.
Option AとOption Bのどちらがよりよいというものではない、ということですね。重要なのはどちらかに揃えることです。
以下のコメントで両陣営の言い分がよくわかります。
Option A
When continuing a chained method invocation on another line keep the . on the second line.
ドット.
を次の行の最初に置くスタイルです。
# 不可
one.two.three. # 1行目を読まないと2行目がメソッドチェーンであることがわからない
four
# 良好
one.two.three # 2行目がメソッドチェーンであることがひと目でわかる
.four
Option B
When continuing a chained method invocation on another line, include the . on the first line to indicate that the expression continues.
ドット.
を前の行に残すスタイルです。
# 不可
one.two.three # 2行目を読まないとメソッドチェーンが継続しているかどうかがわからない
.four
# 良好
one.two.three. # 1行目のメソッドチェーンが継続していることがひと目でわかる
four
仮にメソッドチェーンで..
のようにドットを重ねてよい仕様であれば両方にドットを残すことができるのでしょうが、..
はRubyの範囲演算子なのでぶつかってしまいますね。
『宗論はどちらが負けても釈迦の恥』という言葉をなぜか思い出してしまいました。
メソッド呼び出しを2行以上に分割する場合はパラメータを揃える(幅が足りない場合は「2インデント」も認める)
Align the parameters of a method call if they span more than one line. When aligning parameters is not appropriate due to line-length constraints, single indent for the lines after the first is also acceptable.
原則、以下の上図のようにパラメータの縦をキモチヨク揃えますが、表示幅が狭い場合は下図でもよいということですね。
# この長すぎるメソッドを分割するとする
def send_mail(source)
Mailer.deliver(to: 'bob@example.com', from: 'us@example.com', subject: 'Important message', body: source.text)
end
# 不可(4スペースインデント)
def send_mail(source)
Mailer.deliver(
to: 'bob@example.com',
from: 'us@example.com',
subject: 'Important message',
body: source.text)
end
# 良好
def send_mail(source)
Mailer.deliver(to: 'bob@example.com',
from: 'us@example.com',
subject: 'Important message',
body: source.text)
end
# 良好 (通常の2スペースインデント)
def send_mail(source)
Mailer.deliver(
to: 'bob@example.com',
from: 'us@example.com',
subject: 'Important message',
body: source.text
)
end
配列リテラルの要素を複数行に分割する場合は縦を揃える
Align the elements of array literals spanning multiple lines.
# 不可 - single indent
menu_item = ['Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam',
'Baked beans', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam']
# 良好
menu_item = [
'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam',
'Baked beans', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam'
]
# 良好
menu_item =
['Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam',
'Baked beans', 'Spam', 'Spam', 'Spam', 'Spam', 'Spam']
ブラケット[
も次の行に送ると縦が揃ってないように見える気もしますが、これも認められています。
桁数の多い数値はアンダースコア_
で区切る
Add underscores to large numeric literals to improve their readability.
この記法は他の言語では見かけないような気がしますが、カンマを使わなくてよいので便利ですね。
# 不可 - how many 0s are there?
num = 1000000
# 良好 - much easier to parse for the human brain
num = 1_000_000
数値のprefixは小文字で書く
Prefer smallcase letters for numeric literal prefixes. 0o for octal, 0x for hexadecimal and 0b for binary. Do not use 0d prefix for decimal literals.
Rubyでは大文字でも書けることを初めて知りました。
# 不可
num = 01234
num = 0O1234
num = 0X12AB
num = 0B10101
num = 0D1234
num = 0d1234
# 良好 - easier to separate digits from the prefix
num = 0o1234
num = 0x12AB
num = 0b10101
num = 1234
APIドキュメントにはRDocを使い、RDocコメント行def
の間に空行を置かないようにする
Use Rdoc and its conventions for API documentation. Don’t put an empty line between the comment block and the def.
YARDは標準ではないんですね。
1行は80文字以内とする。
Limit lines to 80 characters.
もちろん半角英数字(alphanumeric)での80文字ですね。1行にそんなにたくさん押し込めたことがないのでわかりませんが、個人的にはエディタのワードラップアラウンドにおまかせしたいところです。
行末にスペース文字(ホワイトスペース)を置かない
Avoid trailing whitespace.
行の末尾のことですね。trailingといえば通常対象の末尾を指します。
ファイルの末尾には空行を置くこと
End each file with a newline.
これが必要とされる理由を知らないのですが、美観上の理由でしょうか。
=begin
と=end
によるブロックコメントは使わない
Don’t use block comments. They cannot be preceded by whitespace and are not as easy to spot as regular comments.
=begin
と=end
の間のコメント行の先頭にはスペースを置けないんですね。実は使ったことがありません。
# 不可
=begin
comment line
another comment line
=end
# 良好
# comment line
# another comment line
今回は以上です。次回は「Syntax」です。ご期待ください。