源代码排版
所有风格都又丑又难读,自己的除外。几乎人人都这样想。把“自己的除外”拿掉,他们或许是对的…
——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]```Ruby
差 - 使用了两个空行
some_method
some_method
好
some_method
some_method
* <a name="empty-lines-around-access-modifier"></a>
在属性修饰器之后,使用一个空行分隔。
<sup>[[link](#empty-lines-around-access-modifier)]</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
两种风格各自优点查阅这里。
当方法调用参数过长时,将它们排列在多行并对齐。若对齐后长度超过行宽限制,将首个参数位置挪到下一行进行缩排也是可以接受的。
[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