global

def intuit_diff_direction(src, patchset, limit = nil)

of one of the above.
Diff::LCS::Change as its source, as an array will cause the creation
some time. This also works better with Diff::LCS::ContextChange or
WARNING: By default, this examines the whole patch, so this could take

patch should be applied.
Examine the patchset and the source to see in which direction the
def intuit_diff_direction(src, patchset, limit = nil)
  string = src.kind_of?(String)
  count = left_match = left_miss = right_match = right_miss = 0
  patchset.each do |change|
    count += 1
    case change
    when Diff::LCS::ContextChange
      le = string ? src[change.old_position, 1] : src[change.old_position]
      re = string ? src[change.new_position, 1] : src[change.new_position]
      case change.action
      when '-' # Remove details from the old string
        if le == change.old_element
          left_match += 1
        else
          left_miss += 1
        end
      when '+'
        if re == change.new_element
          right_match += 1
        else
          right_miss += 1
        end
      when '='
        left_miss += 1 if le != change.old_element
        right_miss += 1 if re != change.new_element
      when '!'
        if le == change.old_element
          left_match += 1
        elsif re == change.new_element
          right_match += 1
        else
          left_miss += 1
          right_miss += 1
        end
      end
    when Diff::LCS::Change
      # With a simplistic change, we can't tell the difference between
      # the left and right on '!' actions, so we ignore those. On '='
      # actions, if there's a miss, we miss both left and right.
      element = string ? src[change.position, 1] : src[change.position]
      case change.action
      when '-'
        if element == change.element
          left_match += 1
        else
          left_miss += 1
        end
      when '+'
        if element == change.element
          right_match += 1
        else
          right_miss += 1
        end
      when '='
        if element != change.element
          left_miss += 1
          right_miss += 1
        end
      end
    end
    break if !limit.nil? && (count > limit)
  end
  no_left = left_match.zero? && left_miss.positive?
  no_right = right_match.zero? && right_miss.positive?
  case [no_left, no_right]
  when [false, true]
    :patch
  when [true, false]
    :unpatch
  else
    case left_match <=> right_match
    when 1
      if left_miss.zero?
        :patch
      else
        :unpatch
      end
    when -1
      if right_miss.zero?
        :unpatch
      else
        :patch
      end
    else
      fail "The provided patchset does not appear to apply to the provided \
umerable as either source or destination value."
    end
  end
end