Skip to content

Instantly share code, notes, and snippets.

@IronSavior
Last active August 29, 2015 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IronSavior/d551415c862d84de45c9 to your computer and use it in GitHub Desktop.
Save IronSavior/d551415c862d84de45c9 to your computer and use it in GitHub Desktop.
Simple diff methods for Hash or other Enumerable
# Author: Erik Elmore <erik@erikelmore.com>
# License: Public Domain
# Enable "diffing" and two-way transformations between collection objects
module Diffable
# Calculates the changes required to transform self to the given collection.
# @param b [Enumerable] The other collection object
# @return [Array] The Diff: A two-element change set representing items to exclude and items to include
def diff( b )
a, b = to_a, b.to_a
[a - b, b - a]
end
# Consume return value of Diffable#diff to produce a collection equal to the one used to produce the given diff.
# @param to_drop [Enumerable] items to exclude from the target collection
# @param to_add [Enumerable] items to include in the target collection
# @return [Array] New transformed collection equal to the one used to create the given change set
def apply_diff( to_drop, to_add )
to_a - to_drop + to_add
end
end
if __FILE__ == $0
# Demo: Hashes with overlapping keys and somewhat random values.
Hash.send :include, Diffable
rng = Random.new
a = (:a..:q).reduce(Hash[]){|h,k| h.merge! Hash[k, rng.rand(2)] }
b = (:i..:z).reduce(Hash[]){|h,k| h.merge! Hash[k, rng.rand(2)] }
raise unless a == Hash[ b.apply_diff(*b.diff(a)) ] # change b to a
raise unless b == Hash[ a.apply_diff(*a.diff(b)) ] # change a to b
raise unless a == Hash[ a.apply_diff(*a.diff(a)) ] # change a to a
raise unless b == Hash[ b.apply_diff(*b.diff(b)) ] # change b to b
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment