牛骨文教育服务平台(让学习变的简单)

所有风格都又丑又难读,自己的除外。几乎人人都这样想。把“自己的除外”拿掉,他们或许是对的...
——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
    

两种方法各自优点参阅这里

  • 方法参数过长时,将它对齐排列在多行。当对齐的参数由于线宽不适合对齐时, 简单的在第一行之后缩进也是可以接受的。

    # 初始(行太长了)
    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
    
    # 好
    # 一行注释
    # 另一行注释