# TITLE: # # Hash Operators # # SUMMARY: # # Operators for common methods, such as merge and update, # plus some usefule variaions like reverse_merge. # # CREDITS: # # - Thomas Sawyer # # TODO: # # - Rewrite #diff to be more readable. # - Rename #diff to #difference or something else? # class Hash # Can be used like update, or passed # as two-element [key,value] array. def <<(other) if other.respond_to?(:to_ary) self.store(*other) else update(other) end end # Hash intersection. Two hashes intersect # when their pairs are equal. # # {:a=>1,:b=>2} & {:a=>1,:c=>3} #=> {:a=>1} # # A hash can also be intersected with an array # to intersect keys only. # # {:a=>1,:b=>2} & [:a,:c] #=> {:a=>1} # # The later form is similar to #pairs_at. The differ only # in that #pairs_at will return a nil value for a key # not in the hash, but #& will not. def &(other) case other when Array k = (keys & other) Hash[*(k.zip(values_at(*k)).flatten)] else x = (to_a & other.to_a).inject([]) do |a, kv| a.concat kv; a end Hash[*x] end end # Operator for reverse_merge. def |(other) other.merge(self) end # Operator for merge. def +(other) merge(other) end # Operator for remove hash paris. If another hash is given # the pairs are only removed if both key and value are equal. # If an array is given then mathcing keys are removed. def -(other) h = self.dup if other.respond_to?(:to_ary) other.to_ary.each do |k| h.delete(k) end else other.each do |k,v| if h.key?(k) h.delete(k) if v == h[k] end end end h end # Like merge operator '+' but merges in reverse order. # # h1 = { :a=>1 } # h2 = { :a=>2, :b=>3 } # # h1 + h2 #=> { :a=>2, :b=>3 } # h1 * h2 #=> { :a=>1, :b=>3 } def *(other) other.merge(self) end # Difference comparison of two hashes. def diff(h2) dup.send(:delete_if){|k,v| h2[k] == v}.send(:merge,h2.dup.send(:delete_if){ |k,v| has_key?(k) }) end end # _____ _ # |_ _|__ ___| |_ # | |/ _ \/ __| __| # | | __/\__ \ |_ # |_|\___||___/\__| # =begin test require 'test/unit' class TestHashOperate < Test::Unit::TestCase def test_op_and_hash a = { :a => 1, :b => 2 } b = { :a => 1 } r = { :a => 1 } assert_equal( r, a & b ) end def test_op_and_hash_subarray a = { :a => [1], :b => [2] } b = { :a => [1] } r = { :a => [1] } assert_equal( r, a & b ) end def test_op_and_array a = { :a => 1, :b => 2 } b = [ :a ] r = { :a => 1 } assert_equal( r, a & b ) end def test_shift_update a = { :a => 1, :b => 2, :c => 3 } b = { :a => 0, :d => 4 } e = { :a => 0, :b => 2, :c => 3, :d => 4 } assert_equal( e, a << b ) end end =end