RubyでHash(JSON)の差分更新
Ruby 2.7.0がリリースされ、パターンマッチングが入ったということで差分データを元にデータを更新するような処理を書いてみる
実装
# hash.rb
require 'active_support/all'
class Hash
def merge_diff!(diff)
diff.each do |k, v|
case [self[k], v]
in [Hash, Hash] then self[k].merge_diff!(v)
in [_, Hash] then self[k] = {}.merge_diff!(v)
in [_, NilClass] then delete(k)
else self[k] = v
end
end
self
end
def merge_diff(diff)
deep_dup.merge_diff!(diff)
end
end
テスト
# test.rb
require './hash.rb'
require 'test/unit'
class TestMergeDiff < Test::Unit::TestCase
def test_merge_diff!
origin = {
a: 1,
b: 2,
c: { ca: 1 },
d: { da: 1, db: { dba: 1 } }
}
diff = {
a: 5,
d: { da: 10 },
e: 5
}
answer = {
a: 5,
b: 2,
c: { ca: 1 },
d: { da: 10, db: { dba: 1 } },
e: 5
}
assert_equal answer, origin.merge_diff!(diff)
end
def test_merge_diff
origin = {
a: 1,
b: 2,
c: { ca: 1 },
d: { da: 1, db: { dba: 1 } }
}
diff = {
c: { ca: 10, cb: { cba: 1 } },
d: { db: { dba: 2, dbb: 5 } }
}
answer = {
a: 1,
b: 2,
c: { ca: 10, cb: { cba: 1 } },
d: { da: 1, db: { dba: 2, dbb: 5 } }
}
assert_equal answer, origin.merge_diff(diff)
end
end
パターンマッチング非常に便利。
追記
ActiveSupportにHash#deep_merge
という今回実装したものと同じものが存在するので無駄な実装になった…Ruby力が足りてない…
Thanks for reading!