Permalink
Browse files

delete_merge!

remove a hash from another hash
- works with deeply nested hash
- works with hash containing arrays
  • Loading branch information...
1 parent 436d918 commit 5f3410e04fe8c4d4745397db866c9633b80ccec6 Michael Elfassy committed Apr 8, 2013
@@ -1,5 +1,6 @@
require 'active_support/core_ext/hash/conversions'
require 'active_support/core_ext/hash/deep_merge'
+require 'active_support/core_ext/hash/delete_merge'
require 'active_support/core_ext/hash/diff'
require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/hash/indifferent_access'
@@ -0,0 +1,32 @@
+class Hash
+ # Returns a hash that removes any matches with the other hash
+ #
+ # {a: {b:"c"}} - {:a=>{:b=>"c"}} # => {}
+ # {a: [{c:"d"},{b:"c"}]} - {:a => [{c:"d"}, {b:"d"}]} # => {:a=>[{:b=>"c"}]}
+ #
+ def delete_merge!(other_hash)
+ other_hash.each_pair do |k,v|
+ tv = self[k]
+ if tv.is_a?(Hash) && v.is_a?(Hash) && v.present? && tv.present?
+ tv.delete_merge!(v)
+ elsif v.is_a?(Array) && tv.is_a?(Array) && v.present? && tv.present?
+ v.each_with_index do |x, i|
+ tv[i].delete_merge!(x)
+ end
+ self[k] = tv - [{}]
+ else
+ self.delete(k) if self.has_key?(k) && tv == v
+ end
+ self.delete(k) if self.has_key?(k) && self[k].blank?
+ end
+ self
+ end
+
+ def delete_merge(other_hash)
+ dup.delete_merge!(other_hash)
+ end
+
+ def -(other_hash)
+ self.delete_merge(other_hash)
+ end
+end
@@ -616,6 +616,30 @@ def test_deep_merge_on_indifferent_access
assert_equal expected, hash_1
end
+ def test_delete_merge
+ hash_1 = { :a => "a", :b => "b", :c => { :c1 => "c1", :c2 => "c2", :c3 => { :d1 => "d1" } } }
+ hash_2 = { :a => 1, :b => "b", :c => { :c3 => { :d1 => "d1", :d2 => "d2" } } }
+ expected_1 = {:a=>"a", :c=>{:c1=>"c1", :c2=>"c2"}}
+ expected_2 = {:a=>1, :c=>{:c3=>{:d1=>"d1", :d2=>"d2"}}}
+ assert_equal expected_1, hash_1.delete_merge(hash_2)
+ assert_equal expected_2, hash_2.delete_merge(hash_1)
+
+ hash_1.delete_merge!(hash_2)
+ assert_equal expected_1, hash_1
+ end
+
+ def test_delete_merge_on_indifferent_access
+ hash_1 = HashWithIndifferentAccess.new({ :a => "a", :b => "b", :c => { :c1 => "c1", :c2 => "c2", :c3 => { :d1 => "d1" } } })
+ hash_2 = HashWithIndifferentAccess.new({ :a => 1, :b => "b", :c => { :c3 => { :d1 => "d1", :d2 => "d2" } } })
+ expected_1 = {"a"=>"a", "c"=>{"c1"=>"c1", "c2"=>"c2"}}
+ expected_2 = {"a"=>1, "c"=>{"c3"=>{"d1"=>"d1", "d2"=>"d2"}}}
+ assert_equal expected_1, hash_1.delete_merge(hash_2)
+ assert_equal expected_2, hash_2.delete_merge(hash_1)
+
+ hash_1.delete_merge!(hash_2)
+ assert_equal expected_1, hash_1
+ end
+
def test_store_on_indifferent_access
hash = HashWithIndifferentAccess.new
hash.store(:test1, 1)

0 comments on commit 5f3410e

Please sign in to comment.