Ruby代码风格向导

公司推荐https://github.com/bbatsov/ruby-style-guide这个Ruby风格向导不错。我这边学习一下与大家共勉之。

蓝色字部分是我的个人理解。有不对之处,还请大家指出。

请记住下面的名言。

风格可以使一个好代码转变为伟大的代码。

-- Bozhidar Batsov


这个Ruby风格指南是推荐编写最佳的ruby代码风格。这样的话每个程序员写得代码都可以也其他程序员维护。

代码风格可以帮助世界上的人理解你的代码。但是不管什么样的代码风格都会被一些人认为有风险而拒绝使用。

该指南分为几个部分的相关规则。我尝试过添加规则背后的原因(如果它被省略,我假设是很明显的的)。


我没有把所有的代码风格都列出来。这些都是我作为一个软件工程师,在工作中从ruby交流社区得到的建议,反馈。

以及一些备受推荐的ruby资源。就像"Programming Ruby 1.9""The Ruby Programming Language".


这些规则有些正在写,有些缺少些例子。有些显而易见的就没有添加例子。在适当的时候,这些问题将得到解决 -

他们现在只需记住。


========源代码布局================

注:每个人都相信别人的代码风格是正确的,而自己是丑陋的,不可读。但是有时候他们也有可能是对的。--Jerry Coffin

这句话的意思大家不能过分相信代码风格向导,有时候还是需要一些自信,你的代码风格也有可能是正确的。


1. 使用UTF-8作为代码编码

一般ruby程序是在头上设定"# encoding: UTF-8"的方式来指定编码。

个人理解在rails里面就是在数据库设定里面指定编码为UTF-8就可以了。


2.使用2个空白作为代码缩进

# 好的缩进 2个空白
def some_method
  do_something
end

# 不好的缩进 - 4个空白
def some_method
    do_something
end
这个不用我解释了。比较简单。


3.结束符使用unix风格的 (*BSD/Solaris/Linux/OSX 用户不要担心,因为系统是默认的,Windows用户需要格外小心.)

你如果使用git管理代码的话,可以加入下面的设置保证你代码中不会有windows换行符侵入。

$ git config --global core.autocrlf true

个人认为是ruby是以LF认为换行。所以在代码中的换行要注意。

windows下以CR/LF表换行,而linux的换行符LF


4.在操作符左右,逗号,冒号,分号后面以及"{"前后,"}"前面使用空白.

空白可能和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

5.不要在“(”,“ [“之后或者”]",")"之前使用空白

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

6.case 和when的缩进一样

可能很多人不同意这样的观点,但是"The RubyProgramming 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

7。使用空行在def之间和代码逻辑块之间

def some_method
  data = initialize(options)

  data.manipulate!

  data.result
end

def some_method
  result
end

8.使用RDoc并且他能转化为API文档。

不要在注释块和def之间使用空行。


9.保持每行代码不超过80字节长度


10.避免尾随空白

就是代码结束的地方不要加空白。


========语法================

1.   def函数有参数的时候请用括号。没有参数的时候可以省略括号。

def some_method
   # body omitted
 end

 def some_method_with_arguments(arg1, arg2)
   # body omitted
 end

2.   请不要使用for.除非你有充分的理由。一般情况下是迭代器可以代替for的。

For是each的一种实现。所以你使用for只是间接调用each。但是for没有block块。这点和each不一样。并且for循环里面定义的变量对于外部是可以访问的。

arr = [1, 2, 3]

# bad
for elem in arr do
  puts elem
end

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

3. 多行使用if/unless的时候请不要使用then

# bad
if some_condition then
  # body omitted
end

# good
if some_condition
  # body omitted
end

4.   使用 if/then/else/end结构的地方请尽量用 三元操作符( ?: )代替。

因为它能使你的代码更加简洁

# bad
result = if some_condition then something else something_else end

# good
result = some_condition ? something : something_else

5. 三元操作符每一个分支只有一个表达式。也就是说三元操作符的分支表达式里面不应该有嵌套。在这种情况下,请尽量使用if/else。

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

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

6.  请不要使用ifx: ...表达式。因为在ruby 1.9里面已经去除了。请用三元操作符代替。同样 if x;…也一样不推荐使用。

# bad
result = if some_condition: something else something_else end

# good
result = some_condition ? something : something_else

7.  一行的case语句请用when x then ...语句。请不要使用when x: ...语句。因为ruby 1.9里面已经废弃掉了。同样的when x;…也不要使用。

8. 布尔变量判断请用”&&/||”。控制流程判断请用“and/or”


# boolean expression
if some_condition && some_other_condition
  do_something
end

# control flow
document.saved? or document.save!

9. 多行代码的情况下请尽量避免使用三元操作符。而是使用if/unless代替。

10.如果你的if/unless后的操作代码只有一行。请不要写多行,一行就可以了。另外一种好的写法是用and 代替。


# bad
if some_condition
  do_something
end

# good
do_something if some_condition

# another good option
some_condition and do_something

11. 相反条件的判断不要使用if 而是使用unless代替。或者用or也可以代替。


