relevance-rcov 0.8.2.1 → 0.8.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -44,19 +44,11 @@ Rcov::RcovTask.new(:rcov_ccanalyzer) do |t|
44
44
  end
45
45
 
46
46
  desc "Run the unit tests with rcovrt."
47
- if RUBY_PLATFORM == 'java'
48
- Rake::TestTask.new(:test_rcovrt => ["lib/rcovrt.jar"]) do |t|
49
- t.libs << "lib"
50
- t.test_files = FileList['test/*_test.rb']
51
- t.verbose = true
52
- end
53
- else
54
- Rake::TestTask.new(:test_rcovrt => ["ext/rcovrt/rcovrt.so"]) do |t|
55
- system("cd ext/rcovrt && make clean && rm Makefile")
56
- t.libs << "ext/rcovrt"
57
- t.test_files = FileList['test/*_test.rb']
58
- t.verbose = true
59
- end
47
+ Rake::TestTask.new(:test_rcovrt => ["ext/rcovrt/rcovrt.so"]) do |t|
48
+ system("cd ext/rcovrt && make clean && rm Makefile")
49
+ t.libs << "ext/rcovrt"
50
+ t.test_files = FileList['test/*_test.rb']
51
+ t.verbose = true
60
52
  end
61
53
 
62
54
  file "ext/rcovrt/rcovrt.so" => FileList["ext/rcovrt/*.c"] do
data/bin/rcov CHANGED
@@ -17,7 +17,6 @@ require 'ostruct'
17
17
  SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
18
18
  require 'rcov/version'
19
19
  require 'rcov/formatters'
20
- require 'rcov/report'
21
20
 
22
21
  #{{{ "main" code
23
22
  options = OpenStruct.new
@@ -419,10 +418,9 @@ EOF
419
418
 
420
419
  Please fill in the blanks in the following report.
421
420
 
422
- You can report the bug via the Ruby-Talk ML, send it directly to
423
- <mfp at acm dot org> (include "rcov" in the subject to get past the spam filters),
424
- or post it to
425
- http://eigenclass.org/hiki.rb?rcov+#{VERSION}
421
+
422
+ You can post bugs to
423
+ http://github.com/relevance/rcov/issues
426
424
 
427
425
  Thank you!
428
426
 
@@ -1,23 +1,21 @@
1
- unless RUBY_PLATFORM == 'java' then
2
- require 'mkmf'
3
-
4
- dir_config("gcov")
5
- if ENV["USE_GCOV"] and Config::CONFIG['CC'] =~ /gcc/ and
6
- have_library("gcov", "__gcov_open")
7
-
8
- $CFLAGS << " -fprofile-arcs -ftest-coverage"
9
- if RUBY_VERSION =~ /1.9/
10
- $CFLAGS << ' -DRUBY_19_COMPATIBILITY'
11
- create_makefile("rcovrt", "1.9/")
12
- else
13
- create_makefile("rcovrt", "1.8/")
14
- end
1
+ require 'mkmf'
2
+
3
+ dir_config("gcov")
4
+ if ENV["USE_GCOV"] and Config::CONFIG['CC'] =~ /gcc/ and
5
+ have_library("gcov", "__gcov_open")
6
+
7
+ $CFLAGS << " -fprofile-arcs -ftest-coverage"
8
+ if RUBY_VERSION =~ /1.9/
9
+ $CFLAGS << ' -DRUBY_19_COMPATIBILITY'
10
+ create_makefile("rcovrt", "1.9/")
15
11
  else
16
- if RUBY_VERSION =~ /1.9/
17
- $CFLAGS << ' -DRUBY_19_COMPATIBILITY'
18
- create_makefile("rcovrt", "1.9/")
19
- else
20
- create_makefile("rcovrt", "1.8/")
21
- end
12
+ create_makefile("rcovrt", "1.8/")
22
13
  end
