relevance-rcov 0.8.2.1 → 0.8.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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