module EasyDiff::Core

Public Class Methods

_blank?(obj) click to toggle source

Can’t use regular empty? because that affects strings.

# File lib/easy_diff/core.rb, line 77
def self._blank?(obj)
  if obj.is_a?(Hash) || obj.is_a?(Array)
    obj.empty?
  else
    obj.nil?
  end
end
easy_clone(original) click to toggle source
# File lib/easy_diff/core.rb, line 72
def self.easy_clone(original)
  Marshal::load(Marshal.dump(original))
end
easy_diff(original, modified) click to toggle source
# File lib/easy_diff/core.rb, line 3
def self.easy_diff(original, modified)
  removed = nil
  added   = nil

  if original.nil?
    added = modified.safe_dup

  elsif modified.nil?
    removed = original.safe_dup

  elsif original.is_a?(Hash) && modified.is_a?(Hash)
    removed = {}
    added   = {}

    keys_in_common  = original.keys & modified.keys
    keys_removed    = original.keys - modified.keys
    keys_added      = modified.keys - original.keys

    keys_removed.each{ |key| removed[key] = original[key].safe_dup }
    keys_added.each{ |key| added[key] = modified[key].safe_dup }

    keys_in_common.each do |key|
      r, a = easy_diff original[key], modified[key]
      unless _blank?(r) && _blank?(a)
        removed[key] = r
        added[key] = a
      end
    end

  elsif original.is_a?(Array) && modified.is_a?(Array)
    removed = subtract_arrays(original, modified)
    added   = subtract_arrays(modified, original)

  elsif original != modified
    removed   = original
    added     = modified
  end

  return removed, added
end
easy_merge!(original, added) click to toggle source
# File lib/easy_diff/core.rb, line 60
def self.easy_merge!(original, added)
  if original.is_a?(Hash) && added.is_a?(Hash)
    added_keys = added.keys
    added_keys.each{ |key| original[key] = easy_merge!(original[key], added[key])}
  elsif original.is_a?(Array) && added.is_a?(Array)
    original +=  added
  else
    original = added.safe_dup
  end
  original
end
easy_unmerge!(original, removed) click to toggle source
# File lib/easy_diff/core.rb, line 44
def self.easy_unmerge!(original, removed)
  if original.is_a?(Hash) && removed.is_a?(Hash)
    keys_in_common = original.keys & removed.keys
    keys_in_common.each do |key|
      if original[key] == removed[key]
        original.delete(key)
      else
        easy_unmerge!(original[key], removed[key])
      end
    end
  elsif original.is_a?(Array) && removed.is_a?(Array)
    subtract_arrays!(original, removed)
  end
  original
end
subtract_arrays(arr1, arr2) click to toggle source

Non-destructive version of above method.

# File lib/easy_diff/core.rb, line 96
def self.subtract_arrays arr1, arr2
  cloned_arr1 = easy_clone(arr1)
  subtract_arrays!(cloned_arr1, arr2)

  cloned_arr1
end
subtract_arrays!(arr1, arr2) click to toggle source

Regular array difference does not handle duplicate values in the way that is needed for this library. Examples:

subtract_arrays([1, 1, 2, 3], [1, 2]) => [1, 3]
subtract_arrays([3, 3, 3, 4], [3, 4, 5]) => [3, 3]

Shamelessly stolen from stackoverflow.com/questions/3852755/ruby-array-subtraction-without-removing-items-more-than-once

# File lib/easy_diff/core.rb, line 90
def self.subtract_arrays! arr1, arr2
  counts = arr2.inject(Hash.new(0)) { |h, v| h[v] += 1; h }
  arr1.reject! { |e| counts[e] -= 1 unless counts[e].zero? }
end