class Dyph::Support::Merger

Attributes

diff2[R]
result[R]

Public Class Methods

merge(left, base, right, diff2: Dyph::Differ.default_diff2, diff3: Dyph::Differ.default_diff3) click to toggle source
# File lib/dyph/support/merger.rb, line 5
def self.merge(left, base, right, diff2: Dyph::Differ.default_diff2, diff3: Dyph::Differ.default_diff3)
  merger = Merger.new(left: left, base: base, right: right, diff2: diff2, diff3: diff3)
  merger.execute_three_way_merge()
  merger.result
end
new(left:, base:, right:, diff2:, diff3:) click to toggle source
# File lib/dyph/support/merger.rb, line 11
def initialize(left:, base:, right:, diff2:, diff3:)
  @result = []
  @diff2 = diff2
  @diff3 = diff3
  @text3 = Text3.new(left: left, right: right, base: base)
end

Public Instance Methods

execute_three_way_merge() click to toggle source

rubocop:disable Metrics/AbcSize

# File lib/dyph/support/merger.rb, line 19
def execute_three_way_merge
  d3 = @diff3.execute_diff(@text3.left, @text3.base, @text3.right, @diff2)
  chunk_descs = d3.map { |raw_chunk_desc| ChunkDesc.new(raw_chunk_desc) }
  index = 1
  chunk_descs.each do |chunk_desc|
    initial_text = []

    (index ... chunk_desc.base_lo).each do |lineno|                  # exclusive (...)
      initial_text << @text3.base[lineno - 1]
    end
    #initial_text = initial_text.join("\n") + "\n"
    #
    @result << Dyph::Outcome::Resolved.new(initial_text) unless initial_text.empty?

    interpret_chunk(chunk_desc)
    #assign index to be the line in base after the conflict
    index = chunk_desc.base_hi + 1
    #
  end

  #finish by putting all text after the last conflict into the @result body.

  ending_text = accumulate_lines(index, @text3.base.length, @text3.base)

  @result << Dyph::Outcome::Resolved.new(ending_text) unless ending_text.empty?
end

Protected Instance Methods

_assoc_range(diff, diff_type) click to toggle source

@param [in] diff conflicts in diff structure @param [in] diff_type type of diff looked for in diff @return diff_type if any conflicts in diff are of type diff_type. otherwise return nil

# File lib/dyph/support/merger.rb, line 125
def _assoc_range(diff, diff_type)
  diff.each do |d|
    if d[0] == diff_type
      return d
    end
  end
  nil
end
_conflict_range(chunk_desc) click to toggle source
# File lib/dyph/support/merger.rb, line 96
def _conflict_range(chunk_desc)
  right = set_text(@text3.right, chunk_desc.right_lo,  chunk_desc.right_hi)
  left =  set_text(@text3.left , chunk_desc.left_lo,   chunk_desc.left_hi)
  d = @diff2.diff(right, left)
  if (_assoc_range(d, :change) || _assoc_range(d, :delete)) && chunk_desc.base_lo <= chunk_desc.base_hi
    set_conflict(chunk_desc)
  else
    determine_conflict(d, left, right)
  end
end
accumulate_lines(lo, hi, text) click to toggle source

@param [in] lo indec for beginning of accumulation range @param [in] hi index for end of accumulation range @param [in] text array of lines of text @return a string of lines lo to high joined by new lines, with a trailing new line.

# File lib/dyph/support/merger.rb, line 138
def accumulate_lines(lo, hi, text)
  lines = []
  (lo .. hi).each do |lineno|
    lines << text[lineno - 1] unless text[lineno - 1].nil?
  end
  lines
end
determine_conflict(d, left, right) click to toggle source
# File lib/dyph/support/merger.rb, line 57
def determine_conflict(d, left, right)
  ia = 1
  d.each do |raw_chunk_desc|
    chunk_desc = ChunkDesc.new(raw_chunk_desc)
    (ia ... chunk_desc.left_lo).each do |lineno|
      @result <<  Dyph::Outcome::Resolved.new(accumulate_lines(ia, lineno, right))
    end

    outcome =  determine_outcome(chunk_desc, left, right)
    ia = chunk_desc.right_hi + 1
    @result << outcome if outcome
  end

  final_text = accumulate_lines(ia, right.length + 1, right)
  @result <<  Dyph::Outcome::Resolved.new(final_text) unless final_text.empty?
end
determine_outcome(chunk_desc, left, right) click to toggle source
# File lib/dyph/support/merger.rb, line 74
def determine_outcome(chunk_desc, left, right)
  if chunk_desc.action == :change
    Outcome::Conflicted.new(
      left: accumulate_lines(chunk_desc.right_lo, chunk_desc.right_hi, left),
      right: accumulate_lines(chunk_desc.left_lo, chunk_desc.left_hi, right),
      base: []
    )
  elsif chunk_desc.action == :add
    Outcome::Resolved.new(
      accumulate_lines(chunk_desc.right_lo, chunk_desc.right_hi, left)
    )
  end
end
interpret_chunk(chunk_desc) click to toggle source
# File lib/dyph/support/merger.rb, line 107
def interpret_chunk(chunk_desc)
  if chunk_desc.action == :choose_left
    # 0 flag means choose left.  put lines chunk_desc[1] .. chunk_desc[2] into the @result body.
    temp_text = accumulate_lines(chunk_desc.left_lo, chunk_desc.left_hi, @text3.left)
    # they deleted it, don't use if its only a new line
    @result <<  Dyph::Outcome::Resolved.new(temp_text) unless temp_text.empty?
  elsif chunk_desc.action != :possible_conflict
    # A flag means choose right.  put lines chunk_desc[3] to chunk_desc[4] into the @result body.
    temp_text = accumulate_lines(chunk_desc.right_lo, chunk_desc.right_hi, @text3.right)
    @result << Dyph::Outcome::Resolved.new(temp_text) unless temp_text.empty?
  else
    _conflict_range(chunk_desc)
  end
end
set_conflict(chunk_desc) click to toggle source

rubocop:enable Metrics/AbcSize

# File lib/dyph/support/merger.rb, line 48
def set_conflict(chunk_desc)
  conflict = Dyph::Outcome::Conflicted.new(
    left:   accumulate_lines(chunk_desc.left_lo, chunk_desc.left_hi, @text3.left),
    base:   accumulate_lines(chunk_desc.base_lo, chunk_desc.base_hi, @text3.base),
    right:  accumulate_lines(chunk_desc.right_lo, chunk_desc.right_hi, @text3.right)
  )
  @result << conflict
end
set_text(orig_text, lo, hi) click to toggle source
# File lib/dyph/support/merger.rb, line 88
def set_text(orig_text, lo, hi)
  text = [] # conflicting lines in right
  (lo .. hi).each do |i|                   # inclusive(..)
    text << orig_text[i - 1]
  end
  text
end