Parent

Diff::LCS::Hunk

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).

Attributes

blocks[R]
start_old[R]
start_new[R]
end_old[R]
end_new[R]
file_length_difference[R]
flag_context[RW]

Change the “start” and “end” fields to note that context should be added to this hunk

Public Class Methods

new(data_old, data_new, piece, context, file_length_difference) click to toggle source

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

Public Instance Methods

diff(format) click to toggle source
     # 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
each_old(block) click to toggle source
     # 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
overlaps?(hunk = nil) click to toggle source

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
unshift(hunk) click to toggle source
    # File lib/diff/lcs/hunk.rb, line 85
85:   def unshift(hunk)
86:     @start_old = hunk.start_old
87:     @start_new = hunk.start_new
88:     blocks.unshift(*hunk.blocks)
89:   end

Private Instance Methods

context_diff() click to toggle source
     # 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
context_range(mode) click to toggle source

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
ed_diff(format) click to toggle source
     # 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
old_diff() click to toggle source

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
unified_diff() click to toggle source
     # 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
unified_range(mode) click to toggle source

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.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.