雖然 Ruby 是一門能夠讓開發者發揮十足創意的魔幻語言,你可以用很多種方式完成同一件事。但這個語言的圈子內的開發者,在 Coding Style 上其實還是有一定的默契存在。
縮排慣例
Ruby 的縮排是 2 個空格。不是 3,也不是 4。
1 2 3 4 5 6 7 8 9 | |
編輯器的自動縮排功能
最多開發者使用的兩套文字編輯器是 Vim 與 TextMate。
- TextMate
Texmate 內建有 Ruby 與 Ruby on Rails 兩套 Bundle。開發者在撰寫的時候就會自動進行縮排。而如果在開發時遇到其他人不小心將程式碼排的歪七扭八。也可以使用 Code Beautifier 這套 Bundle 自動整理程式碼。
- Vim
可以使用 vim-ruby 和 vim-rails 這兩套 plugin。
命名慣例
變數或者是 method 名稱,採用 snake_case
1 2 3 | |
Class 和 Module 名稱,採用 CamelCase
1 2 3 4 5 | |
CONSTANT 使用 SCREAMING_SNAKE_CASE
1 2 3 | |
迴圈慣例
單行的迴圈使用 { } ,多行的迴圈使用 do end
1 2 3 4 5 6 | |
大師 Jim Weirich 在 Braces VS DO/END 這篇提出他的觀點:
- Use { } for blocks that return values
- Use do / end for blocks that are executed for side effects
1 2 3 4 5 6 7 8 | |
使用 each 而非 for
Ruby 中跑迴圈的方式可以有很多種,最常使用的是 for 和 each
使用無窮迴圈測試四種常見迴圈寫法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | |
跑出來的數值如下
1 2 3 4 5 | |
for 明顯比 each 慢上許多。
參考資料:
括號慣例
定義 method 要加括號。除非沒有參數。
1 2 3 4 5 6 7 8 9 | |
使用 method 要加括號。除非是 statement 或 command
1 2 3 4 5 6 7 | |
statement 多數時候要加括號,但如果狀況單純可不加括號
1 2 3 4 5 6 7 8 9 10 11 | |
「使用括號」是一個相對比較好的習慣
看到這裡都開始讓人搞迷糊了。到底是什麼樣的情況要加括號?什麼樣的情況不加括號?筆者的建議是,一旦沾到相當較複雜的陳述句時,儘量加上括號。Ruby 雖然是一個相當自由的語言,可以用空格(space)或是括號(parentheses)傳入參數。但濫用空格可能造成 Ruby 在 parsing 陳述句的時候解讀異常,產出非正確的結果,這就是大家所不願意樂見的狀況了。
括號的唯一例外:super 與 super()
在 Ruby 中,唯一加括號和不加括號會有別的是 super 與 super()。它們代表了不同的意思:
- super 不加括號表示呼叫父類別的同名函式,並且將本函式的所有參數傳入父類別的同名函式。
1 2 3 4 5 6 7 8 9 10 11 | |
如果執行
1 2 | |
將會印出 a b c
- super() 帶括號則表示呼叫父類別的同名函式,但是不傳入任何參數。
但如果是
1 2 3 4 5 6 7 8 9 10 11 | |
執行
1 2 | |
則不會印出任何東西。
Boolean 慣例
- 布林邏輯使用 && 與 || ,而非 and 和 or
不少人在寫邏輯判段式時,會誤以為 && 和 || 與 and / or 是等價的,因此產出不少 bug。其實 and 和 or 跟 if / else 是等價的。所以請千萬不要在 boolean 邏輯內使用 and / or。
- 被判斷為 foo = ( 42 && foo ) / 2
1 2 | |
- 使用 and
1 2 | |
and 與 or 真正的用法
and 的用法
1
| |
相當於
1
| |
or 的用法
1
| |
相當於
1
| |
參考資料
- Avdi 的 Using “and” and “or” in Ruby
邏輯慣例
if / unless 的寫作觀念
Ruby 在邏輯控制的部份,除了提供 if 還提供了 unless。
unless 等於 「if not something 」等於 「if !something」。
不過雖說 Ruby 提供了 unless 這個用法,但在實務上來說,一般還是不太推薦使用 unless。除了以下幾種狀況:
當語意較適合時,使用 unless
1 2 3 | |
沒有 else 的時候,使用 unless
當沒有 else 的時候,看起來還算 OK
1 2 3 | |
但加上一個 else,看起來就不是那麼直觀了
1 2 3 4 5 | |
如果專案當中有這樣的 code,相信我,換成 if 的陳述會直觀許多。
1 2 3 4 5 | |
當只有一個條件時,使用 unless 很適合。但多個條件時,使用 unless 很糟糕。
1 2 3 | |
相同的,改成 if 也會直觀許多
1 2 3 | |
if / else 牽扯到的 Fail Close 安全觀念
在撰寫安全性程式碼時,使用 if 和 unless,也會產生截然不同的差別。在 Security on Rails 中有介紹 Fail open 與 Fail close 兩種觀念:
“Fail open” way, it’s bad
1 2 3 4 5 6 | |
“Fail close” way
1 2 3 4 5 6 7 8 | |
使用 Fail open:「條件不成功,才不允許,不然就允許。」出包的機率遠比 Fail close:「如果條件成功,才允許進行,不然就不允許。」高的許多,這也是值得注意的地方。
使用三重運算子簡化 if / else
比較簡單的 if / else statement
如:
1 2 3 4 5 | |
其實可以簡化成 :
1
| |
不要濫用三重運算子
雖說 Ruby 提供這樣的簡化方式,但儘量還是不要濫用。如果超過兩層還是要將之拆開
1 2 3 4 5 6 7 8 9 | |
其他慣例
字串慣例
使用 "#{}" 而非 + 串接字串。
1 2 3 4 5 | |
原因:使用 string interpolation 可以讓程式顯得更直觀。而且 +會產生一堆不必要的 new object。
使用 << 而非 + 串接字串
1
| |
原因:String#<< 比 String#+ 速度快的多。而且 +會產生一堆不必要的 new object。
偏好使用 " "(double quote) 而非' '(single quote) 包覆字串
1 2 3 4 5 6 7 8 | |
原因: 雖然 ' ' 和 " " 都可以用來宣告字串。但" " 才有 string interpolation (double quote)效果。
使用 %() 處理需要 string interpolation 但同時也需要 " "(double quote) 的狀況
有時候我們不避免的需要寫出這樣的 code
1
| |
雖然可以透過將 " " 換成 ' ' 讓 code 不那麼粘膩。
1
| |
但其實還有這一招使用 %(),可以確保事情不會變得更加複雜。
1
| |
Array 慣例
當要宣告一個擁有多字串的 Array 陣列時,偏好使用 %w
1 2 3 4 | |
Hash 慣例
使用 :symbool 而非 "string" 作為 Hash 的 key
1 2 3 4 5 | |
原因:若使用 "string",Ruby 每次都會為 key 在不同的記憶體位置再產生一個新 string object 。
使用 "string" :
1 2 3 4 5 6 | |
改採用 :symbol :
1 2 3 4 5 6 | |
這就是鼓勵使用 [:symbol] 而非"string" 作為 Hash 中的key的原因,在很多記憶體使用量的膨脹和浪費的 case 中,多數都是因為產生了過多不必要的 object 所造成的問題。