khall-metric_fu 1.0.2.1
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/HISTORY +119 -0
- data/MIT-LICENSE +22 -0
- data/Manifest.txt +25 -0
- data/README +1 -0
- data/Rakefile +46 -0
- data/TODO +14 -0
- data/lib/base/base_template.rb +134 -0
- data/lib/base/configuration.rb +187 -0
- data/lib/base/generator.rb +147 -0
- data/lib/base/md5_tracker.rb +52 -0
- data/lib/base/report.rb +100 -0
- data/lib/generators/churn.rb +86 -0
- data/lib/generators/flay.rb +29 -0
- data/lib/generators/flog.rb +127 -0
- data/lib/generators/rcov.rb +77 -0
- data/lib/generators/reek.rb +32 -0
- data/lib/generators/roodi.rb +24 -0
- data/lib/generators/saikuro.rb +212 -0
- data/lib/generators/stats.rb +43 -0
- data/lib/metric_fu.rb +20 -0
- data/lib/templates/standard/churn.html.erb +30 -0
- data/lib/templates/standard/default.css +64 -0
- data/lib/templates/standard/flay.html.erb +33 -0
- data/lib/templates/standard/flog.html.erb +52 -0
- data/lib/templates/standard/index.html.erb +38 -0
- data/lib/templates/standard/rcov.html.erb +42 -0
- data/lib/templates/standard/reek.html.erb +41 -0
- data/lib/templates/standard/roodi.html.erb +28 -0
- data/lib/templates/standard/saikuro.html.erb +83 -0
- data/lib/templates/standard/standard_template.rb +26 -0
- data/lib/templates/standard/stats.html.erb +54 -0
- data/spec/base/base_template_spec.rb +140 -0
- data/spec/base/configuration_spec.rb +303 -0
- data/spec/base/generator_spec.rb +159 -0
- data/spec/base/md5_tracker_spec.rb +57 -0
- data/spec/base/report_spec.rb +139 -0
- data/spec/generators/churn_spec.rb +152 -0
- data/spec/generators/flay_spec.rb +101 -0
- data/spec/generators/flog_spec.rb +200 -0
- data/spec/generators/reek_spec.rb +59 -0
- data/spec/generators/saikuro_spec.rb +53 -0
- data/spec/generators/stats_spec.rb +74 -0
- data/spec/spec_helper.rb +28 -0
- data/tasks/metric_fu.rake +15 -0
- data/tasks/railroad.rake +39 -0
- data/vendor/saikuro/saikuro.rb +1214 -0
- metadata +163 -0
@@ -0,0 +1,212 @@
|
|
1
|
+
module MetricFu
|
2
|
+
|
3
|
+
class Saikuro < Generator
|
4
|
+
|
5
|
+
|
6
|
+
def emit
|
7
|
+
relative_path = [File.dirname(__FILE__), '..', '..',
|
8
|
+
'vendor', 'saikuro', 'saikuro.rb']
|
9
|
+
saikuro = File.expand_path(File.join(relative_path))
|
10
|
+
|
11
|
+
format_directories
|
12
|
+
|
13
|
+
options_string = MetricFu.saikuro.inject("") do |options, option|
|
14
|
+
options + "--#{option.join(' ')} "
|
15
|
+
end
|
16
|
+
|
17
|
+
sh %{ruby "#{saikuro}" #{options_string}} do |ok, response|
|
18
|
+
unless ok
|
19
|
+
puts "Saikuro failed with exit status: #{response.exitstatus}"
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def format_directories
|
26
|
+
dirs = MetricFu.saikuro[:input_directory].join(" | ")
|
27
|
+
dirs = "\"#{dirs}\""
|
28
|
+
MetricFu.saikuro[:input_directory] = dirs
|
29
|
+
end
|
30
|
+
|
31
|
+
def analyze
|
32
|
+
@files = []
|
33
|
+
saikuro_results.each do |path|
|
34
|
+
if Saikuro::SFile.is_valid_text_file?(path)
|
35
|
+
file = Saikuro::SFile.new(path)
|
36
|
+
if file
|
37
|
+
@files << file
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
@files = @files.sort_by do |file|
|
42
|
+
file.elements.
|
43
|
+
max {|a,b| a.complexity.to_i <=> b.complexity.to_i}.
|
44
|
+
complexity.to_i
|
45
|
+
end
|
46
|
+
@files.reverse!
|
47
|
+
klasses = []
|
48
|
+
@files.each {|f| klasses << f.elements}
|
49
|
+
klasses.flatten!
|
50
|
+
@classes = klasses.sort_by {|k| k.complexity.to_i}
|
51
|
+
@classes.reverse!
|
52
|
+
meths = []
|
53
|
+
@files.each {|f|
|
54
|
+
f.elements.each {|el|
|
55
|
+
el.defs.each {|defn|
|
56
|
+
defn.name = "#{el.name}##{defn.name}"
|
57
|
+
meths << defn}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
meths = meths.sort_by {|meth| meth.complexity.to_i}
|
61
|
+
@meths = meths.reverse
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_h
|
66
|
+
files = @files.map do |file|
|
67
|
+
my_file = file.to_h
|
68
|
+
my_file[:filename] = file.filename
|
69
|
+
my_file
|
70
|
+
end
|
71
|
+
{:saikuro => {:files => files,
|
72
|
+
:classes => @classes.map {|c| c.to_h},
|
73
|
+
:methods => @meths.map {|m| m.to_h}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
def saikuro_results
|
79
|
+
Dir.glob("#{metric_directory}/**/*.html")
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
class Saikuro::SFile
|
88
|
+
|
89
|
+
attr_reader :elements
|
90
|
+
|
91
|
+
def initialize(path)
|
92
|
+
@path = path
|
93
|
+
@file_handle = File.open(@path, "r")
|
94
|
+
@elements = []
|
95
|
+
get_elements
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.is_valid_text_file?(path)
|
99
|
+
File.open(path, "r") do |f|
|
100
|
+
if f.eof? || !f.readline.match /--/
|
101
|
+
return false
|
102
|
+
else
|
103
|
+
return true
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def filename
|
109
|
+
File.basename(@path, '_cyclo.html')
|
110
|
+
end
|
111
|
+
|
112
|
+
def to_h
|
113
|
+
merge_classes
|
114
|
+
{:classes => @elements}
|
115
|
+
end
|
116
|
+
|
117
|
+
def get_elements
|
118
|
+
begin
|
119
|
+
while (line = @file_handle.readline) do
|
120
|
+
return [] if line.blank?
|
121
|
+
if line.match /START/
|
122
|
+
line = @file_handle.readline
|
123
|
+
element = Saikuro::ParsingElement.new(line)
|
124
|
+
elsif line.match /END/
|
125
|
+
@elements << element
|
126
|
+
element = nil
|
127
|
+
else
|
128
|
+
element << line
|
129
|
+
end
|
130
|
+
end
|
131
|
+
rescue EOFError
|
132
|
+
nil
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
def merge_classes
|
138
|
+
new_elements = []
|
139
|
+
get_class_names.each do |target_class|
|
140
|
+
elements = @elements.find_all {|el| el.name == target_class }
|
141
|
+
complexity = 0
|
142
|
+
lines = 0
|
143
|
+
defns = []
|
144
|
+
elements.each do |el|
|
145
|
+
complexity += el.complexity.to_i
|
146
|
+
lines += el.lines.to_i
|
147
|
+
defns << el.defs
|
148
|
+
end
|
149
|
+
|
150
|
+
new_element = {:class_name => target_class,
|
151
|
+
:complexity => complexity,
|
152
|
+
:lines => lines,
|
153
|
+
:methods => defns.flatten.map {|d| d.to_h}}
|
154
|
+
new_element[:methods] = new_element[:methods].
|
155
|
+
sort_by {|x| x[:complexity] }.
|
156
|
+
reverse
|
157
|
+
|
158
|
+
new_elements << new_element
|
159
|
+
end
|
160
|
+
@elements = new_elements if new_elements
|
161
|
+
end
|
162
|
+
|
163
|
+
def get_class_names
|
164
|
+
class_names = []
|
165
|
+
@elements.each do |element|
|
166
|
+
unless class_names.include?(element.name)
|
167
|
+
class_names << element.name
|
168
|
+
end
|
169
|
+
end
|
170
|
+
class_names
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
class Saikuro::ParsingElement
|
176
|
+
TYPE_REGEX=/Type:(.*) Name/
|
177
|
+
NAME_REGEX=/Name:(.*) Complexity/
|
178
|
+
COMPLEXITY_REGEX=/Complexity:(.*) Lines/
|
179
|
+
LINES_REGEX=/Lines:(.*)/
|
180
|
+
|
181
|
+
attr_reader :complexity, :lines, :defs, :element_type
|
182
|
+
attr_accessor :name
|
183
|
+
|
184
|
+
def initialize(line)
|
185
|
+
@line = line
|
186
|
+
@element_type = line.match(TYPE_REGEX)[1].strip
|
187
|
+
@name = line.match(NAME_REGEX)[1].strip
|
188
|
+
@complexity = line.match(COMPLEXITY_REGEX)[1].strip
|
189
|
+
@lines = line.match(LINES_REGEX)[1].strip
|
190
|
+
@defs = []
|
191
|
+
end
|
192
|
+
|
193
|
+
def <<(line)
|
194
|
+
@defs << Saikuro::ParsingElement.new(line)
|
195
|
+
end
|
196
|
+
|
197
|
+
def to_h
|
198
|
+
base = {:name => @name, :complexity => @complexity.to_i, :lines => @lines.to_i}
|
199
|
+
unless @defs.empty?
|
200
|
+
defs = @defs.map do |my_def|
|
201
|
+
my_def = my_def.to_h
|
202
|
+
my_def.delete(:defs)
|
203
|
+
my_def
|
204
|
+
end
|
205
|
+
base[:defs] = defs
|
206
|
+
end
|
207
|
+
return base
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
|
212
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module MetricFu
|
2
|
+
|
3
|
+
class Stats < Generator
|
4
|
+
|
5
|
+
def emit
|
6
|
+
`rake stats > #{metric_directory + '/stats.txt'}`
|
7
|
+
end
|
8
|
+
|
9
|
+
def analyze
|
10
|
+
output = File.open(metric_directory + '/stats.txt').read
|
11
|
+
output = output.split("\n")
|
12
|
+
output = output.find_all {|line| line[0].chr != "+" }
|
13
|
+
output = output.find_all {|line| line[0].chr != "(" }
|
14
|
+
output.shift
|
15
|
+
totals = output.pop
|
16
|
+
totals = totals.split(" ").find_all {|el| ! el.empty? }
|
17
|
+
@stats = {}
|
18
|
+
@stats[:codeLOC] = totals[0].match(/\d.*/)[0].to_i
|
19
|
+
@stats[:testLOC] = totals[1].match(/\d.*/)[0].to_i
|
20
|
+
@stats[:code_to_test_ratio] = totals[2].match(/1\:(\d.*)/)[1].to_f
|
21
|
+
|
22
|
+
@stats[:lines] = output.map do |line|
|
23
|
+
elements = line.split("|")
|
24
|
+
elements.map! {|el| el.strip }
|
25
|
+
elements = elements.find_all {|el| ! el.empty? }
|
26
|
+
info_line = {}
|
27
|
+
info_line[:name] = elements.shift
|
28
|
+
elements.map! {|el| el.to_i }
|
29
|
+
[:lines, :loc, :classes, :methods,
|
30
|
+
:methods_per_class, :loc_per_method].each do |sym|
|
31
|
+
info_line[sym] = elements.shift
|
32
|
+
end
|
33
|
+
info_line
|
34
|
+
end
|
35
|
+
@stats
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_h
|
39
|
+
{:stats => @stats}
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
data/lib/metric_fu.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# Load a few things to make our lives easier elsewhere.
|
2
|
+
module MetricFu
|
3
|
+
LIB_ROOT = File.dirname(__FILE__)
|
4
|
+
end
|
5
|
+
base_dir = File.join(MetricFu::LIB_ROOT, 'base')
|
6
|
+
generator_dir = File.join(MetricFu::LIB_ROOT, 'generators')
|
7
|
+
template_dir = File.join(MetricFu::LIB_ROOT, 'templates')
|
8
|
+
|
9
|
+
# We need to require these two things first because our other classes
|
10
|
+
# depend on them.
|
11
|
+
require File.join(base_dir, 'report')
|
12
|
+
require File.join(base_dir, 'generator')
|
13
|
+
|
14
|
+
# Load the rakefile so users of the gem get the default metric_fu task
|
15
|
+
load File.join(MetricFu::LIB_ROOT, '..', 'tasks', 'metric_fu.rake')
|
16
|
+
|
17
|
+
# Now load everything else that's in the directory
|
18
|
+
Dir[File.join(base_dir, '*.rb')].each{|l| require l }
|
19
|
+
Dir[File.join(generator_dir, '*.rb')].each {|l| require l }
|
20
|
+
Dir[File.join(template_dir, 'standard/*.rb')].each {|l| require l}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Source Control Churn Results</title>
|
4
|
+
<style>
|
5
|
+
<%= inline_css("default.css") %>
|
6
|
+
</style>
|
7
|
+
</head>
|
8
|
+
|
9
|
+
<body>
|
10
|
+
<h1>Source Control Churn Results</h1>
|
11
|
+
<p>Files that change a lot in your project may be bad a sign.
|
12
|
+
This task uses your source control log to identify those files.
|
13
|
+
</p>
|
14
|
+
<table>
|
15
|
+
<tr>
|
16
|
+
<th>File Path</th>
|
17
|
+
<th>Times Changed</th>
|
18
|
+
</tr>
|
19
|
+
<% count = 0 %>
|
20
|
+
<% @churn[:changes].each do |change| %>
|
21
|
+
<tr>
|
22
|
+
<td><%= change[:file_path] %></td>
|
23
|
+
<td><%= change[:times_changed] %></td>
|
24
|
+
</tr>
|
25
|
+
<% count += 1 %>
|
26
|
+
<% end %>
|
27
|
+
</table>
|
28
|
+
<p>Generated on <%= Time.now.localtime %></p>
|
29
|
+
</body>
|
30
|
+
</html>
|
@@ -0,0 +1,64 @@
|
|
1
|
+
body {
|
2
|
+
background-color: #efefef;
|
3
|
+
margin: 20px;
|
4
|
+
padding: 0;
|
5
|
+
font: 12px verdana, arial, helvetica;
|
6
|
+
}
|
7
|
+
|
8
|
+
table {
|
9
|
+
border-collapse: collapse;
|
10
|
+
border: 1px solid #666;
|
11
|
+
background: #fff;
|
12
|
+
margin-bottom: 20px;
|
13
|
+
}
|
14
|
+
|
15
|
+
table tr.light {
|
16
|
+
background: #fff;
|
17
|
+
}
|
18
|
+
|
19
|
+
table tr.dark {
|
20
|
+
background: #f9f9f9;
|
21
|
+
}
|
22
|
+
|
23
|
+
table td, table th {
|
24
|
+
padding: 4px 10px;
|
25
|
+
font-size: 13px;
|
26
|
+
}
|
27
|
+
table th {
|
28
|
+
text-align: center;
|
29
|
+
color: #fc0;
|
30
|
+
background: #336;
|
31
|
+
font-weight: bold;
|
32
|
+
border: #d0d0d0 1px solid;
|
33
|
+
}
|
34
|
+
|
35
|
+
table td {
|
36
|
+
border: #d0d0d0 1px solid;
|
37
|
+
}
|
38
|
+
|
39
|
+
table td.score {
|
40
|
+
text-align: right;
|
41
|
+
}
|
42
|
+
|
43
|
+
.warning {
|
44
|
+
background: yellow;
|
45
|
+
}
|
46
|
+
.rcov_code td {
|
47
|
+
border-bottom: 1px solid #ddd ;
|
48
|
+
padding: 0;
|
49
|
+
margin: 0;
|
50
|
+
}
|
51
|
+
.rcov_code tr {
|
52
|
+
border: 0px;
|
53
|
+
padding:0px;
|
54
|
+
margin: 0px;
|
55
|
+
}
|
56
|
+
.rcov_code pre {
|
57
|
+
border: 0px;
|
58
|
+
padding: 0px;
|
59
|
+
margin: 0px;
|
60
|
+
}
|
61
|
+
.rcov_run {}
|
62
|
+
.rcov_not_run {
|
63
|
+
background-color: #d88;
|
64
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Flay Results</title>
|
4
|
+
<style>
|
5
|
+
<%= inline_css("default.css") %>
|
6
|
+
</style>
|
7
|
+
</head>
|
8
|
+
|
9
|
+
<body>
|
10
|
+
<h1>Flay Results</h1>
|
11
|
+
<h2>Total Score (lower is better): <%= @flay[:total_score] %></h2>
|
12
|
+
<p><a href='http://ruby.sadi.st/Flay.html'>Flay</a> analyzes ruby code for structural similarities.</p>
|
13
|
+
<table>
|
14
|
+
<tr>
|
15
|
+
<th>Files</th>
|
16
|
+
<th>Matches</th>
|
17
|
+
</tr>
|
18
|
+
<% count = 0 %>
|
19
|
+
<% @flay[:matches].each do |match| %>
|
20
|
+
<tr class='<%= cycle("light", "dark", count) %>'>
|
21
|
+
<td>
|
22
|
+
<% match[:matches].each do |file| %>
|
23
|
+
<%= file[:name] %>:<%= file[:line] %><br />
|
24
|
+
<% end %>
|
25
|
+
</td>
|
26
|
+
<td><%= match[:reason] %></td>
|
27
|
+
</tr>
|
28
|
+
<% count += 1 %>
|
29
|
+
<% end %>
|
30
|
+
</table>
|
31
|
+
<p>Generated on <%= Time.now.localtime %></p>
|
32
|
+
</body>
|
33
|
+
</html>
|
@@ -0,0 +1,52 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Flog Reporter</title>
|
4
|
+
<style>
|
5
|
+
<%= inline_css("default.css") %>
|
6
|
+
</style>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<h1>Flog Results</h1>
|
10
|
+
<p><a href='http://ruby.sadi.st/Flog.html'>Flog</a> measures code complexity.</p>
|
11
|
+
<h2>Total Flog score for all methods: <%= @flog[:total]%></h2>
|
12
|
+
<h2>Average Flog score for all methods: <%= @flog[:average]%></h2>
|
13
|
+
<table>
|
14
|
+
<tr>
|
15
|
+
<th>File</th>
|
16
|
+
<th>Total score</th>
|
17
|
+
<th>Methods</th>
|
18
|
+
<th>Average score</th>
|
19
|
+
<th>Highest score</th>
|
20
|
+
</tr>
|
21
|
+
<% @flog[:pages].each do |page| %>
|
22
|
+
<tr>
|
23
|
+
<td><%= page[:path] %></td>
|
24
|
+
<td><%= page[:score].round %></td>
|
25
|
+
<td><%= page[:scanned_methods].length %></td>
|
26
|
+
<td><%= page[:average_score].round %></td>
|
27
|
+
<td><%= page[:highest_score].round %></td>
|
28
|
+
</tr>
|
29
|
+
<% end %>
|
30
|
+
</table>
|
31
|
+
|
32
|
+
<% @flog[:pages].each do |page| %>
|
33
|
+
<h2><%= page[:path] %></h2>
|
34
|
+
<% page[:scanned_methods].each do |sm| %>
|
35
|
+
<p><%= sm[:name] %></p>
|
36
|
+
<table>
|
37
|
+
<tr>
|
38
|
+
<th>Score</th>
|
39
|
+
<th>Operator</th>
|
40
|
+
</tr>
|
41
|
+
<% sm[:operators].each do |operator| %>
|
42
|
+
<tr>
|
43
|
+
<td><%= operator[:score] %></td>
|
44
|
+
<td><%= operator[:operator] %></td>
|
45
|
+
</tr>
|
46
|
+
<% end %>
|
47
|
+
</table>
|
48
|
+
<% end %>
|
49
|
+
<% end %>
|
50
|
+
<p>Generated on <%= Time.now.localtime %></p>
|
51
|
+
</body>
|
52
|
+
</html>
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Metric Fu Results</title>
|
4
|
+
<style>
|
5
|
+
<%= inline_css("default.css") %>
|
6
|
+
</style>
|
7
|
+
</head>
|
8
|
+
|
9
|
+
<body>
|
10
|
+
<h1>Metric Fu Results</h1>
|
11
|
+
<% if @churn %>
|
12
|
+
<p><a href="churn.html">Churn report</a></p>
|
13
|
+
<% end %>
|
14
|
+
<% if @flay %>
|
15
|
+
<p><a href="flay.html">Flay report</a></p>
|
16
|
+
<% end %>
|
17
|
+
<% if @flog %>
|
18
|
+
<p><a href="flog.html">Flog report</a></p>
|
19
|
+
<% end %>
|
20
|
+
<% if @rcov %>
|
21
|
+
<p><a href="rcov.html">Rcov report</a></p>
|
22
|
+
<% end %>
|
23
|
+
<% if @reek %>
|
24
|
+
<p><a href="reek.html">Reek report</a></p>
|
25
|
+
<% end %>
|
26
|
+
<% if @roodi %>
|
27
|
+
<p><a href="roodi.html">Roodi report</a></p>
|
28
|
+
<% end %>
|
29
|
+
<% if @saikuro %>
|
30
|
+
<p><a href="saikuro.html">Saikuro report</a></p>
|
31
|
+
<% end %>
|
32
|
+
<% if @stats %>
|
33
|
+
<p><a href="stats.html">Stats report</a></p>
|
34
|
+
<% end %>
|
35
|
+
<p>Generated on <%= Time.now.localtime %></p>
|
36
|
+
</body>
|
37
|
+
</html>
|
38
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Rcov Code Coverage Results</title>
|
4
|
+
<style>
|
5
|
+
<%= inline_css("default.css") %>
|
6
|
+
</style>
|
7
|
+
</head>
|
8
|
+
|
9
|
+
<body>
|
10
|
+
<h1>Rcov Code Coverage Results</h1>
|
11
|
+
<p>C0 code coverage information.</p>
|
12
|
+
<p>Total Coverage: <%= @rcov.delete(:global_percent_run) %>% </p>
|
13
|
+
<table>
|
14
|
+
<tr>
|
15
|
+
<th>File Path</th>
|
16
|
+
<th>Percent run</th>
|
17
|
+
</tr>
|
18
|
+
<% count = 0 %>
|
19
|
+
<% @rcov.each_pair do |fname, file| %>
|
20
|
+
<tr>
|
21
|
+
<td><%= fname %></td>
|
22
|
+
<td><%= file[:percent_run] %></td>
|
23
|
+
</tr>
|
24
|
+
<% count += 1 %>
|
25
|
+
<% end %>
|
26
|
+
</table>
|
27
|
+
|
28
|
+
<% @rcov.each_pair do |fname, file| %>
|
29
|
+
<h2> <%= fname %></h2>
|
30
|
+
<table class="rcov_code">
|
31
|
+
<% file[:lines].each do |line| %>
|
32
|
+
<tr>
|
33
|
+
<% css_class = line[:was_run] ? "rcov_run" : "rcov_not_run" %>
|
34
|
+
<td class="<%= css_class %>"><pre><%= line[:content] %></pre></td>
|
35
|
+
</tr>
|
36
|
+
<% end %>
|
37
|
+
</table>
|
38
|
+
<% end %>
|
39
|
+
<p>Generated on <%= Time.now.localtime %></p>
|
40
|
+
</body>
|
41
|
+
</html>
|
42
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Reek Results</title>
|
4
|
+
<style>
|
5
|
+
<%= inline_css("default.css") %>
|
6
|
+
</style>
|
7
|
+
</head>
|
8
|
+
|
9
|
+
<body>
|
10
|
+
<h1>Reek Results</h1>
|
11
|
+
<p><a href="http://reek.rubyforge.org/">Reek</a> detects common code smells in ruby code.</p>
|
12
|
+
<table>
|
13
|
+
<tr>
|
14
|
+
<th>File Path</th>
|
15
|
+
<th>Method</th>
|
16
|
+
<th>Description</th>
|
17
|
+
<th>Type</th>
|
18
|
+
</tr>
|
19
|
+
<% count = 0 %>
|
20
|
+
<% @reek[:matches].each do |match| %>
|
21
|
+
<% match[:code_smells].each do |smell| %>
|
22
|
+
<tr class='<%= cycle("light", "dark", count) %>'>
|
23
|
+
<td><%= match[:file_path] %></td>
|
24
|
+
<td>
|
25
|
+
<%= smell[:method] %>
|
26
|
+
</td>
|
27
|
+
<td>
|
28
|
+
<%= smell[:message] %>
|
29
|
+
</td>
|
30
|
+
<td>
|
31
|
+
<%= smell[:type] %>
|
32
|
+
</td>
|
33
|
+
</tr>
|
34
|
+
<% count += 1 %>
|
35
|
+
<% end %>
|
36
|
+
<% end %>
|
37
|
+
|
38
|
+
</table>
|
39
|
+
<p>Generated on <%= Time.now.localtime %></p>
|
40
|
+
</body>
|
41
|
+
</html>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Roodi Results</title>
|
4
|
+
<style>
|
5
|
+
<%= inline_css("default.css") %>
|
6
|
+
</style>
|
7
|
+
</head>
|
8
|
+
|
9
|
+
<body>
|
10
|
+
<h1>Roodi Results</h1>
|
11
|
+
<p><a href="http://roodi.rubyforge.org/">Roodi</a> parses your Ruby code and warns you about design issues you have based on the checks that is has configured.</p>
|
12
|
+
<table>
|
13
|
+
<tr>
|
14
|
+
<th>File Path</th>
|
15
|
+
<th>Warning</th>
|
16
|
+
</tr>
|
17
|
+
<% count = 0 %>
|
18
|
+
<% @roodi[:problems].each do |problem| %>
|
19
|
+
<tr class='<%= cycle("light", "dark", count) %>'>
|
20
|
+
<td><%= problem[:file] %>:<%= problem[:line] %></td>
|
21
|
+
<td><%= problem[:problem] %></td>
|
22
|
+
</tr>
|
23
|
+
<% count += 1 %>
|
24
|
+
<% end %>
|
25
|
+
</table>
|
26
|
+
<p>Generated on <%= Time.now.localtime %></p>
|
27
|
+
</body>
|
28
|
+
</html>
|
@@ -0,0 +1,83 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Saikuro Results</title>
|
4
|
+
<style>
|
5
|
+
<%= inline_css("default.css") %>
|
6
|
+
</style>
|
7
|
+
</head>
|
8
|
+
|
9
|
+
<body>
|
10
|
+
<h1>Saikuro Results</h1>
|
11
|
+
<p><a href='http://saikuro.rubyforge.org/'>Saikuro</a> analyzes ruby code for cyclomatic complexity.</p>
|
12
|
+
|
13
|
+
<h2>Analyzed Methods</h2>
|
14
|
+
<table>
|
15
|
+
<tr>
|
16
|
+
<th>Method Name</th>
|
17
|
+
<th>Complexity</th>
|
18
|
+
<th># Lines</th>
|
19
|
+
</tr>
|
20
|
+
<% @saikuro[:methods].each do |method| %>
|
21
|
+
<tr>
|
22
|
+
<td><%= method[:name] %></td>
|
23
|
+
<td><%= method[:complexity] %></td>
|
24
|
+
<td><%= method[:lines] %></td>
|
25
|
+
</tr>
|
26
|
+
<% end %>
|
27
|
+
</table>
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
<h2>Analyzed Classes</h2>
|
32
|
+
<table>
|
33
|
+
<tr>
|
34
|
+
<th>Class Name</th>
|
35
|
+
<th>Complexity</th>
|
36
|
+
<th># Lines</th>
|
37
|
+
</tr>
|
38
|
+
<% @saikuro[:classes].each do |klass| %>
|
39
|
+
<tr>
|
40
|
+
<td><%= klass[:name] %></td>
|
41
|
+
<td><%= klass[:complexity] %></td>
|
42
|
+
<td><%= klass[:lines] %></td>
|
43
|
+
</tr>
|
44
|
+
<% end %>
|
45
|
+
</table>
|
46
|
+
|
47
|
+
|
48
|
+
<h2>Analyzed Files</h2>
|
49
|
+
<% @saikuro[:files].each do |file| %>
|
50
|
+
<% file[:classes].each do |klass| %>
|
51
|
+
<% if !klass[:methods].empty? %>
|
52
|
+
<h3><%= file[:filename] %></h3>
|
53
|
+
<h4>Class : <%= klass[:class_name] %></h4>
|
54
|
+
<h5>Total complexity : <%= klass[:complexity] %></h5>
|
55
|
+
<h5>Total lines : <%= klass[:lines] %></h5>
|
56
|
+
<table>
|
57
|
+
<tr>
|
58
|
+
<th>Method</th>
|
59
|
+
<th>Complexity</th>
|
60
|
+
<th># Lines</th>
|
61
|
+
</tr>
|
62
|
+
<% klass[:methods].each do |method| %>
|
63
|
+
<tr>
|
64
|
+
<td>
|
65
|
+
<%= method[:name] %>
|
66
|
+
</td>
|
67
|
+
<td>
|
68
|
+
<%= method[:complexity] %>
|
69
|
+
</td>
|
70
|
+
<td>
|
71
|
+
<%= method[:lines] %>
|
72
|
+
</td>
|
73
|
+
</tr>
|
74
|
+
<% end %>
|
75
|
+
</table>
|
76
|
+
<% end %>
|
77
|
+
<% end %>
|
78
|
+
<% end %>
|
79
|
+
|
80
|
+
<p>Generated on <%= Time.now.localtime %></p>
|
81
|
+
</body>
|
82
|
+
</html>
|
83
|
+
|