源代码排版

最后更新于: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 # 好 # 一行注释 # 另一行注释 ~~~
';