# bad
do_something if !some_condition

# good
do_something unless some_condition

# another good option
some_condition or do_something

12. 不要把unless和else在一起使用。可以用正常逻辑重写代码。


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

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

13. 请不要在if/unless/while的条件外面加上括号。

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

# good
if x > 10
  # body omitted
end

14. 调用内部DSL(例如Rake, Rails, RSpec),还有一些关键字的方法是可以省略括号的。其他方法调用的时候都不能省略括号。


class Person
  attr_reader name, age

  # omitted
end

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

puts temperance.age

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

15. 单行的block使用“{}”。多行的时候避免使用”{}”。一般是用do…end作为控制流程和一些方法(Rakefiles and certain DSLs)定义。避免使用 do…end 有链接方法的时候。


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

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

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

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

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

16. 尽量避免使用return。


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

# good
def some_method(some_arr)
  some_arr.size
end

17. 在方法的参数设置默认值的=操作符两边请加入空白

# bad
def some_method(arg1=:default, arg2=nil, arg3=[])
  # do something...
end

# good
def some_method(arg1 = :default, arg2 = nil, arg3 = [])
  # do something...
end

18.尽量避免使用换行符(\)。

# bad
result = 1 - \
         2

# good (but still ugly as hell)
result = 1 \
         - 2

19.使用=取得返回值是可以的。


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

20. 可以自由使用||=来初始化变量。


# set name to Bozhidar, only if it's nil or false
name ||= 'Bozhidar'

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


# bad - would set enabled to true even if it was false
enabled ||= true

# good
enabled = true if enabled.nil?

