Geminstaller C0 Coverage Information - RCov

/Users/woolley/.rvm/gems/ruby-1.8.7-p174@geminstaller/gems/diff-lcs-1.1.2/lib/diff/lcs/hunk.rb

Name Total Lines Lines of Code Total Coverage Code Coverage
/Users/woolley/.rvm/gems/ruby-1.8.7-p174@geminstaller/gems/diff-lcs-1.1.2/lib/diff/lcs/hunk.rb 257 170
25.29%
11.76%

Key

Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.

Coverage Details

1 #! /usr/env/bin ruby
2 #--
3 # Copyright 2004 Austin Ziegler <diff-lcs@halostatue.ca>
4 #   adapted from:
5 #     Algorithm::Diff (Perl) by Ned Konz <perl@bike-nomad.com>
6 #     Smalltalk by Mario I. Wolczko <mario@wolczko.com>
7 #   implements McIlroy-Hunt diff algorithm
8 #
9 # This program is free software. It may be redistributed and/or modified under
10 # the terms of the GPL version 2 (or later), the Perl Artistic licence, or the
11 # Ruby licence.
12 # 
13 # $Id: hunk.rb,v 1.2 2004/08/08 20:33:09 austin Exp $
14 #++
15 # Contains Diff::LCS::Hunk for bin/ldiff.
16 
17 require 'diff/lcs/block'
18 
19   # A Hunk is a group of Blocks which overlap because of the context
20   # surrounding each block. (So if we're not using context, every hunk will
21   # contain one block.) Used in the diff program (bin/diff).
22 class Diff::LCS::Hunk
23     # Create a hunk using references to both the old and new data, as well as
24     # the piece of data
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
60 
61   attr_reader :blocks
62   attr_reader :start_old, :start_new
63   attr_reader :end_old, :end_new
64   attr_reader :file_length_difference
65 
66     # Change the "start" and "end" fields to note that context should be added
67     # to this hunk
68   attr_accessor :flag_context
69   def flag_context=(context) #:nodoc:
70     return if context.nil? or context.zero?
71 
72     add_start = (context > @start_old) ? @start_old : context
73     @start_old -= add_start
74     @start_new -= add_start
75 
76     if (@end_old + context) > @data_old.size
77       add_end = @data_old.size - @end_old
78     else
79       add_end = context
80     end
81     @end_old += add_end
82     @end_new += add_end
83   end
84 
85   def unshift(hunk)
86     @start_old = hunk.start_old
87     @start_new = hunk.start_new
88     blocks.unshift(*hunk.blocks)
89   end
90 
91     # Is there an overlap between hunk arg0 and old hunk arg1? Note: if end
92     # of old hunk is one less than beginning of second, they overlap
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
100 
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
117 
118   def each_old(block)
119     @data_old[@start_old .. @end_old].each { |e| yield e }
120   end
121 
122   private
123     # Note that an old diff can't have any context. Therefore, we know that
124     # there's only one block in the hunk.
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
142 
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
177 
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
211 
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
228 
229     # Generate a range of item numbers to print. Only print 1 number if the
230     # range has only one item in it. Otherwise, it's 'start,end'
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
241 
242     # Generate a range of item numbers to print for unified diff. Print
243     # number where block starts, followed by number of lines in the block
244     # (don't print number of lines if it's 1)
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
257 end

Generated on Mon May 10 23:40:27 -0700 2010 with rcov 0.9.8