源代码排版
最后更新于:2022-04-01 01:18:30
> 所有风格都又丑又难读,自己的除外。几乎人人都这样想。把“自己的除外”拿掉,他们或许是对的...
> ——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
# 好
# 一行注释
# 另一行注释
~~~