23
- end
14
+ else
15
+ if RUBY_VERSION =~ /1.9/
16
+ $CFLAGS << ' -DRUBY_19_COMPATIBILITY'
17
+ create_makefile("rcovrt", "1.9/")
18
+ else
19
+ create_makefile("rcovrt", "1.8/")
20
+ end
21
+ end
@@ -0,0 +1,292 @@
1
+ require "erb"
2
+
3
+ class Document
4
+
5
+ attr_accessor :local_variables
6
+
7
+ def initialize(template_file, locals={})
8
+ template_path = File.expand_path("#{File.dirname(__FILE__)}/../templates/#{template_file}")
9
+ @template = ERB.new(File.read(template_path))
10
+ @local_variables = locals
11
+ @path_relativizer = Hash.new{|h,base|
12
+ # TODO: Waaaahhhhh?
13
+ h[base] = Pathname.new(base).cleanpath.to_s.gsub(%r{^\w:[/\\]}, "").gsub(/\./, "_").gsub(/[\\\/]/, "-") + ".html"
14
+ }
15
+ end
16
+
17
+ def render
18
+ @template.result(get_binding)
19
+ end
20
+
21
+ def relative_filename(path)
22
+ @path_relativizer[path]
23
+ end
24
+
25
+ #def create_cross_refs(filename, lineno, linetext)
26
+ #form = formatter
27
+ #return linetext unless @callsite_analyzer && @do_callsites
28
+
29
+ #ref_blocks = []
30
+ #form.send(:_get_defsites, ref_blocks, filename, lineno, "Calls", linetext) do |ref|
31
+ #if ref.file
32
+ #where = "at #{formatter.normalize_filename(ref.file)}:#{ref.line}"
33
+ #else
34
+ #where = "(C extension/core)"
35
+ #end
36
+ #CGI.escapeHTML("%7d %s" % [ref.count, "#{ref.klass}##{ref.mid} " + where])
37
+ #end
38
+
39
+ #form.send(:_get_callsites, ref_blocks, filename, lineno, "Called by", linetext) do |ref|
40
+ #r = "%7d %s" % [ref.count, "#{formatter.normalize_filename(ref.file||'C code')}:#{ref.line} " + "in '#{ref.klass}##{ref.mid}'"]
41
+ #CGI.escapeHTML(r)
42
+ #end
43
+
44
+ #create_cross_reference_block(linetext, ref_blocks)
45
+ #end
46
+
47
+ #def create_cross_reference_block(linetext, ref_blocks)
48
+ #return linetext if ref_blocks.empty?
49
+ #ret = ""
50
+ #@cross_ref_idx ||= 0
51
+ #@known_files ||= formatter.sorted_file_pairs.map{|fname, finfo| formatter.normalize_filename(fname)}
52
+ #ret << %[<a class="crossref-toggle" href="#" onclick="toggleCode('XREF-#{@cross_ref_idx+=1}'); return false;">#{linetext}</a>]
53
+ #ret << %[<span class="cross-ref" id="XREF-#{@cross_ref_idx}">]
54
+ #ret << "\n"
55
+ #ref_blocks.each do |refs, toplabel, label_proc|
56
+ #unless !toplabel || toplabel.empty?
57
+ #ret << %!<span class="cross-ref-title">#{toplabel}</span>\n!
58
+ #end
59
+ #refs.each do |dst|
60
+ #dstfile = formatter.normalize_filename(dst.file) if dst.file
61
+ #dstline = dst.line
62
+ #label = label_proc.call(dst)
63
+ #if dst.file && @known_files.include?(dstfile)
64
+ #ret << %[<a href="#{formatter.mangle_filename(dstfile)}#line#{dstline}">#{label}</a>]
65
+ #else
66
+ #ret << label
67
+ #end
68
+ #ret << "\n"
69
+ #end
70
+ #end
71
+ #ret << "</span>"
72
+ #end
73
+
74
+ def line_css(line_number)
75
+ case file.coverage[line_number]
76
+ when true
77
+ "marked"
78
+ when :inferred
79
+ "inferred"
80
+ else
81
+ "uncovered"
82
+ end
83
+ end
84
+
85
+
86
+ #def format_lines(file)
87
+ #result = ""
88
+ #last = nil
89
+ #end_of_span = ""
90
+ #format_line = "%#{file.num_lines.to_s.size}d"
91
+ #file.num_lines.times do |i|
92
+ #line = file.lines[i].chomp
93
+ #marked = file.coverage[i]
94
+ #count = file.counts[i]
95
+ #spanclass = span_class(file, marked, count)
96
+ #if spanclass != last
97
+ #result += end_of_span
98
+ #case spanclass
99
+ #when nil
100
+ #end_of_span = ""
101
+ #else
102
+ #result += %[<span class="#{spanclass}">]
103
+ #end_of_span = "</span>"
104
+ #end
105
+ #end
106
+ #result += %[<a name="line#{i+1}"></a>] + (format_line % (i+1)) +
107
+ #" " + create_cross_refs(file.name, i+1, CGI.escapeHTML(line)) + "\n"
108
+ #last = spanclass
109
+ #end
110
+ #result += end_of_span
111
+ #"<pre>#{result}</pre>"
112
+ #end
113
+
114
+
115
+ def method_missing(key, *args)
116
+ local_variables.has_key?(key) ? local_variables[key] : super
117
+ end
118
+
119
+ def get_binding
120
+ binding
121
+ end
122
+
123
+ end
124
+
125
+ module Rcov
126
+
127
+ class BaseFormatter # :nodoc:
128
+ require 'pathname'
129
+ require 'mkmf'
130
+ ignore_files = [/\A#{Regexp.escape(Pathname.new(::Config::CONFIG['libdir']).cleanpath.to_s)}/, /\btc_[^.]*.rb/, /_test\.rb\z/, /\btest\//, /\bvendor\//, /\A#{Regexp.escape(__FILE__)}\z/]
131
+
132
+ DEFAULT_OPTS = {:ignore => ignore_files, :sort => :name, :sort_reverse => false,
133
+ :output_threshold => 101, :dont_ignore => [], :callsite_analyzer => nil, :comments_run_by_default => false}
134
+
135
+ def initialize(opts = {})
136
+ options = DEFAULT_OPTS.clone.update(opts)
137
+ @files = {}
138
+ @ignore_files = options[:ignore]
139
+ @dont_ignore_files = options[:dont_ignore]
140
+ @sort_criterium = case options[:sort]
141
+ when :loc then lambda{|fname, finfo| finfo.num_code_lines}
142
+ when :coverage then lambda{|fname, finfo| finfo.code_coverage}
143
+ else lambda{|fname, finfo| fname}
144
+ end
145
+ @sort_reverse = options[:sort_reverse]
146
+ @output_threshold = options[:output_threshold]
147
+ @callsite_analyzer = options[:callsite_analyzer]
148
+ @comments_run_by_default = options[:comments_run_by_default]
149
+ @callsite_index = nil
150
+
151
+ @mangle_filename = Hash.new{|h,base|
152
+ h[base] = Pathname.new(base).cleanpath.to_s.gsub(%r{^\w:[/\\]}, "").gsub(/\./, "_").gsub(/[\\\/]/, "-") + ".html"
153
+ }
154
+ end
155
+
156
+ def add_file(filename, lines, coverage, counts)
157
+ old_filename = filename
158
+ filename = normalize_filename(filename)
159
+ SCRIPT_LINES__[filename] = SCRIPT_LINES__[old_filename]
160
+ if @ignore_files.any?{|x| x === filename} &&
161
+ !@dont_ignore_files.any?{|x| x === filename}
162
+ return nil
163
+ end
164
+ if @files[filename]
165
+ @files[filename].merge(lines, coverage, counts)
166
+ else
167
+ @files[filename] = FileStatistics.new(filename, lines, counts,
168
+ @comments_run_by_default)
169
+ end
170
+ end
171
+
172
+ def normalize_filename(filename)
173
+ File.expand_path(filename).gsub(/^#{Regexp.escape(Dir.getwd)}\//, '')
174
+ end
175
+
176
+ def mangle_filename(base)
177
+ @mangle_filename[base]
178
+ end
179
+
180
+ def each_file_pair_sorted(&b)
181
+ return sorted_file_pairs unless block_given?
182
+ sorted_file_pairs.each(&b)
183
+ end
184
+
185
+ def sorted_file_pairs
186
+ pairs = @files.sort_by do |fname, finfo|
187
+ @sort_criterium.call(fname, finfo)
188
+ end.select{|_, finfo| 100 * finfo.code_coverage < @output_threshold}
189
+ @sort_reverse ? pairs.reverse : pairs
190
+ end
191
+
192
+ def total_coverage
193
+ lines = 0
194
+ total = 0.0
195
+ @files.each do |k,f|
196
+ total += f.num_lines * f.total_coverage
197
+ lines += f.num_lines
198
+ end
199
+ return 0 if lines == 0
200
+ total / lines
201
+ end
202
+
203
+ def code_coverage
204
+ lines = 0
205
+ total = 0.0
206
+ @files.each do |k,f|
207
+ total += f.num_code_lines * f.code_coverage
208
+ lines += f.num_code_lines
209
+ end
210
+ return 0 if lines == 0
211
+ total / lines
212
+ end
213
+
214
+ def num_code_lines
215
+ lines = 0
216
+ @files.each{|k, f| lines += f.num_code_lines }
217
+ lines
218
+ end
219
+
220
+ def num_lines
221
+ lines = 0
222
+ @files.each{|k, f| lines += f.num_lines }
223
+ lines
224
+ end
225
+
226
+ private
227
+ def cross_references_for(filename, lineno)
228
+ return nil unless @callsite_analyzer
229
+ @callsite_index ||= build_callsite_index
230
+ @callsite_index[normalize_filename(filename)][lineno]
231
+ end
232
+
233
+ def reverse_cross_references_for(filename, lineno)
234
+ return nil unless @callsite_analyzer
235
+ @callsite_reverse_index ||= build_reverse_callsite_index
236
+ @callsite_reverse_index[normalize_filename(filename)][lineno]
237
+ end
238
+
239
+ def build_callsite_index
240
+ index = Hash.new{|h,k| h[k] = {}}
241
+ @callsite_analyzer.analyzed_classes.each do |classname|
242
+ @callsite_analyzer.analyzed_methods(classname).each do |methname|
243
+ defsite = @callsite_analyzer.defsite(classname, methname)
244
+ index[normalize_filename(defsite.file)][defsite.line] =
245
+ @callsite_analyzer.callsites(classname, methname)
246
+ end
247
+ end
248
+ index
249
+ end
250
+
251
+ def build_reverse_callsite_index
252
+ index = Hash.new{|h,k| h[k] = {}}
253
+ @callsite_analyzer.analyzed_classes.each do |classname|
254
+ @callsite_analyzer.analyzed_methods(classname).each do |methname|
255
+ callsites = @callsite_analyzer.callsites(classname, methname)
256
+ defsite = @callsite_analyzer.defsite(classname, methname)
257
+ callsites.each_pair do |callsite, count|
258
+ next unless callsite.file
259
+ fname = normalize_filename(callsite.file)
260
+ (index[fname][callsite.line] ||= []) << [classname, methname, defsite, count]
261
+ end
262
+ end
263
+ end
264
+ index
265
+ end
266
+
267
+ class XRefHelper < Struct.new(:file, :line, :klass, :mid, :count) # :nodoc:
268
+ end
269
+
270
+ def _get_defsites(ref_blocks, filename, lineno, linetext, label, &format_call_ref)
271
+ if @do_cross_references and
272
+ (rev_xref = reverse_cross_references_for(filename, lineno))
273
+ refs = rev_xref.map do |classname, methodname, defsite, count|
274
+ XRefHelper.new(defsite.file, defsite.line, classname, methodname, count)
275
+ end.sort_by{|r| r.count}.reverse
276
+ ref_blocks << [refs, label, format_call_ref]
277
+ end
278
+ end
279
+
280
+ def _get_callsites(ref_blocks, filename, lineno, linetext, label, &format_called_ref)
281
+ if @do_callsites and
282
+ (refs = cross_references_for(filename, lineno))
283
+ refs = refs.sort_by{|k,count| count}.map do |ref, count|
284
+ XRefHelper.new(ref.file, ref.line, ref.calling_class, ref.calling_method, count)
285
+ end.reverse
286
+ ref_blocks << [refs, label, format_called_ref]
287
+ end
288
+ end
289
+
290
+ end
291
+
292
+ end
@@ -0,0 +1,55 @@
1
+ module Rcov
2
+
3
+ class FullTextReport < BaseFormatter # :nodoc:
4
+ DEFAULT_OPTS = {:textmode => :coverage}
5
+
6
+ def initialize(opts = {})
7
+ options = DEFAULT_OPTS.clone.update(opts)
8
+ @textmode = options[:textmode]
9
+ @color = options[:color]
10
+ super(options)
11
+ end
12
+
13
+ def execute
14
+ each_file_pair_sorted do |filename, fileinfo|
15
+ puts "=" * 80
16
+ puts filename
17
+ puts "=" * 80
18
+ lines = SCRIPT_LINES__[filename]
19
+
20
+ unless lines
21
+ # try to get the source code from the global code coverage
22
+ # analyzer
23
+ re = /#{Regexp.escape(filename)}\z/
24
+ if $rcov_code_coverage_analyzer and
25
+ (data = $rcov_code_coverage_analyzer.data_matching(re))
26
+ lines = data[0]
27
+ end
28
+ end
29
+
30
+ (lines || []).each_with_index do |line, i|
31
+
32
+ case @textmode
33
+ when :counts
34
+ puts "%-70s| %6d" % [line.chomp[0,70], fileinfo.counts[i]]
35
+ when :gcc
36
+ puts "%s:%d:%s" % [filename, i+1, line.chomp] unless fileinfo.coverage[i]
37
+ when :coverage
38
+ if @color
39
+ prefix = fileinfo.coverage[i] ? "\e[32;40m" : "\e[31;40m"
40
+ puts "#{prefix}%s\e[37;40m" % line.chomp
41
+ else
42
+ prefix = fileinfo.coverage[i] ? " " : "!! "
43
+ puts "#{prefix}#{line}"
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+
55
+ end
@@ -0,0 +1,258 @@
1
+ module Rcov
2
+
3
+ class HTMLCoverage < BaseFormatter # :nodoc:
4
+ require 'fileutils'
5
+
6
+ DEFAULT_OPTS = {:color => false, :fsr => 30, :destdir => "coverage",
7
+ :callsites => false, :cross_references => false,
8
+ :validator_links => true, :charset => nil
9
+ }
10
+
11
+ def initialize(opts = {})
12
+ options = DEFAULT_OPTS.clone.update(opts)
13
+ super(options)
14
+ @dest = options[:destdir]
15
+ @color = options[:color]
16
+ @fsr = options[:fsr]
17
+ @do_callsites = options[:callsites]
18
+ @do_cross_references = options[:cross_references]
19
+ @span_class_index = 0
20
+ @show_validator_links = options[:validator_links]
21
+ @charset = options[:charset]
22
+ end
23
+
24
+ def execute
25
+ return if @files.empty?
26
+ FileUtils.mkdir_p @dest
27
+ css_file = File.expand_path("#{File.dirname(__FILE__)}/../templates/screen.css")
28
+ FileUtils.cp(css_file, File.join(@dest, "screen.css"))
29
+
30
+ create_index(File.join(@dest, "index.html"))
31
+
32
+ each_file_pair_sorted do |filename, fileinfo|
33
+ create_file(File.join(@dest, mangle_filename(filename)), fileinfo)
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ class SummaryFileInfo # :nodoc:
40
+
41
+ def initialize(obj)
42
+ @o = obj
43
+ end
44
+
45
+ def num_lines
46
+ @o.num_lines
47
+ end
48
+
49
+ def num_code_lines
50
+ @o.num_code_lines
51
+ end
52
+
53
+ def code_coverage
54
+ @o.code_coverage
55
+ end
56
+
57
+ def code_coverage_for_report
58
+ code_coverage * 100
59
+ end
60
+
61
+ def total_coverage
62
+ @o.total_coverage
63
+ end
64
+
65
+ def total_coverage_for_report
66
+ total_coverage * 100
67
+ end
68
+
69
+ def name
70
+ "TOTAL"
71
+ end
72
+
73
+ end
74
+
75
+ def create_index(destname)
76
+ files = [SummaryFileInfo.new(self)] + each_file_pair_sorted.map{|k,v| v}
77
+
78
+ doc = Document.new('index.html.erb', :title => 'C0 Coverage Information - RCov',
79
+ :generated_on => Time.now,
80
+ :rcov => Rcov,
81
+ :formatter => self,
82
+ :output_threshold => @output_threshold,
83
+ :files => files)
84
+
85
+ File.open(destname, "w") { |f| f.puts doc.render }
86
+ end
87
+
88
+
89
+ def create_file(destfile, fileinfo)
90
+ doc = Document.new('detail.html.erb', :title => fileinfo.name,
91
+ :generated_on => Time.now,
92
+ :rcov => Rcov,
93
+ :formatter => self,
94
+ :output_threshold => @output_threshold,
95
+ :file => fileinfo)
96
+ File.open(destfile, "w") { |f| f.puts doc.render }
97
+ end
98
+
99
+ end
100
+
101
+ class HTMLProfiling < HTMLCoverage # :nodoc:
102
+
103
+ DEFAULT_OPTS = {:destdir => "profiling"}
104
+ def initialize(opts = {})
105
+ options = DEFAULT_OPTS.clone.update(opts)
106
+ super(options)
107
+ @max_cache = {}
108
+ @median_cache = {}
109
+ end
110
+
111
+ def default_title
112
+ "Bogo-profile information"
113
+ end
114
+
115
+ def default_color
116
+ if @color
117
+ "rgb(179,205,255)"
118
+ else
119
+ "rgb(255, 255, 255)"
120
+ end
121
+ end
122
+
123
+ def output_color_table?
124
+ false
125
+ end
126
+
127
+ def span_class(sourceinfo, marked, count)
128
+ full_scale_range = @fsr # dB
129
+ nz_count = sourceinfo.counts.select{|x| x && x != 0}
130
+ nz_count << 1 # avoid div by 0
131
+ max = @max_cache[sourceinfo] ||= nz_count.max
132
+ #avg = @median_cache[sourceinfo] ||= 1.0 *
133
+ # nz_count.inject{|a,b| a+b} / nz_count.size
134
+ median = @median_cache[sourceinfo] ||= 1.0 * nz_count.sort[nz_count.size/2]
135
+ max ||= 2
136
+ max = 2 if max == 1
137
+ if marked == true
138
+ count = 1 if !count || count == 0
139
+ idx = 50 + 1.0 * (500/full_scale_range) * Math.log(count/median) / Math.log(10)
140
+ idx = idx.to_i
141
+ idx = 0 if idx < 0
142
+ idx = 100 if idx > 100
143
+ "run#{idx}"
144
+ else
145
+ nil
146
+ end
147
+ end
148
+
149
+ end
150
+
151
+ class RubyAnnotation < BaseFormatter # :nodoc:
152
+ DEFAULT_OPTS = { :destdir => "coverage" }
153
+ def initialize(opts = {})
154
+ options = DEFAULT_OPTS.clone.update(opts)
155
+ super(options)
156
+ @dest = options[:destdir]
157
+ @do_callsites = true
158
+ @do_cross_references = true
159
+
160
+ @mangle_filename = Hash.new{|h,base|
161
+ h[base] = Pathname.new(base).cleanpath.to_s.gsub(%r{^\w:[/\\]}, "").gsub(/\./, "_").gsub(/[\\\/]/, "-") + ".rb"
162
+ }
163
+ end
164
+
165
+ def execute
166
+ return if @files.empty?
167
+ FileUtils.mkdir_p @dest
168
+ each_file_pair_sorted do |filename, fileinfo|
169
+ create_file(File.join(@dest, mangle_filename(filename)), fileinfo)
170
+ end
171
+ end
172
+
173
+ private
174
+
175
+ def format_lines(file)
176
+ result = ""
177
+ format_line = "%#{file.num_lines.to_s.size}d"
178
+ file.num_lines.times do |i|
179
+ line = file.lines[i].chomp
180
+ marked = file.coverage[i]
181
+ count = file.counts[i]
182
+ result << create_cross_refs(file.name, i+1, line, marked) + "\n"
183
+ end
184
+ result
185
+ end
186
+
187
+ def create_cross_refs(filename, lineno, linetext, marked)
188
+ return linetext unless @callsite_analyzer && @do_callsites
189
+ ref_blocks = []
190
+ _get_defsites(ref_blocks, filename, lineno, linetext, ">>") do |ref|
191
+ if ref.file
192
+ ref.file.sub!(%r!^./!, '')
193
+ where = "at #{mangle_filename(ref.file)}:#{ref.line}"
194
+ else
195
+ where = "(C extension/core)"
196
+ end
197
+ "#{ref.klass}##{ref.mid} " + where + ""
198
+ end
199
+ _get_callsites(ref_blocks, filename, lineno, linetext, "<<") do |ref| # "
200
+ ref.file.sub!(%r!^./!, '')
201
+ "#{mangle_filename(ref.file||'C code')}:#{ref.line} " +
202
+ "in #{ref.klass}##{ref.mid}"
203
+ end
204
+
205
+ create_cross_reference_block(linetext, ref_blocks, marked)
206
+ end
207
+
208
+ def create_cross_reference_block(linetext, ref_blocks, marked)
209
+ codelen = 75
210
+ if ref_blocks.empty?
211
+ if marked
212
+ return "%-#{codelen}s #o" % linetext
213
+ else
214
+ return linetext
215
+ end
216
+ end
217
+ ret = ""
218
+ @cross_ref_idx ||= 0
219
+ @known_files ||= sorted_file_pairs.map{|fname, finfo| normalize_filename(fname)}
220
+ ret << "%-#{codelen}s # " % linetext
221
+ ref_blocks.each do |refs, toplabel, label_proc|
222
+ unless !toplabel || toplabel.empty?
223
+ ret << toplabel << " "
224
+ end
225
+ refs.each do |dst|
226
+ dstfile = normalize_filename(dst.file) if dst.file
227
+ dstline = dst.line
228
+ label = label_proc.call(dst)
229
+ if dst.file && @known_files.include?(dstfile)
230
+ ret << "[[" << label << "]], "
231
+ else
232
+ ret << label << ", "
233
+ end
234
+ end
235
+ end
236
+
237
+ ret
238
+ end
239
+
240
+ def create_file(destfile, fileinfo)
241
+ #body = format_lines(fileinfo)
242
+ #File.open(destfile, "w") do |f|
243
+ #f.puts body
244
+ #f.puts footer(fileinfo)
245
+ #end
246
+ end
247
+
248
+ def footer(fileinfo)
249
+ s = "# Total lines : %d\n" % fileinfo.num_lines
250
+ s << "# Lines of code : %d\n" % fileinfo.num_code_lines
251
+ s << "# Total coverage : %3.1f%%\n" % [ fileinfo.total_coverage*100 ]
252
+ s << "# Code coverage : %3.1f%%\n\n" % [ fileinfo.code_coverage*100 ]
253
+ # prevents false positives on Emacs
254
+ s << "# Local " "Variables:\n" "# mode: " "rcov-xref\n" "# End:\n"
255
+ end
256
+ end
257
+
258
+ end