源代码排版
所有风格都又丑又难读,自己的除外。几乎人人都这样想。把“自己的除外”拿掉,他们或许是对的...
——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
- (可选 A)和当一个链式方法调用需要在另一行继续时,将
两种方法各自优点参阅这里。
-
方法参数过长时,将它对齐排列在多行。当对齐的参数由于线宽不适合对齐时, 简单的在第一行之后缩进也是可以接受的。
# 初始(行太长了) def send_mail(source) Mailer.deliver(to: '[email protected]', from: '[email protected]', subject: 'Important message', body: source.text) end # 差(两倍缩排) def send_mail(source) Mailer.deliver( to: '[email protected]', from: '[email protected]', subject: 'Important message', body: source.text) end # 好 def send_mail(source) Mailer.deliver(to: '[email protected]', from: '[email protected]', subject: 'Important message', body: source.text) end # 好(普通缩排) def send_mail(source) Mailer.deliver( to: '[email protected]', from: '[email protected]', 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 # 好 # 一行注释 # 另一行注释
更多建议: