Ruby 风格指导

使用空格来围绕操作符,逗号 、冒号 及分号 之后。空格可能对(大部分)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

不要有空格在 ( 、 [ 之后,或 ] 、 ) 之前。

some(arg).other
[1, 2, 3].length

把 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

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

在 def 之间使用空行,并且把方法分成合乎逻辑的段落。

def some_method
  data = initialize(options)

  data.manipulate!

  data.result
end

def some_method
  result
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

# 好
def send_mail(source)
  Mailer.deliver(to: 'bob@example.com',
                 from: 'us@example.com',
                 subject: 'Important message',
                 body: source.text)
end

使用 RDoc 以及它的惯例来撰写 API 文档。不要在注解区块及 def 之前放一个空行。 让每一行保持少于 80 个字符。 避免尾随的空白。

语法

使用 def 时,当有参数时使用括号。当方法不接受任何参数时,省略括号。

def some_method
# body omitted
end

def some_method_with_arguments(arg1, arg2)
# body omitted
end

永远不要使用 for ,除非你很清楚为什么。大部分情况应该使用迭代器来取代。 for 是由 each 所实作的(所以你加入了一层的迂回),但出乎意料的是 — for 并没有包含一个新的视野(不像是 each )而在这个区块中定义的变量将会被外部所看到。

arr = [1, 2, 3]

# 差
for elem in arr do
  puts elem
end

# 好
arr.each { |elem| puts elem }

永远不要在多行的 if/unless 使用 then

# 差
if some_condition then
  # body omitted
end

# 好
if some_condition
  # body omitted
end

偏爱三元操作符 ? : 胜于 if/then/else/end 结构。它更为常见及更精准。

# 差
result = if some_condition then something else something_else end

# 好
result = some_condition ? something : something_else

使用一个表达式给一个三元操作符的分支。这也意味着三元操作符不要嵌套。嵌套情况使用 if/else 结构。

# 差
some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else

# 好
if some_condition
  nested_condition ? nested_something : nested_something_else
else
  something_else
end

永远不要使用 if x: ... — 它已经在 Ruby 1.9 被移除了。使用三元操作符来取代。

# 差
result = if some_condition: something else something_else end

# 好
result = some_condition ? something : something_else

永远不要使用 if x: ... 使用三元操作符来取代。

一行的情况使用 when x then ...。替代方案的语法 when x: ... 在 Ruby 1.9 被移除了。

永远不要使用 when x: ...。参考前一个规则。

布尔表达式使用 &&/||,控制流程使用 and/or。 (经验法则:如果你需要使用外部括号,你正在使用错误的操作符。)

# 布尔表达式
if some_condition && some_other_condition
  do_something
end

# 控制流程
document.saved? or document.save!

避免多行的 ? :(三元操作符),使用 if/unless 来取代。

偏爱 if/unless 修饰符当你有单行的主体。

另一个好的方法是使用控制流程的 and/or

# 差
if some_condition
  do_something
end

# 好
do_something if some_condition

# 另一个好方法
some_condition and do_something

否定条件偏爱 unless 优于 if(或是控制流程 or)。

# 差
do_something if !some_condition

# 好
do_something unless some_condition

# 另一个好方法
some_condition or do_something

永远不要使用 unless 搭配 else 。将它们改写成肯定条件。

# 差
unless success?
  puts 'failure'
else
  puts 'success'
end

# 好
if success?
  puts 'success'
else
  puts 'failure'
end

不要使用括号围绕 if/unless/while 的条件式,除非这条件包含了一个赋值(见下面使用 = (一个赋值)的返回值)。

# 差
if (x > 10)
  # body omitted
end

# 好
if x > 10
  # body omitted
end

# 好
if (x = self.next_value)
  # body omitted
end

忽略围绕方法参数的括号,如内部 DSL (如:Rake, Rails, RSpec),Ruby 中带有“关键字”状态的方法(如:attr_readerputs)以及属性存取方法。

所有其他的方法呼叫使用括号围绕参数。

class Person
  attr_reader :name, :age

# 忽略
end

temperance = Person.new('Temperance', 30)
temperance.name

puts temperance.age

x = Math.sin(y)
array.delete(e)

单行区块喜好 {...} 胜于 do..end。多行区块避免使用 {...}(多行串连总是​​丑陋)。在 do...end 、“控制流程”及“方法定义” ,永远使用 do...end (如 Rakefile 及某些 DSL)。串连时避免使用 do...end

