Object
A Hunk is a group of Blocks which overlap because of the context surrounding each block. (So if we’re not using context, every hunk will contain one block.) Used in the diff program (bin/diff).
Change the “start” and “end” fields to note that context should be added to this hunk
Create a hunk using references to both the old and new data, as well as the piece of data
# File lib/diff/lcs/hunk.rb, line 25 25: def initialize(data_old, data_new, piece, context, file_length_difference) 26: # At first, a hunk will have just one Block in it 27: @blocks = [ Diff::LCS::Block.new(piece) ] 28: @data_old = data_old 29: @data_new = data_new 30: 31: before = after = file_length_difference 32: after += @blocks[0].diff_size 33: @file_length_difference = after # The caller must get this manually 34: 35: # Save the start & end of each array. If the array doesn't exist 36: # (e.g., we're only adding items in this block), then figure out the 37: # line number based on the line number of the other file and the 38: # current difference in file lengths. 39: if @blocks[0].remove.empty? 40: a1 = a2 = nil 41: else 42: a1 = @blocks[0].remove[0].position 43: a2 = @blocks[0].remove[1].position 44: end 45: 46: if @blocks[0].insert.empty? 47: b1 = b2 = nil 48: else 49: b1 = @blocks[0].insert[0].position 50: b2 = @blocks[0].insert[1].position 51: end 52: 53: @start_old = a1 || (b1 - before) 54: @start_new = b1 || (a1 + before) 55: @end_old = a2 || (b2 - after) 56: @end_new = b2 || (a2 + after) 57: 58: self.flag_context = context 59: end
# File lib/diff/lcs/hunk.rb, line 101 101: def diff(format) 102: case format 103: when :old 104: old_diff 105: when :unified 106: unified_diff 107: when :context 108: context_diff 109: when :ed 110: self 111: when :reverse_ed, :ed_finish 112: ed_diff(format) 113: else 114: raise "Unknown diff format #{format}." 115: end 116: end
# File lib/diff/lcs/hunk.rb, line 118 118: def each_old(block) 119: @data_old[@start_old .. @end_old].each { |e| yield e } 120: end
Is there an overlap between hunk arg0 and old hunk arg1? Note: if end of old hunk is one less than beginning of second, they overlap
# File lib/diff/lcs/hunk.rb, line 93 93: def overlaps?(hunk = nil) 94: return nil if hunk.nil? 95: 96: a = (@start_old - hunk.end_old) <= 1 97: b = (@start_new - hunk.end_new) <= 1 98: return (a or b) 99: end
# File lib/diff/lcs/hunk.rb, line 178 178: def context_diff 179: s = "***************\n" 180: s << "*** #{context_range(:old)} ****\n" 181: r = context_range(:new) 182: 183: # Print out file 1 part for each block in context diff format if there 184: # are any blocks that remove items 185: lo, hi = @start_old, @end_old 186: removes = @blocks.select { |e| not e.remove.empty? } 187: if removes 188: outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } 189: removes.each do |block| 190: block.remove.each do |item| 191: outlist[item.position - lo].gsub!(/^ /) { block.op } # - or ! 192: end 193: end 194: s << outlist.join("\n") 195: end 196: 197: s << "\n--- #{r} ----\n" 198: lo, hi = @start_new, @end_new 199: inserts = @blocks.select { |e| not e.insert.empty? } 200: if inserts 201: outlist = @data_new[lo .. hi].collect { |e| e.gsub(/^/, ' ') } 202: inserts.each do |block| 203: block.insert.each do |item| 204: outlist[item.position - lo].gsub!(/^ /) { block.op } # + or ! 205: end 206: end 207: s << outlist.join("\n") 208: end 209: s 210: end
Generate a range of item numbers to print. Only print 1 number if the range has only one item in it. Otherwise, it’s ‘start,end’
# File lib/diff/lcs/hunk.rb, line 231 231: def context_range(mode) 232: case mode 233: when :old 234: s, e = (@start_old + 1), (@end_old + 1) 235: when :new 236: s, e = (@start_new + 1), (@end_new + 1) 237: end 238: 239: (s < e) ? "#{s},#{e}" : "#{e}" 240: end
# File lib/diff/lcs/hunk.rb, line 212 212: def ed_diff(format) 213: op_act = { "+" => 'a', "-" => 'd', "!" => "c" } 214: warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 215: 216: if format == :reverse_ed 217: s = "#{op_act[@blocks[0].op]}#{context_range(:old)}\n" 218: else 219: s = "#{context_range(:old).gsub(/,/, ' ')}#{op_act[@blocks[0].op]}\n" 220: end 221: 222: unless @blocks[0].insert.empty? 223: @data_new[@start_new .. @end_new].each { |e| s << "#{e}\n" } 224: s << ".\n" 225: end 226: s 227: end
Note that an old diff can’t have any context. Therefore, we know that there’s only one block in the hunk.
# File lib/diff/lcs/hunk.rb, line 125 125: def old_diff 126: warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 127: op_act = { "+" => 'a', "-" => 'd', "!" => "c" } 128: 129: block = @blocks[0] 130: 131: # Calculate item number range. Old diff range is just like a context 132: # diff range, except the ranges are on one line with the action between 133: # them. 134: s = "#{context_range(:old)}#{op_act[block.op]}#{context_range(:new)}\n" 135: # If removing anything, just print out all the remove lines in the hunk 136: # which is just all the remove lines in the block. 137: @data_old[@start_old .. @end_old].each { |e| s << "< #{e}\n" } unless block.remove.empty? 138: s << "---\n" if block.op == "!" 139: @data_new[@start_new .. @end_new].each { |e| s << "> #{e}\n" } unless block.insert.empty? 140: s 141: end
# File lib/diff/lcs/hunk.rb, line 143 143: def unified_diff 144: # Calculate item number range. 145: s = "@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n" 146: 147: # Outlist starts containing the hunk of the old file. Removing an item 148: # just means putting a '-' in front of it. Inserting an item requires 149: # getting it from the new file and splicing it in. We splice in 150: # +num_added+ items. Remove blocks use +num_added+ because splicing 151: # changed the length of outlist. 152: # 153: # We remove +num_removed+ items. Insert blocks use +num_removed+ 154: # because their item numbers -- corresponding to positions in the NEW 155: # file -- don't take removed items into account. 156: lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0 157: 158: outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } 159: 160: @blocks.each do |block| 161: block.remove.each do |item| 162: op = item.action.to_s # - 163: offset = item.position - lo + num_added 164: outlist[offset].gsub!(/^ /, op.to_s) 165: num_removed += 1 166: end 167: block.insert.each do |item| 168: op = item.action.to_s # + 169: offset = item.position - @start_new + num_removed 170: outlist[offset, 0] = "#{op}#{@data_new[item.position]}" 171: num_added += 1 172: end 173: end 174: 175: s << outlist.join("\n") 176: end
Generate a range of item numbers to print for unified diff. Print number where block starts, followed by number of lines in the block (don’t print number of lines if it’s 1)
# File lib/diff/lcs/hunk.rb, line 245 245: def unified_range(mode) 246: case mode 247: when :old 248: s, e = (@start_old + 1), (@end_old + 1) 249: when :new 250: s, e = (@start_new + 1), (@end_new + 1) 251: end 252: 253: length = e - s + 1 254: first = (length < 2) ? e : s # "strange, but correct" 255: (length == 1) ? "#{first}" : "#{first},#{length}" 256: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.