From: Kev Jackson Date: 2005-10-28T19:15:09+09:00 Subject: failed GDiff attempt was [Re: Ruby Quiz for building up Ruby?] Well I've got to dash off early today, but here's something I've hacked together (very rough) I'm sure there are many better ways of doing this - indeed my algorithm is very naive, it doesn't scan for matches in an efficient way (just barely scans :) The approach I was going for was to have a GDiffFile class, and then create various GDiff command objects and pump them into the file. At the moment it will spit out a semi-compliant gdiff file, but it's horrendously bloated, and I couldn't find a nice way to quote strings as in the example on http://www.w3.org/TR/NOTE-gdiff-19970901 Kev GDiff composer (just bytes, not longs etc), not in class, just hacking at the script really gdiff.rb require 'lib/gdiff_copy' require 'lib/gdiff_data' require 'lib/gdiff_file' diff_file = GDiff::GDiffFile.new("d:\\ruby_projects\\gdiff\\test") diff_file.put_header # get data into arrays old = IO.read("d:\\ruby_projects\\gdiff\\gdiff.rb").scan(/./) new = IO.read("d:\\ruby_projects\\gdiff\\gdiff_new.rb").scan(/./) # dumb scan comparing single chars, should make it compare matching sequences pos =0 old.each do |oldb| diff_file.put_cmd_and_data(GDiff::GDiffCopy.new(pos, 1)) if new[pos] == oldb diff_file.put_cmd_and_data(GDiff::GDiffData.new(1,new[pos])) if new[pos] != oldb pos +=1 end diff_file.put_trailer diff_file.write_diff lib/gdiff_cmd.rb module GDiff class GDiffCmd attr_accessor :cmd attr_accessor :data def initialize(cmd, data) @cmd = cmd @data = data end end end lib/gdiff_copy.rb require 'lib/gdiff_cmd' module GDiff class GDiffCopy < GDiffCmd def initialize(position, length) @cmd = 249 @data = [0] @data << position @data << length end end end lib/gdiff_data.rb require 'lib/gdiff_cmd' module GDiff class GDiffData < GDiffCmd def initialize(cmd, data) #if cmd < 1 or cmd > 248 # raise DataError #end @cmd = cmd @data = data end end end lib/gdiff_file.rb module GDiff class GDiffFile < File @@magic = 0xd1ffd1ff @@version = 0x04 @@EOF = 0 def initialize(filename) @filename = filename @filedata = [] end def put_header put_data(@@magic) put_data(@@version) end def put_trailer put_data(@@EOF) end def copy_byte(start) write_diff() end def put_data(data) if data.respond_to?(length) then if data.length==1 then @filedata << data else data.each_byte do |b| @filedata << data + "," end else @filedata << data end end def put_cmd(cmd) @filedata << cmd.cmd << "," end def put_cmd_and_data(cmd) put_cmd(cmd) put_data(cmd.data) end def write_diff p @filedata File.open(@filename, "w") { |f| f << @filedata.flatten } end end end