Class: Diff::GDiff

Inherits:
Object
  • Object
show all
Defined in:
lib/gdiff.rb,
lib/gdiff.rb

Overview

Class encapsulating the gdiff protocoll

www.w3.org/TR/NOTE-gdiff-19970901

Defined Under Namespace

Modules: Operations Classes: EGdiffError, ENoGdiffStream, EPrematureEndOfStream

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(a = nil, b = nil, threshhold = 5) ⇒ GDiff

Create a new gdiff patch from string a to string b. Threshhold needs to be estimated more exactly to yield the best possible compression.



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/gdiff.rb', line 175

def initialize(a = nil, b = nil, threshhold = 5)      
  if (!a and !b) or b.empty?
	@operations = [] 
  elsif a.empty?
	@operations = [Operations::Data.new(b)]
  else
	# Lifted the suffix array and this algorithm from zed shaws fastcst project
	# http://www.zedshaw.com/projects/fastcst/rdoc/index.html
	#
	# It is licenced under the gpl, so now my code is also licensed under the gpl
	sary = SuffixArray.new(a)

	@operations = []
	start = 0
	while start < b.length
	  non_len, match_start, match_len = sary.longest_nonmatch b, start, threshhold

	  @operations << Operations::Data.new(b[start, non_len]) if non_len > 0
	  @operations << Operations::Copy.new(match_start, match_len) if match_len > 0

	  start += non_len + match_len
	end

	@operations << Operations::EOS
  end
end

Class Method Details

.unpack(string) ⇒ Object

Unpack a binary representation of a diff.

TODO: use stream operations to allow reading the diff step by step from an io.



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/gdiff.rb', line 209

def self.unpack(string)
  result = self.new
  result.instance_eval do
	raise ENoGdiffStream, "No gdiff stream." if string[0,5].unpack("C5") != [0xd1, 0xff, 0xd1, 0xff, 4]
	position = 5
	while string[position] != 0
	  position, operation = (Operations::Data.unpack_if_match(string, position) or 
 Operations::Copy.unpack_if_match(string, position))
 @operations << operation
 raise EPrematureEndOfStream, "Premature end of gdiff stream" if position >= string.length
	end
	@operations << Operations::EOS
  end
  result
end

Instance Method Details

#apply_to(a) ⇒ Object

Apply this patch to a string, yielding another string.

TODO: Implement a stream version that writes successively to a stream and saves memory.



229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/gdiff.rb', line 229

def apply_to(a)
  result = ""
  @operations.each do | operation |
	case operation
	when Operations::Copy
	  result << a[operation.position, operation.length]
	when Operations::Data
	  result << operation.data
	end
  end
  result
end

#packObject

Return a binary representation in GDiff format



248
249
250
# File 'lib/gdiff.rb', line 248

def pack
  [0xd1, 0xff, 0xd1, 0xff, 4].pack("C5") <<  @operations.map { | operation | operation.pack }.join
end

#to_sObject

Return a readable string representation



243
244
245
# File 'lib/gdiff.rb', line 243

def to_s
  @operations.map { | operation | operation.to_s }
end