使用 :: 引用常量(包括類和模塊)和構(gòu)造器 (比如 Array() 或者 Nokogiri::HTML())。
永遠(yuǎn)不要使用 :: 來調(diào)用方法。
# bad
SomeClass::some_method
some_object::some_method
# good
SomeClass.some_method
some_object.some_method
SomeModule::SomeClass::SOME_CONST
SomeModule::SomeClass()
使用括號將def的參數(shù)括起來。當(dāng)方法不接收任何參數(shù)的時候忽略括號。
# bad
def some_method()
# body omitted
end
# good
def some_method
# body omitted
end
# bad
def some_method_with_arguments arg1, arg2
# body omitted
end
# good
def some_method_with_arguments(arg1, arg2)
# body omitted
end
從來不要使用 for, 除非你知道使用它的準(zhǔn)確原因。大多數(shù)時候迭代器都可以用來替for。for 是由一組 each 實現(xiàn)的 (因此你正間接添加了一級),但是有一個小道道 - for并不包含一個新的 scope (不像 each)并且在它的塊中定義的變量在外面也是可以訪問的。
arr = [1, 2, 3]
# bad
for elem in arr do
puts elem
end
# note that elem is accessible outside of the for loop
elem #=> 3
# good
arr.each { |elem| puts elem }
# elem is not accessible outside each's block
elem #=> NameError: undefined local variable or method `elem'
在多行的 if/unless 中堅決不要使用 then。
# bad
if some_condition then
# body omitted
end
# good
if some_condition
# body omitted
end
在多行的 if/unless 總是把條件放在與 if/unless 的同一行。
# bad
if
some_condition
do_something
do_something_else
end
# good
if some_condition
do_something
do_something_else
end
喜歡三元操作運(yùn)算(?:)超過if/then/else/end結(jié)構(gòu)。
它更加普遍而且明顯的更加簡潔。
# bad
result = if some_condition then something else something_else end
# good
result = some_condition ? something : something_else
使用一個表達(dá)式在三元操作運(yùn)算的每一個分支下面只使用一個表達(dá)式。也就是說三元操作符不要被嵌套。在這樣的情形中寧可使用 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
不要使用 if x: ... - 它在Ruby 1.9中已經(jīng)移除。使用三元操作運(yùn)算代替。
# bad
result = if some_condition then something else something_else end
# good
result = some_condition ? something : something_else
不要使用 if x; ...。使用三元操作運(yùn)算代替。
利用 if and case 是表達(dá)式這樣的事實它們返回一個結(jié)果。
# bad
if condition
result = x
else
result = y
end
# good
result =
if condition
x
else
y
end
在 one-line cases 的時候使用 when x then ...。替代的語法when x: xxx已經(jīng)在Ruby 1.9中移除。
不要使用when x; ...。查看上面的規(guī)則。
使用 ! 替代 not.
# 差 - 因為操作符有優(yōu)先級,需要用括號。
x = (not something)
# good
x = !something
避免使用 !!.
# bad
x = 'test'
# obscure nil check
if !!x
# body omitted
end
x = false
# double negation is useless on booleans
!!x # => false
# good
x = 'test'
unless x.nil?
# body omitted
end
The and and or keywords are banned. It's just not worth
it. Always use and || instead.
and 和 or 這兩個關(guān)鍵字被禁止使用了。它名不符實??偸鞘褂? 和 || 來取代。
# bad
# boolean expression
if some_condition and some_other_condition
do_something
end
# control flow
document.saved? or document.save!
# good
# boolean expression
if some_condition some_other_condition
do_something
end
# control flow
document.saved? || document.save!
避免多行的 ? :(三元操作符);使用 if/unless 來取代。
單行主體喜歡使用 if/unless 修飾符。另一個好方法是使用 /|| 控制流程。
# bad
if some_condition
do_something
end
# good
do_something if some_condition
# another good option
some_condition do_something
布爾表達(dá)式使用/||, and/or用于控制流程。(經(jīng)驗Rule:如果你必須使用額外的括號(表達(dá)邏輯),那么你正在使用錯誤的的操作符。)
# boolean expression
if some_condition some_other_condition
do_something
end
# control flow
document.save? or document.save!
避免多行?:(三元操作運(yùn)算),使用 if/unless 替代。
在單行語句的時候喜愛使用 if/unless 修飾符。另一個好的選擇就是使 and/or 來做流程控制。
# bad
if some_condition
do_something
end
# good
do_something if some_condition
# another good option
some_condition and do_something
永遠(yuǎn)不要使用 unless 和 else 組合。將它們改寫成肯定條件。
# bad
unless success?
puts 'failure'
else
puts 'success'
end
# good
if success?
puts 'success'
else
puts 'failure'
end
不用使用括號包含 if/unless/while 的條件。
# bad
if (x > 10)
# body omitted
end
# good
if x > 10
# body omitted
end
在多行 while/until 中不要使用 while/until condition do 。
# bad
while x > 5 do
# body omitted
end
until x > 5 do
# body omitted
end
# good
while x > 5
# body omitted
end
until x > 5
# body omitted
end
當(dāng)你有單行主體時,盡量使用 while/until 修飾符。
# bad
while some_condition
do_something
end
# good
do_something while some_condition
否定條件判斷盡量使用 until 而不是 while 。
# bad
do_something while !some_condition
# good
do_something until some_condition
循環(huán)后條件判斷使用 Kernel#loop 和 break,而不是 begin/end/until 或者 begin/end/while。
# bad
begin
puts val
val += 1
end while val 0
# good
loop do
puts val
val += 1
break unless val 0
end
忽略圍繞內(nèi)部 DSL 方法參數(shù)的括號 (如:Rake, Rails, RSpec),Ruby 中帶有 "關(guān)鍵字" 狀態(tài)的方法(如:attr_reader,puts)以及屬性存取方法。所有其他的方法調(diào)用使用括號圍繞參數(shù)。
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)
bowling.score.should == 0
忽略隱式選項 hash 外部的花括號。
# bad
user.set({ name: 'John', age: 45, permissions: { read: true } })
# good
user.set(name: 'John', age: 45, permissions: { read: true })
內(nèi)部 DSL 方法的外部括號和大括號。
class Person ActiveRecord::Base
# bad
validates(:name, { presence: true, length: { within: 1..10 } })
# good
validates :name, presence: true, length: { within: 1..10 }
end
方法調(diào)用不需要參數(shù),那么忽略圓括號。
# bad
Kernel.exit!()
2.even?()
fork()
'test'.upcase()
# good
Kernel.exit!
2.even?
fork
'test'.upcase
在單行代碼塊的時候?qū)幵甘褂?{...} 而不是 do...end。避免在多行代碼塊使用 {...} (多行鏈?zhǔn)酵ǔW兊梅浅3舐?。通常使用 do...end 來做 流程控制 和 方法定義 (例如 在 Rakefiles 和某些 DSLs 中)。避免在鏈?zhǔn)秸{(diào)用中使用 do...end。
names = ['Bozhidar', 'Steve', 'Sarah']
# bad
names.each do |name|
puts name
end
# good
names.each { |name| puts name }
# bad
names.select do |name|
name.start_with?('S')
end.map { |name| name.upcase }
# good
names.select { |name| name.start_with?('S') }.map { |name| name.upcase }
有人會爭論多行鏈?zhǔn)娇雌饋砗褪褂?{...} 一樣工作,但是他們問問自己 - 這樣的代碼真的有可讀性碼并且為什么代碼塊中的內(nèi)容不能被提取到美麗的方法中。
Consider using explicit block argument to avoid writing block
literal that just passes its arguments to another block. Beware of
the performance impact, though, as the block gets converted to a
Proc.
考慮使用明確的塊參數(shù)來避免寫入的塊字面量僅僅傳遞參數(shù)的給另一個塊。小心性能的影響,即使,
塊被轉(zhuǎn)換成了 Proc。
require 'tempfile'
# bad
def with_tmp_dir
Dir.mktmpdir do |tmp_dir|
Dir.chdir(tmp_dir) { |dir| yield dir } # block just passes arguments
end
end
# good
def with_tmp_dir(block)
Dir.mktmpdir do |tmp_dir|
Dir.chdir(tmp_dir, block)
end
end
with_tmp_dir do |dir|
puts "dir is accessible as parameter and pwd is set: #{dir}"
end
避免在不需要流的控制使用 return。
# bad
def some_method(some_arr)
return some_arr.size
end
# good
def some_method(some_arr)
some_arr.size
end
避免在不需要的地方使用 self(它僅僅在調(diào)用一些 self 做寫訪問的時候需要)(It is only required when calling a self write accessor.)
# bad
def ready?
if self.last_reviewed_at > self.last_updated_at
self.worker.update(self.content, self.options)
self.status = :in_progress
end
self.status == :verified
end
# good
def ready?
if last_reviewed_at > last_updated_at
worker.update(content, options)
self.status = :in_progress
end
status == :verified
end
作為一個必然的結(jié)果,避免將方法(參數(shù))放于局部變量陰影之下除非它們是相等的。
class Foo
attr_accessor :options
# ok
def initialize(options)
self.options = options
# both options and self.options are equivalent here
end
# bad
def do_something(options = {})
unless options[:when] == :later
output(self.options[:message])
end
end
# good
def do_something(params = {})
unless params[:when] == :later
output(options[:message])
end
end
end
不要在條件表達(dá)式里使用 = (賦值)的返回值,除非條件表達(dá)式在圓括號內(nèi)被賦值。
這是一個相當(dāng)流行的 ruby 方言,有時被稱為 safe assignment in condition。
# bad (+ a warning)
if v = array.grep(/foo/)
do_something(v)
...
end
# good (MRI would still complain, but RuboCop won't)
if (v = array.grep(/foo/))
do_something(v)
...
end
# good
v = array.grep(/foo/)
if v
do_something(v)
...
end
在任何可以的地方使用快捷的 self assignment 操作符。
# bad
x = x + y
x = x * y
x = x**y
x = x / y
x = x || y
x = x y
# good
x += y
x *= y
x **= y
x /= y
x ||= y
x = y
只有在變量沒有被初始化的時候使用 ||= 來初始化變量。
# set name to Vozhidar, only if it's nil or false
name ||= 'Bozhidar'
不要使用||=來初始化布爾變量。(想想如果當(dāng)前值為false的時候會發(fā)生什么。)
# bad - would set enabled to true even if it was false
enable ||= true
# good
enabled = true if enabled.nil?
使用 = 來預(yù)處理變量不確定是否存在的變量。使用 = 僅僅在(變量)存在的時候
才會改變值,除去了使用 if 來檢查它的存在性。
# bad
if something
something = something.downcase
end
# bad
something = something ? nil : something.downcase
# ok
something = something.downcase if something
# good
something = something something.downcase
# better
something = something.downcase
避免全等(case equality)=== 操作符的使用。從名稱可知,這是 case 表達(dá)式的隱式使用并且在 case 語句外的場合使用會產(chǎn)生難以理解的代碼。
# bad
Array === something
(1..100) === 7
/something/ === some_string
# good
something.is_a?(Array)
(1..100).include?(7)
some_string =~ /something/
避免使用 Perl 的指定變量風(fēng)格(比如,$:,$; 等等。)。它們相當(dāng)神秘,不鼓勵在單行代碼之外使用它們。
使用 English 庫提供的友好別名。
# bad
$:.unshift File.dirname(__FILE__)
# good
require 'English'
$LOAD_PATH.unshift File.dirname(__FILE__)
從來不要在方法名和(參數(shù))開括號之間使用空格。
# bad
f (3+2) + 1
# good
f(3 + 2) +1
如果方法的第一個參數(shù)以開括號開始,通常使用括號把它們?nèi)坷ㄆ饋?。例如f((3 + 2) + 1)。
通常使用 -w 選項運(yùn)行 Ruby 解釋器,在你忘記上面所訴規(guī)則,ruby 將會提示你。
定義單行塊使用新的 lambda 語法。定義多行塊中使用 lambda 方法。
# bad
l = lambda { |a, b| a + b }
l.call(1, 2)
# correct, but looks extremely awkward
l = ->(a, b) do
tmp = a * 7
tmp * b / 50
end
# good
l = ->(a, b) { a + b }
l.call(1, 2)
l = lambda do |a, b|
tmp = a * 7
tmp * b / 50
end
用 proc 而不是 Proc.new。
# bad
p = Proc.new { |n| puts n }
# good
p = proc { |n| puts n }
匿名方法 和 塊 用 proc.call() 而不是 proc[] 或 proc.()。
# bad - looks similar to Enumeration access
l = ->(v) { puts v }
l[1]
# also bad - uncommon syntax
l = ->(v) { puts v }
l.(1)
# good
l = ->(v) { puts v }
l.call(1)
未使用的塊參數(shù)和局部變量使用 _。它也可以接受通過 _ 來使用(即使它有少了些描述性)。
這個慣例由 Ruby 解釋器以及 RuboCop 這樣的工具組織其將會抑制它們的未使用參數(shù)警告。
# bad
result = hash.map { |k, v| v + 1 }
def something(x)
unused_var, used_var = something_else(x)
# ...
end
# good
result = hash.map { |_k, v| v + 1 }
def something(x)
_unused_var, used_var = something_else(x)
# ...
end
# good
result = hash.map { |_, v| v + 1 }
def something(x)
_, used_var = something_else(x)
# ...
end
使用 $stdout/$stderr/$stdin 而不是 STDOUT/STDERR/STDIN。STDOUT/STDERR/STDIN 是常量,雖然在 Ruby 中是可以給常量重新賦值的(可能是重定向到某個流),但解釋器會警告如果你執(zhí)意這樣。
使用 warn 而不是 $stderr.puts。除了更加清晰簡潔,如果你需要的話,
warn 還允許你抑制(suppress)警告(通過 -W0 將警告級別設(shè)為 0)。
傾向使用 sprintf 和它的別名 format 而不是相當(dāng)隱晦的 String#% 方法.
# bad
'%d %d' % [20, 10]
# => '20 10'
# good
sprintf('%d %d', 20, 10)
# => '20 10'
# good
sprintf('%{first} %{second}', first: 20, second: 10)
# => '20 10'
format('%d %d', 20, 10)
# => '20 10'
# good
format('%{first} %{second}', first: 20, second: 10)
# => '20 10'
傾向使用 Array#join 而不是相當(dāng)隱晦的使用字符串作參數(shù)的 Array#*。
# bad
%w(one two three) * ', '
# => 'one, two, three'
# good
%w(one two three).join(', ')
# => 'one, two, three'
當(dāng)處理你希望像 Array 那樣對待的變量,但是你不確定它是一個數(shù)組時,
使用 [*var] or Array() 而不是顯式的 Array 檢查。
# bad
paths = [paths] unless paths.is_a? Array
paths.each { |path| do_something(path) }
# good
[*paths].each { |path| do_something(path) }
# good (and a bit more readable)
Array(paths).each { |path| do_something(path) }
盡量使用范圍或 Comparable#between? 來替換復(fù)雜的邏輯比較。
# bad
do_something if x >= 1000 x = 2000
# good
do_something if (1000..2000).include?(x)
# good
do_something if x.between?(1000, 2000)
盡量用謂詞方法而不是使用 ==。比較數(shù)字除外。
# bad
if x % 2 == 0
end
if x % 2 == 1
end
if x == nil
end
# good
if x.even?
end
if x.odd?
end
if x.nil?
end
if x.zero?
end
if x == 0
end
避免使用 BEGIN 區(qū)塊。
使用 Kernel#at_exit 。永遠(yuǎn)不要用 END 區(qū)塊。
# bad
END { puts 'Goodbye!' }
# good
at_exit { puts 'Goodbye!' }
避免使用 flip-flops 。
避免使用嵌套的條件來控制流程。
當(dāng)你可能斷言不合法的數(shù)據(jù),使用一個防御語句。一個防御語句是一個在函數(shù)頂部的條件聲明,這樣如果數(shù)據(jù)不合法就能盡快的跳出函數(shù)。
# bad
def compute_thing(thing)
if thing[:foo]
update_with_bar(thing)
if thing[:foo][:bar]
partial_compute(thing)
else
re_compute(thing)
end
end
end
# good
def compute_thing(thing)
return unless thing[:foo]
update_with_bar(thing[:foo])
return re_compute(thing) unless thing[:foo][:bar]
partial_compute(thing)
end
您可能感興趣的文章:- Ruby語法筆記
- Ruby的基礎(chǔ)語法入門學(xué)習(xí)教程
- Ruby基礎(chǔ)語法初探
- Ruby中一些基本語法知識點的羅列匯總
- ruby聲明式語法的實現(xiàn)例子
- Ruby的基本語法學(xué)習(xí)總結(jié)
- ruby 學(xué)習(xí)筆記(1) 初識語法
- Ruby的語法和語言特性總結(jié)