源代码排版
源代码排版
所有风格都又丑又难读,自己的除外。几乎人人都这样想。把“自己的除外”拿掉,他们或许是对的…
——Jerry Coffin(论缩排)
-
使用
UTF-8作为源文件的编码。
[link] -
每个缩排层级使用两个空格 。不要使用制表符。
[link]
## 差 - 四个空格
def some_method
do_something
end
## 好
def some_method
do_something
end
-
使用 Unix 风格的换行符。(*BSD/Solaris/Linux/OS X 系统的用户不需担心,Windows 用户则要格外小心。)
[link]- 如果你使用 Git,可用下面这个配置来保护你的项目不被 Windows 的换行符干扰:
$ git config --global core.autocrlf true
- 不要使用
;隔开语句与表达式。推论:一行一条语句。
[link]
## 差
puts 'foobar'; # 不必要的分号
puts 'foo'; puts 'bar' # 一行里有两个表达式
## 好
puts 'foobar'
puts 'foo'
puts 'bar'
puts 'foo', 'bar' # 仅对 puts 适用
- 对于没有主体的类,倾向使用单行定义。
[link]
## 差
class FooError < StandardError
end
## 勉强可以
class FooError < StandardError; end
## 好
FooError = Class.new(StandardError)
- 定义方法时,避免单行写法。尽管这种写法有时颇为普遍,但其略显古怪的定义语法容易使人犯错。无论如何,至少保证单行写法的方法不应该拥有一个以上的表达式。
[link]
## 差
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 解释器(大部分情况下)会忽略空格,但适量的空格可以增强代码的可读性。
[link]
sum = 1 + 2
a, b = 1, 2
class FooError < StandardError; end
(对于操作符)唯一的例外是当使用指数操作符时:
## 差
e = M * c ** 2
## 好
e = M * c**2
(、[之后,]、)之前,不要添加任何空格。在{前后,在}之前添加空格。
[link]
# 差
some( arg ).other
[ 1, 2, 3 ].each{|e| puts e}
# 好
some(arg).other
[1, 2, 3].each { |e| puts e }
{ 与 } 需要额外说明,因为它们可以同时用在区块、哈希字面量及字符串插值中。
对于哈希字面量,有两种可被接受的风格。第一种风格更具可读性(在 Ruby 社区里似乎更为流行)。第二种风格的优点是,在视觉上使得区块与哈希字面量有所区分。无论你选择何种风格,务必在使用时保持连贯性。
# 好 - { 之后 与 } 之前有空格
{ one: 1, two: 2 }
# 好 - { 之后 与 } 之前无空格
{one: 1, two: 2}
对于插值表达式,括号内两端不要添加空格。
# 差
"From: #{ user.first_name }, #{ user.last_name }"
# 好
"From: #{user.first_name}, #{user.last_name}"
!之后,不要添加任何空格。
[link]
## 差
! something
## 好
!something
- 范围的字面量语法中,不要添加任何空格。
[link]
# 差
1 .. 3
'a' ... 'z'
# 好
1..3
'a'...'z'
- 把
when与case缩排在同一层级。这是《Programming Ruby》与《The Ruby Programming Language》中早已确立的风格。
[link]
## 差
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
- 当将一个条件表达式的结果赋值给一个变量时,保持分支缩排在同一层级。
[link]
## 差 - 非常费解
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
- 在各个方法定义之间添加空行,并且将方法分成若干合乎逻辑的段落。
[link]
def some_method
data = initialize(options)
data.manipulate!
data.result
end
def some_method
result
end
- 在各个段落之间,使用一个空行分隔。
[link]
## 差 - 使用了两个空行
some_method
some_method
## 好
some_method
some_method
- <a name="empty-lines-around-access-modifier"></a> 在属性修饰器之后,使用一个空行分隔。 <sup>[link]</sup>
```Ruby # 差 class Foo attr_reader :foo def foo # 做一些事情 end end
# 好 class Foo attr_reader :foo
def foo
# 做一些事情
end
end
*
在不同缩进的代码之间,不要使用空行分隔。
[link]
差
class Foo
def foo
begin
do_something do
something
end
rescue
something
end
end
end
好
class Foo def foo begin do_something do something end rescue something end end end
*
避免在方法调用的最后一个参数之后添加逗号,尤其当参数没有分布在同一行时。
[link]
差 - 尽管移动、新增、删除参数颇为方便,但仍不推荐这种写法
some_method( size, count, color, )
差
some_method(size, count, color, )
好
some_method(size, count, color)
*
当给方法的参数赋予默认值时,在 `=` 前后添加空格。
[link]
差
def some_method(arg1=:default, arg2=nil, arg3=[]) # 做一些事情 end
好
def some_method(arg1 = :default, arg2 = nil, arg3 = []) # 做一些事情 end
尽管有几本 Ruby 书籍推荐使用第一种风格,但第二种在实践中更为常见(而且似乎更具可读性)。
*
避免在非必要的情形下使用续行符 `\`。在实践中,除了字符串拼接,避免在其他任何地方使用续行。
[link]
差
result = 1 - \ 2
好 - 但仍然丑到爆
result = 1 \ - 2
long_string = 'First part of the long string' \ ' and second part of the long string'
*
使用统一的风格进行多行链式方法调用。在 Ruby 社区中存在两种流行的风格:前置 `.`(风格 A)与后置 `.`(风格 B)。
[link]
* **(风格 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>)。
*
当方法调用参数过长时,将它们排列在多行并对齐。若对齐后长度超过行宽限制,将首个参数位置挪到下一行进行缩排也是可以接受的。
[link]
初始(行太长了)
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
*
当构建数组时,若元素跨行,应当保持对齐。
[link]
差 - 没有对齐
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']
*
使用 `_` 语法改善大数的数值字面量的可读性。
[link]
差 - 有几个零?
num = 1000000
好 - 方便人脑理解
num = 1_000_000
*
当数值需要前缀标识进制时,倾向使用小写字母。使用 `0o` 标识八进制,使用 `0x` 标识十六进制,使用 `0b` 标识二进制。十进制数值无需前缀(`0d`)标识。
[link]
差
num = 01234 num = 0O1234 num = 0X12AB num = 0B10101 num = 0D1234 num = 0d1234
好 - 方便区分数值前缀与具体数字
num = 0o1234 num = 0x12AB num = 0b10101 num = 1234
*
使用 [RDoc][rdoc] 及其惯例来编写 API 文档。注意,不要在注释与 `def` 之间添加空行。
[link]
*
将单行长度控制在 80 个字符内。
[link]
*
避免行尾空格。
[link]
*
文件以空白行结束。
[link]
*
不要使用区块注释。它们不能被空白字符引导,且不如常规注释容易辨认。
[link]
差
=begin comment line another comment line =end
好
comment line
another comment line
```
