Tap
從 source code 可以看出最後會傳回 self
以下分成兩個用途,分別介紹如何運用此特性
用途一:調測
在使用 chain 時,要查看某個過程的內容,可以使用 #tap
印出內容,卻又不會影響執行
1
2
3
4
| (1..10) .tap {|x| puts "original: #{x.inspect}"}
.to_a .tap {|x| puts "array: #{x.inspect}"}
.select {|x| x%2==0} .tap {|x| puts "evens: #{x.inspect}"}
.map { |x| x*x } .tap {|x| puts "squares: #{x.inspect}"}
|
用途二:簡化代碼
可用在建立一個方法,要傳回一個 String/Array/Hash 的結果
1
2
| [].tap {|i| i << "abc"}
''.tap {|i| i << do_some_thing }
|
Reference
Fetch
取不到值時,會以預設值取代,但沒設定預設值會出現 Error
Hash / Array 皆有實作 #fetch
Array#fetch
1
2
3
4
5
6
| a = [ 11, 22, 33, 44 ]
a.fetch(1) #=> 22
a.fetch(-1) #=> 44
a.fetch(4, 'cat') #=> "cat"
a.fetch(4) { |i| i*i } #=> 16
a.fetch(5) #=> IndexError
|
Hash#fetch
1
2
3
4
5
| h = { "a" => 100, "b" => 200 }
h.fetch("a") #=> 100
h.fetch("z", "go fish") #=> "go fish"
h.fetch("z") { |el| "go fish, #{el}"} #=> "go fish, z"
h.fetch("z") #=> KeyError
|
Reference
Dig
適用在多層
跟 #try 一樣,如果其中一層為 nil,會回傳 nil 而不會出現 Error
Ruby 2.3.0
Hash / Array 皆有實作 #dig
Array#dig
1
2
3
4
| a = [[1, [2, 3]]]
a.dig(0, 1, 1) #=> 3
a.dig(0, 0, 0) #=> nil
|
Hash#dig
在 rails 取 params 時,會使用以下方式取值
1
| name = params[:company][:owner][:name]
|
要避免遇到 nil,可改寫成
1
| name = params[:company][:owner][:name] if params[:company] && params[:company][:owner] && params[:company][:owner][:name]
|
使用 #dig 處理
1
| name = params.dig(:company, :owner, :name)
|
同樣 case 用 #try
的 chain,看來使用 #dig
比較適合
1
| params.try(:[], :company).try(:[], :owner).try(:[], :name)
|
Reference
try
同場加映,#try
是屬於 Rails Object method
等同 Object#send
,但 object 為 nil 時,呼叫 method 會出現 NoMethodError exception
但使用 #try
,object 為 nil 時,會回傳 nil ,而不會出現 NoMethodError exception
因此是一個相當實用的功能
最常見的例子像是我們想判斷某些動作只有管理員可以進行操作,因此我們通常會這樣寫
1
2
3
| if current_user.is_admin?
# do something
end
|
但總會遇到 current_user 有 nil 的時候,這時就適合用 #try
確認 current_user 是否為 nil,再去呼叫 #is_admin?
1
2
3
| if current_user.try(:is_admin?)
# do something
end
|
#try
也可以實現 block,如果 instance object 不為 nil
1
| @person.try { |p| "#{p.first_name}" "#{p.last_name}" }
|
Reference