Space efficient revision history storage with diffs

I've written a tool to store a files history more efficiently by only generating diffs and storing them whereas whole file would otherwise have to be stored. I would like to to hear about ways to improve readability and otherwise make this code more "ruby" or suggestions for test-cases to improve robustness. I also feel like the swap case could be expressed as a insertion/deletion combinations, but maybe it's more readable to leave it as is. Here is the Diff class:

class Diff

def initialize(a,b)
@a = a
@b = b
@diff = {} # {line_number => {type: +/-/~, content: text}}
a = a.split("");
b = b.split("");
a_pos = 0
b_pos = 0
while (a+b).length > 0
if a[0] == b[0]
a.shift
a_pos += 1
b.shift
else
i = 1
loop do
if a[i] == b[0]
@diff[a_pos] = {type: "-", content: a[0..i-1].join}
a = a[i..-1]
a_pos += a[0..i].length
break
elsif b[i] == a[0]
@diff[a_pos] = {type: "+", content: b[0..i-1].join}
b = b[i..-1]
break
elsif a[i] == b[i]
a_pos += i
@diff[a_pos] = {type: "~", content: [a.shift(i), b.shift(i)]}
end
i = i+1
break if a[i] == b[0] || b[i] == a[0] || a[i]==b[i]
end
end
if a.empty? && !b.empty?
@diff[a_pos] = {type: "+", content: b.join}
break
elsif b.empty? && !a.empty?
@diff[a_pos] = {type: "-", content: a.join}
break
end
end
end

def self.apply(a, diff_hash)
a = a.split("")
Hash[diff_hash.diff.sort.reverse].each do |line, diff|
case diff[:type]
when "-"
a = a[0..line-1]+a[line+diff[:content].length..-1]
when "+"
a.insert(line-1, diff[:content]) # line-2
when "~"
a = a[0..line-2]+a[line+diff[:content][0].length-1..-1]
a.insert(line-1, diff[:content][1])
end
end
return a.join
end
end

• test input and resulting output? for someone unfamiliar with this code its near impossible to understand....more explanation would help immensely – BKSpurgeon Apr 13 '17 at 23:24
• Does this work? These lines a = a[i..-1]; a_pos += a[0..i].length look awfully suspicious to me. – David Stanley Apr 18 '17 at 16:15
• There's something wrong with the code. Trying Diff.new("dddddabc", "abc") goes into an infinite loop. – David Stanley Apr 19 '17 at 0:45
• Curiousity question: is there a reason you didn't start with an existing diff gem like diffy? – Mark Thomas Apr 27 '17 at 1:29