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