Active Support 針對 Ruby 裡面許多的 Class 增加了很多方便的工具給你使用。
最近開始閱讀 Rails 的 source code ,目前先以比較簡單的部分為主軸。
今天要解析 Active Support 針對 Hash 提供的 compact
以及 compact!
這兩個 method 。
原始碼在這裡: /activesupport/lib/active_support/core_ext/hash/compact.rb
compact 以及 compact! 的用途
這兩個 method 的主要用途為:把一個 hash 當中,值為 nil
者排除。
compact
傳回的是排除 nil 的新 hash ,也就是說原來的 hash 不會更動:
hash = { a: true, b: false, c: nil}
hash.compact # => { a: true, b: false}
hash # => { a: true, b: false, c: nil}
而 compact!
則會直接更改原來的 hash :
hash = { a: true, b: false, c: nil}
hash.compact! # => { a: true, b: false}
hash # => { a: true, b: false}
解析原始碼
class Hash
def compact
self.select { |_, value| !value.nil? }
end
def compact!
self.reject! { |_, value| value.nil? }
end
end
原理非常簡單,只要了解 select
以及 reject!
這兩個 method 的功用就可以輕易看懂。
官方文件針對 select 的說明是:
把在 block 中返回值為 true 的所有項目集合起來、組成一個新 hash。
如下:
h = { "a" => 100, "b" => 200, "c" => 300 }
h.select {|k,v| k > "a"} #=> {"b" => 200, "c" => 300}
而官方文件針對 reject! 的說明如下:
等同於 Hash#delete_if ,不過如果沒有更動到什麼的話會返回 nil。
看說明便可以知道 delete_if
這個 method 會把在 block 中為 true 的所有項目都刪除。例如:
h = { "a" => 100, "b" => 200, "c" => 300 }
h.delete_if {|key, value| key >= "b" }
puts h #=> {"a"=>100}
因此簡單來說 compact
會把所有非 nil 的項目組合成一個新 hash,而 compact!
則會把原 hash 中所有為 nil 的項目刪除。