22. 避免使用Perl-style特殊的变量。例如($0-9, $

23.在调用方法的时候,请不要在方法名和括号之间加空格

# bad
f (3 + 2) + 1

# good
f(3 + 2) + 1

24. 如果方法的第一个参数有括号,请使用括号在方法调用的时候。例如

  f((3 + 2) + 1)

25.在ruby代码运行时候,请加上–w 运行选项。他可以提醒你,如果你忘记上面的规则的话。


==============命名==================

1.      方法名和变量命名使用snake case。

snake case = 单词之间用下划线连接。单词要么全部大写,要么全部小写。

2.  定义类和模块名字使用CamelCase

CamelCase = 每个单词的首字母为大写,空格和标点符号删除。

3.  常量命名使用SCREAMING_SNAKE_CASE

   SCREAMING_SNAKE_CASE= 全部大写的snakecase

4.   一个返回布尔型的方法命名的结尾请加上问号?.

5.   有潜在危险的方法的命名请在结尾加上感叹号!

有潜在危险的方法 = 改变自己或者参数的方法

6.   使用inject方法时,命名参数为|a,e|(accumulator, element).

7.   如果定义二元运算符方法时,参数命名为other

def +(other)
  # body omitted
end

8.  使用map优于collect,find优于detect,select优于find_all,size优于length.

这不是硬性规定。如果使用别名能增强可读性,那就可以使用。


===========注释==================

良好的代码就是最好的注释。当你想要增加注释的时候,问问你自己,怎么样提高代码的质量那样就没有必要写注释呢?

1.如果可以写出高质量的代码,你可以忽略这节的其他部分。

2.注释比较长的话,请注意首字母大写,或者加标点符号。单词之间有空格。

3.避免冗余的注释

# bad
counter += 1 # increments counter by one


4.  保持注释是最新的。没有注释都比过期的注释好。

5. 避免写注释来解释烂代码。应该重构代码让他能够更加易读。


==========注解===================

1.   注解一般写在相关代码的上面。并且紧挨在一起。

2.   注解一般写在#和一个空白之后,然后描述问题

3.   如果注解要写多行,第二行必须在#之后缩进2个空白

def bar
  # FIXME: This has crashed occasionally since v3.2.1. It may
  #   be related to the BarBazUtil upgrade.
  baz(:quux)
end

4.   如果问题很明显,写任何的注解有点冗余。这时候可以写在代码后面,不需要写任何注解。这个是特殊情况不是规则。

def bar
  sleep 100 # OPTIMIZE
end

5.   TODO 一般是表示缺少某些功能,以后将会完成。

6.   FIXME 一般表示代码这块会引起中断,需要被解决。

7.   OPTIMIZE 一般表示这段代码效率有问题,有性能问题。

8.   HACK 表示感觉这段代码很可疑有问题,需要重构。

9.   REVIEW 表示这段代码需要被别人确认是否达到预期。

10.   如果合适的话,也可以用其他关键字表示注解。但是你一定要确保他们在你的readme文件或者其他类似文件里面进行详细说明。


==================类========================

1.  始终提供一个适当的方法to_s.

class Person
  attr_reader :first_name, :last_name

  def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
  end

  def to_s
    "#@first_name #@last_name"
  end
end

2.  利用attr的设定来定义琐碎的访问器或者存取器

3.  考虑增加工厂方法提供额外的方法来创建一个特定的类的实例。

4.  尽量使用鸭子类型而不是继承。(多态)

5.  避免使用@@类变量因为他们在继承里面会引起Bug。

6.  定义方法的时候请根据各个方法的使用范围确定他们的scope。到底是public,private,protect的请注明。而不是全部是public。

7. public,private,protect缩进是和方法缩进一样的。在上面要空一行。

8.  请使用self定义类方法。这样的话这些方法更有抵抗性。

class TestClass
  # bad
  def TestClass.some_method
    # body omitted
  end

  # good
  def self.some_other_method
    # body omitted
  end

  # Also possible and convenient when you
  # have to define many singleton methods.
  class << self
    def first_method
      # body omitted
    end

    def second_method_etc
      # body omitted
    end
  end
end

=============================异常===============================

1.  不要压制异常

2.  流程控制里面不要使用异常

3.  避免使用rescue Exception 类。

============================= 集合==============================

1.  少的元素的集合可以使用数组Array

2.  请用%w定义一个字符串数组

%w(foo bar baz) => [“foo”,”bar”,”baz”]

3.  避免创建的数组的元素有巨大差异

4.  如果有很多元素的话请使用Set而不是Array

5.  hash的key请用symbols而不是string

6.  避免使用动态的对象作为hash的key

7. 如果你使用ruby 1.9,请使用新的语法定义hash。而不是用旧的方式。

  # old way that still works in Ruby 1.9
  my_hash = { :a => 'apple', :b => 'banana' }

  # new way
  my_hash = { a: 'apple', b: 'banana' }

9.  在ruby 1.9里面hash的key不会自动排序了。按照插入的顺序的。

10.  遍历集合的时候,请不要修改他。


==========================字符串=======================================

1.  字符串连接尽量使用嵌入,而不是+号。

# bad
email_with_name = user.name + ' <' + user.email + '>'

# good
email_with_name = "#{user.name} <#{user.email}>"

2. 如果定义一个字符串,这个字符串不需要嵌入或者特殊字符的话,请用单引号字符串

# bad
name = "Bozhidar"

# good
name = 'Bozhidar'

3. 实例变量进行字符串嵌入的时候,{}花括号可以省略。

class Person
  attr_reader :first_name, :last_name

  def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
  end

  # bad
  def to_s
    "#{@first_name} #{@last_name}"
  end

  # good
  def to_s
    "#@first_name #@last_name"
  end
end

4. 字符串连接请用String#<< 而不是用String#+.连接字符串实例总比+要快。

因为+创建了一堆新字符串。

class Person
  attr_reader :first_name, :last_name

  def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
  end

  # bad
  def to_s
    "#{@first_name} #{@last_name}"
  end

  # good
  def to_s
    "#@first_name #@last_name"
  end
end

==================关于百分号=========================

1.  请自由使用%w

STATES = %w(draft open closed)

2.  需要字符串替换和双引号嵌入的字符串定义的话,请使用%().多行的字符串定义请使用定界符 <<.

# bad (no interpolation needed)
%(<div class="text">Some text</div>)
# should be '<div class="text">Some text</div>'

# bad (no double-quotes)
%(This is #{quality} style)
# should be "This is #{quality} style"

# bad (multiple lines)
%(<div>\n<span class="big">#{exclamation}</span>\n</div>)
# should be a heredoc.

print <<EOS
  the string
  next line
EOS

# good (requires interpolation, has quotes, single line)
%(<tr><td class="name">#{name}</td>)

3. 当你的正则表达式里面含有2个以上的/的字符的时候才使用 %r

# bad
%r(\s+)

# still bad
%r(^/(.*)$)
# should be /^\/(.*)$/

# good
%r(^/blog/2011/(.*)$)

4. 避免使用%q, %Q, %x,%s%W.

%Q 替代双引号

%q替代单引号

%s 定义symbols

%x 运行系统命令

%W 定义双引号的字符串数组

5. 对于所有的%请使用()作为分割符

==================杂项========================

1. 运行时候用 ruby –w来确保你的代码安全

2. 避免用hash作为方法的可选参数。是不是方法做的事情太多了。

3. 避免方法的长度超过10行。理想情况下,大多数方法是少于5行的。

  空行不包含在内。

4. 避免方法的参数太长。比如,3,4个参数。

5. 你如果想增加全局方法到内核里面。请保持他们是private的。

6. 使用实例变量代替全局变量

#bad
$foo_bar = 1

#good
class Foo
  class << self
    attr_accessor :bar
  end
end

Foo.bar = 1

7. 避免使用alias给方法起别名。而是使用alias_method.

8.使用OptionParser来解析复杂的命令行参数。以及使用ruby –s 来进行设定参数。

set the variable $opt to "electric".
% ruby -s prog -opt= electric ./mydata

9.  使用ruby 1.9的时候,请不要使用1.8的一些传统不好的语法

。使用javascript类似的hash语法

。使用新的lamda语法

。inject可以接受方法名作为参数

[1, 2, 3].inject(:+)

10.   避免不必要的metaprogramming

所谓的metaprogramming就是动态新建类的方法,增加类的属性等。

matz = Object.new
def matz.speak
  "Place your burden to machine's shoulders"
end
 
matz.class #=> Object












  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值