> 所有風格都又丑又難讀,自己的除外。幾乎人人都這樣想。把“自己的除外”拿掉,他們或許是對的...
> ——Jerry Coffin(論縮排)
* 使用?`UTF-8`?作為源文件的編碼。
* 每個縮排層級使用兩個**空格**。不要使用硬 tab。
~~~
# 差 - 四個空格
def some_method
do_something
end
# 好
def some_method
do_something
end
~~~
* 使用 Unix 風格的換行符。(BSD/Solaris/Linux/OSX 的用戶不用擔心,Windows 用戶要格外小心。)
* 如果你使用 Git ,可用下面這個配置,來保護你的項目不被 Windows 的換行符干擾:
~~~
$ git config --global core.autocrlf true
~~~
* 不使用?`;`?隔開語句和表達式。推論——一行一條語句。
~~~
# 差
puts 'foobar'; # 不必要的分號
puts 'foo'; puts 'bar' # 一行里有兩個表達式
# 好
puts 'foobar'
puts 'foo'
puts 'bar'
puts 'foo', 'bar' # 僅對 puts 適用
~~~
* 對于沒有成員的類,盡可能使用單行類定義。
~~~
# 差
class FooError < StandardError
end
# 勉強可以
class FooError < StandardError; end
# 好
FooError = Class.new(StandardError)
~~~
* 定義方法時避免單行寫法。盡管還是有些人喜歡這么用的。但是單行定義很容易出錯,因為它在語法上有些古怪。無論如何——一個單行方法里的表達式不應該多于 1 個。
~~~
# 差
def too_much; something; something_else; end
# 勉強可以——注意第一個 ; 是必需的
def no_braces_method; body end
# 勉強可以——注意第二個 ; 是可選的
def no_braces_method; body; end
# 勉強可以——語法上正確,但是沒有 ; 讓它有些難讀
def some_method() body end
# 好
def some_method
body
end
~~~
這個規則的一個例外是空方法。
~~~
# 好
def no_op; end
~~~
* 操作符前后的空格。在逗號?`,`?、冒號?`:`?及分號?`;`?之后,在?`{`?前后,在?`}`?之前。 Ruby 解釋器(大部分情況下)忽略空格。但要寫出可讀性高的代碼,正確使用空格是關鍵。
~~~
sum = 1 + 2
a, b = 1, 2
1 > 2 ? true : false; puts 'Hi'
[1, 2, 3].each { |e| puts e }
~~~
(針對操作符)唯一的例外是當使用指數操作符時:
~~~
# 差
e = M * c ** 2
# 好
e = M * c**2
~~~
`{`?和?`}`?需要額外說明,因為他們是用在塊(block)、 哈希字面量(hash literals),以及字符串插值中。 對于哈希字面量來說,兩種風格都是可接受的。
~~~
# 好——`{` 之后和 `}` 之前有空格
{ one: 1, two: 2 }
# 好——`{` 之后和 `}` 之前沒有空格
{one: 1, two: 2}
~~~
第一個種風格稍微更具可讀性(而且有爭議的是,一般在 Ruby 社區里更受歡迎)。 第二種風格具有可為塊和哈希字面量添加可視化的差別的優點。 無論你選哪一種都行——但是最好保持一致。
* `(`?、?`[`?之后,?`]`?、?`)`?之前,不要有空格。
~~~
some(arg).other
[1, 2, 3].length
~~~
* `!`?后不要有空格。
~~~
# 差
! something
# 好
!something
~~~
* 范圍表達式中間不要有空格。
~~~
# 差
1 .. 3
'a' ... 'z'
# 好
1..3
'a'...'z'
~~~
* 把?`when`?跟?`case`?縮排在同一層。我知道很多人不同意這一點,但這是《The Ruby Programming Language》及《Programming Ruby》所使用的風格。
~~~
# 差
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
~~~
* 當賦值一個條件表達式的結果給一個變量時,保持分支的縮排在同一層。
~~~
# 差 - 非常復雜
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
~~~
* 在?`def`?之間使用空行,并且用空行把方法分成合乎邏輯的段落。
~~~
def some_method
data = initialize(options)
data.manipulate!
data.result
end
def some_method
result
end
~~~
* 函數最后一個參數后面不要加逗號,特別是每個參數單獨一樣的時候
~~~
# 差 - 雖然移動和增刪參數的時候會很簡單,但仍不推薦
some_method(
size,
count,
color,
)
# 差
some_method(size, count, color, )
# 好
some_method(size, count, color)
~~~
* 當給方法的參數賦默認值時,在?`=`?兩邊使用空格:
~~~
# 差
def some_method(arg1=:default, arg2=nil, arg3=[])
# 做一些任務...
end
# 好
def some_method(arg1 = :default, arg2 = nil, arg3 = [])
# 做一些任務...
end
~~~
雖然幾本 Ruby 書建議用第一個風格,不過第二個風格在實踐中更為常見(并可爭議地可讀性更高一點)。
* 避免在不需要的時候使用行繼續符?`\`?。實際編碼時,除非用于連接字符串, 否則避免在任何情況下使用行繼續符。
~~~
# 差
result = 1 - \
2
# 好 (但是仍然丑到爆)
result = 1 \
- 2
long_string = 'First part of the long string' \
' and second part of the long string'
~~~
* 使用鏈式方法時風格統一。社區認為前引點號和末端點號都是好的風格。
* (可選 A)和當一個鏈式方法調用需要在另一行繼續時,將?`.`?放在第二行。
~~~
# 差 - 為了理解第二行需要去查閱第一行
one.two.three.
four
# 好 - 第二行在做什么立刻變得很清晰
one.two.three
.four
~~~
* (可選 B)末尾用點號表示表達式沒有結束
~~~
# 差 - 需要讀到第二行才能確定表達式沒有結束
one.two.three
.four
# 好 - 從第一行就可以立即明白表達式沒有結束
one.two.three.
four
~~~
兩種方法各自優點參閱[這里](https://github.com/bbatsov/ruby-style-guide/pull/176)。
* 方法參數過長時,將它對齊排列在多行。當對齊的參數由于線寬不適合對齊時, 簡單的在第一行之后縮進也是可以接受的。
~~~
# 初始(行太長了)
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
# 好
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
~~~
* 用字面量構建數組時,如果跨行,應對齊。
~~~
# 差 - 未對齊
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']
~~~
* 大數字添加下劃線來改善可讀性。
~~~
# 差 - 有幾個零?
num = 1000000
# 好 - 更容易被人腦解析。
num = 1_000_000
~~~
* 使用 RDoc 以及它的慣例來撰寫 API 文檔。注解區塊及?`def`?不要用空行隔開。
* 每一行限制在 80 個字符內。
* 避免行尾空格。
* 文件以空白行結尾。
* 不要使用區塊注釋。它們不能由空白引導(`=begin`?必須頂頭開始),并且不如普通注釋容易辨認。
~~~
# 差
= begin
一行注釋
另一行注釋
= end
# 好
# 一行注釋
# 另一行注釋
~~~