无意中在 ruby-china 的 wiki 看到了这篇有关 Ruby 编码风格的文章. http://ruby-china.org/wiki/coding-style 由于本人平常就很在意这些,大部分想法,都和我的 Ruby 笔记中的个人惯例部分 惊人的相似。看来我的代码风格,编码习惯应该不错。哈哈。
我见后半部分还没有翻译,我就补充上了。欢迎指正。
我就从Annotations
这个部分开始往下写了。前面的内容看原帖。
代码的注解
应该总是写在被注释代码的上面,并且紧贴被注释代码。
注解的标题
应该紧跟一个冒号以及一个空格,用来突出显示该注释描述的内容
.
如果需要多行注释,第二行注释应该在#
之后缩进两个空格。(译者注:以上两条规则在 Ruby 源码中都不多看到,前者在 Lisp 源码较多见,而后者从没见过)
def bar
# FIXME: This has crashed occasionally since v3.2.1. It may
# be related to the BarBazUtil upgrade.
baz(:quux)
end
def bar
sleep 100 # OPTIMIZE
end
使用TODO
标题描述 漏掉的功能或打算加入的新特性
使用FIXME
标题描述 需要被修复的有问题代码
使用OPTIMIZE
标题描述 可能有性能瓶颈,需要优化的代码。
使用HACK
标题描述 感觉上需要重构的代码
使用REVIEW
标题描述 关键性代码,需要稍后不断的检查该代码是否工作正确。
只要对阅读代码有帮助,也可以使用其他直白的
注解标题,但记得在 README 中注明。
当设计一个类时,务必记住LSP
原则。(译者注:LSP 原则大概含义为:如果一个函数中引用了`父类的实例', 则一定可以使用其子类的实例替代,并且函数的基本功能不变。(虽然功能允许被扩展)
尽量使你的类更加健壮,稳固。
为你自己的类定义 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
# bad
class Person
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
def first_name
@first_name
end
def last_name
@last_name
end
end
# good
class Person
attr_reader :first_name, :last_name
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
end
class Person
def self.create(options_hash)
# body omitted
end
end
# bad
class Animal
# abstract method
def speak
end
end
# extend superclass
class Duck < Animal
def speak
puts 'Quack! Quack'
end
end
# extend superclass
class Dog < Animal
def speak
puts 'Bau! Bau!'
end
end
# good
class Duck
def speak
puts 'Quack! Quack'
end
end
class Dog
def speak
puts 'Bau! Bau!'
end
end
class Parent
@@class_var = 'parent'
def self.print_class_var
puts @@class_var
end
end
class Child < Parent
@@class_var = 'child'
end
Parent.print_class_var # => will print "child"
正如上例看到的,所有的类实例共享类变量,并且可以直接修改类变量,此时使用类实例变量是更好的主意。
总是为类的实例方法定义适当的可见性.(private, protected, private) 不应该总是使用 public (默认可见性为 public), 这不是 Python!
可见性关键字应该和方法定义有相同的缩进,并且不同的关键字之间要空行分隔。
class SomeClass
def public_method
# ...
end
private
def private_method
# ...
end
end
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
begin
# an exception occurs here
rescue SomeError
# the rescue clause does absolutely nothing
end
# bad
begin
n / d
rescue ZeroDivisionError
puts "Cannot divide by 0!"
end
# good
if n.zero?
puts "Cannot divide by 0!"
else
n / d
# bad
begin
# an exception occurs here
rescue
# exception handling
end
# still bad
begin
# an exception occurs here
rescue Exception
# exception handling
end
# bad
begin
# some code
rescue Exception => e
# some handling
rescue StandardError => e
# some handling
end
# good
begin
# some code
rescue StandardError => e
# some handling
rescue Exception => e
# some handling
end
f = File.open("testfile")
begin
# .. process
rescue
# .. handle error
ensure
f.close unless f.nil?
end
# bad
STATES = ['draft', 'open', 'closed']
# good
STATES = %w(draft open closed)
arr = []
arr[100] = 1 # now you have an array with lots of nils
如果要确保元素唯一,则使用 Set 代替 Array.Set 更适合于无顺序的,并且元素唯一的集合. 集合具有类似于数组一致性操作以及哈希的快速查找。
尽可能使用 hash 代替字符串作为哈希键。
# bad
hash = { 'one' => 1, 'two' => 2, 'three' => 3 }
# good
hash = { one: 1, two: 2, three: 3 }
避免使用易变对象
作为哈希键。
应该尽可能的使用 Ruby1.9 的新哈希语法。
# bad
hash = { :one => 1, :two => 2, :three => 3 }
# good
hash = { one: 1, two: 2, three: 3 }
记住,在 Ruby1.9 中,哈希的表现不再是无序的。(译者注:Ruby1.9 将会记住元素插入的序列)
当遍历一个集合的同时,不要修改这个集合。
字符串插值
来代替字符串串联
.# bad
email_with_name = user.name + ' <' + user.email + '>'
# good
email_with_name = "#{user.name} <#{user.email}>"
# bad
name = "Bozhidar"
# good
name = 'Bozhidar'
实例变量
时,应该省略{}.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
+
, 如果需要修改被操作字符串,应该总是使用<<
作为代替。# good and also fast
html = ''
html << '<h1>Page title</h1>'
paragraphs.each do |paragraph|
html << "<p>#{paragraph}</p>"
end
如果只是需要查找普通字符串,不要使用 RE. 例如:string['text'] (译者注:示例什么意思?)
针对简单的结构,你可以直接使用 string[/RE/] 的方式来查询。(译者注:string[] 难道是新添加的语法?)
match = string[/regexp/] # get content of matched regexp
first_group = string[/text(grp)/, 1] # get content of captured group
string[/text (grp)/, 1] = 'replace' # string => 'text replace'
/(first|second)/ # bad
/(?:first|second)/ # good
命名分组
来代替。# bad
/(regexp)/ =~ string
...
process $1
# good
/(?<meaningful_var>regexp)/ =~ string
...
process meaningful_var
有关 RE 集合 [...], 他们只有以下几个特殊关键字值得注意:^, -, \, ]
所以,不要在集合中,转义.
或者[
, 他们是正常字符。
注意,^
和$
, 他们匹配行首和行尾,而不是一个字符串的结尾.
如果你想匹配整个字符串,用\A和\E. (译者注,A 和 Z 分别为英文的第一个和最后一个字符)
string = "some injection\nusername"
string[/^username$/] # matches
string[/\Ausername\Z/] # don't match
regexp = %r{
start # some text
\s # white space char
(group) # first group
(?:alt1|alt2) # some alternation
end
}x
哈希
以及代码块
形式语法,可用于复杂情形下的替换操作.
* * * * *应该大量的使用%w.
应该使用%() 的方式,来定义需要字符串插值
以及包含"符号
的单行字符串.
多行字符串,尽量使用 here doc 格式。(译者注:我好喜欢%() 的方式,可能是%() 比%{}写起来方便的缘故)
# 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.
# good (requires interpolation, has quotes, single line)
%(<tr><td class="name">#{name}</td>)
包含多个/符号
的正则表达式。# bad
%r(\s+)
# still bad
%r(^/(.*)$)
# should be /^\/(.*)$/
# good
%r(^/blog/2011/(.*)$)
尽量避免%q, %Q, %x, %s, 和%W.
优先使用 () 作为%类语法格式的分隔符. (译者注,本人很喜欢%(...), 不过 Programming Ruby 中,显然更喜欢使用%{}的方式)
总是打开 Ruby -w 开关。应该写没有警告提示的代码。
通常情况下,尽量避免使用哈希作为方法参数。(此时应该考虑这个方法是不是功能太多?)
避免一个方法内容超过 10 行代码,理想情况下,大多数方法内容应该少于 5 行.(不算空行)
尽量避免方法的参数超过三个。
有时候,必须用到全局方法,应该增加这些方法到 Kernel 模块。
尽可能使用类实例变量
代替全局变量。(译者注:是类实例变量
, 而不是类的实例变量
. 汗~~)
#bad
$foo_bar = 1
#good
class Foo
class << self
attr_accessor :bar
end
end
Foo.bar = 1
尽可能的使用 alias_method 代替 alias.
使用OptionParser
来解析复杂的命令行选项,较简单的命令行,-s 参数即可处理。
按照功能来编写方法,当方法名有意义时,应该避免方法功能被唐突的改变。
避免不需要的元编程。
除非必要,避免更改已经定义的方法的参数。
避免超过三级的代码块嵌套。
应该持续性的遵守以上指导方针。
尽量使用 (生活中的) 常识。(译者注:这应该是编程的最高境界?)