names = ["Bozhidar", "Steve", "Sarah"]

# 好
names.each { |name| puts name }

# 差
names.each do |name|
  puts name
end

# 好
names.select { |name| name.start_with?("S") }.map { |name| name.upcase }

# 差
names.select do |name|
  name.start_with?("S")
end.map { |name| name.upcase }

某些人会争论多行串连时,使用 {...} 看起来还可以,
但他们应该问问自己 — 这样代码真的可读吗
以及不能把区块内容取出来放到绝妙的方法中吗。

避免在不需要的场合时使用 return 。

# 差
def some_method(some_arr)
  return some_arr.size
end

# 好
def some_method(some_arr)
  some_arr.size
end

当赋予缺省值给方法参数时,使用空格围绕 = 操作符。

# 差
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

使用 =(一个赋值)的返回值是好的,但用括号环绕赋值。

# 好 — 演示赋值的目标用途
if (v = array.grep(/foo/)) ...

# 差
if v = array.grep(/foo/) ...

# 也很好 — 演示赋值的目标用途及有正确的优先序
if (v = self.next_value) == "hello" ...

随意使用 ||= 来初始化变量

# 仅在 name 为 nil 或 false 时,把名字设为 Bozhidar。
name ||= 'Bozhidar'

不要使用 ||= 来初始化布尔变量。

(想看看如果现在的值刚好是 false 时会发生什么。)

# 差 — 会把 enabled 设成真,即便它本来是假。
enabled ||= true

# 好
enabled = true if enabled.nil?

避免使用 Perl 风格的特别变量(像是 $0-9$`, 等等)。它们看起来非常神秘以及不鼓励使用一行的脚本。

避免在方法名与左括号之间放一个空格。

# 差
f (3 + 2) + 1

# 好
f(3 + 2) + 1

如果方法的第一个参数由左括号开始,永远在这个方法呼叫里使用括号。

举个例子,写 f((3+2) + 1)

总是使用 -w 来执行 Ruby 直译器,如果你忘了某个上述的规则,它就会警告你!

当你的哈希键是符号时,使用 Ruby 1.9 哈希字面语法。

# 差
hash = { :one => 1, :two => 2 }

# 好
hash = { one: 1, two: 2 }

使用新的 lambda 字面语法。

# 差
lambda = lambda { |a, b​​| a + b }
lambda.call(1, 2)

# 好
lambda = ->(a, b) { a + b }
lambda.(1, 2)

未使用的区块参数使用 _ 。

# 差
result = hash.map { |k, v| v + 1 }

# 好
result = hash.map { |_, v| v + 1 }

命名

程式设计的真正难题是替事物命名及无效的缓存。 
-- Phil Karlton

方法与变量使用蛇底式小写( snake_case )。

类别与模组使用驼峰式大小写( CamelCase )。(保留像是HTTP、RFC、XML 这种缩写为大写)

其他常数使用尖叫蛇底式大写( SCREAMING_SNAKE_CASE )。

判断式方法的名字(返回布尔值的方法)应以问号结尾。 (即 Array#empty? )

有潜在“危险性”的方法,若此危险方法有安全版本存在时,应以惊叹号结尾(即:改动 self 或参数、 exit! 等等方法)。

# 不好 - 没有对应的安全方法
class Person
  def update!
  end
end

# 好
class Person
  def update
  end
end

# 好
class Person
  def update!
  end

  def update
  end
end

如果可能的话,从危险方法(bang)的角度来定义对应的安全方法(non-bang)。

class Array
  def flatten_once!
    res = []

    each do |e|
      [*e].each { |f| res << f }
    end

    replace(res)
  end

  def flatten_once
    dup.f​​latten_once!
  end
end

在短的区块使用 reduce 时,把参数命名为 |a, e| (累加器,元素)。

当定义二元操作符时,把参数命名为 other 。

def +(other)
  # body omitted
end

偏好 map 胜于 collect , find 胜于 detect , select 胜于 find_all , reduce胜于 inject 以及 size 胜于 length 。这不是一个硬性要求;如果使用别名增加了可读性,使用它没关系。

这些有押韵的方法名是从 Smalltalk 继承而来,在别的语言不常见。鼓励使用 select 而不是 find_all 的理由是它跟 reject 搭配起来是一目了然的。


详细地址: https://guides.ruby.tw/ruby-rails-style-guides/zhCN/#ruby

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值