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!