metric_fu 4.2.1 → 4.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.metrics +19 -1
- data/.travis.yml +2 -2
- data/Gemfile +2 -1
- data/HISTORY.md +24 -0
- data/README.md +60 -1
- data/TODO.md +1 -0
- data/bin/mf-saikuro +8 -0
- data/checksum/metric_fu-4.3.0.gem.sha512 +1 -0
- data/gemfiles/Gemfile.travis +9 -0
- data/lib/metric_fu.rb +1 -1
- data/lib/metric_fu/cli/client.rb +2 -2
- data/lib/metric_fu/cli/helper.rb +3 -3
- data/lib/metric_fu/cli/parser.rb +37 -16
- data/lib/metric_fu/configuration.rb +9 -1
- data/lib/metric_fu/constantize.rb +57 -0
- data/lib/metric_fu/data_structures/line_numbers.rb +19 -3
- data/lib/metric_fu/data_structures/location.rb +8 -3
- data/lib/metric_fu/formatter.rb +24 -0
- data/lib/metric_fu/formatter/html.rb +91 -0
- data/lib/metric_fu/formatter/yaml.rb +18 -0
- data/lib/metric_fu/initial_requires.rb +0 -1
- data/lib/metric_fu/io.rb +69 -0
- data/lib/metric_fu/load_files.rb +5 -2
- data/lib/metric_fu/logging/mf_debugger.rb +23 -0
- data/lib/metric_fu/metrics/base_template.rb +10 -4
- data/lib/metric_fu/metrics/cane/cane.rb +2 -1
- data/lib/metric_fu/metrics/cane/cane_bluff_grapher.rb +10 -9
- data/lib/metric_fu/metrics/cane/cane_gchart_grapher.rb +25 -0
- data/lib/metric_fu/metrics/flay/flay_bluff_grapher.rb +10 -9
- data/lib/metric_fu/metrics/flay/flay_gchart_grapher.rb +14 -11
- data/lib/metric_fu/metrics/flog/flog_bluff_grapher.rb +11 -10
- data/lib/metric_fu/metrics/flog/flog_gchart_grapher.rb +22 -15
- data/lib/metric_fu/metrics/generator.rb +10 -10
- data/lib/metric_fu/metrics/graph.rb +2 -2
- data/lib/metric_fu/metrics/hotspots/analysis/scoring_strategies.rb +3 -3
- data/lib/metric_fu/metrics/hotspots/hotspot.rb +4 -3
- data/lib/metric_fu/metrics/hotspots/hotspot_analyzer.rb +19 -10
- data/lib/metric_fu/metrics/hotspots/hotspots.rb +1 -1
- data/lib/metric_fu/metrics/hotspots/template_awesome/hotspots.html.erb +45 -45
- data/lib/metric_fu/metrics/rails_best_practices/rails_best_practices_bluff_grapher.rb +10 -9
- data/lib/metric_fu/metrics/rails_best_practices/rails_best_practices_gchart_grapher.rb +21 -15
- data/lib/metric_fu/metrics/rcov/rcov.rb +1 -1
- data/lib/metric_fu/metrics/rcov/rcov_bluff_grapher.rb +10 -9
- data/lib/metric_fu/metrics/rcov/rcov_gchart_grapher.rb +13 -8
- data/lib/metric_fu/metrics/reek/reek_bluff_grapher.rb +9 -13
- data/lib/metric_fu/metrics/reek/reek_gchart_grapher.rb +22 -17
- data/lib/metric_fu/metrics/roodi/roodi_bluff_grapher.rb +10 -9
- data/lib/metric_fu/metrics/roodi/roodi_gchart_grapher.rb +14 -11
- data/lib/metric_fu/metrics/saikuro/saikuro.rb +5 -34
- data/lib/metric_fu/metrics/stats/stats.rb +2 -1
- data/lib/metric_fu/metrics/stats/stats_bluff_grapher.rb +11 -10
- data/lib/metric_fu/metrics/stats/stats_gchart_grapher.rb +21 -14
- data/lib/metric_fu/reporter.rb +37 -0
- data/lib/metric_fu/reporting/graphs/engines/bluff.rb +20 -0
- data/lib/metric_fu/reporting/graphs/engines/gchart.rb +41 -3
- data/lib/metric_fu/reporting/graphs/grapher.rb +9 -2
- data/lib/metric_fu/reporting/result.rb +51 -0
- data/lib/metric_fu/reporting/templates/awesome/awesome_template.rb +8 -8
- data/lib/metric_fu/run.rb +34 -39
- data/lib/metric_fu/version.rb +1 -1
- data/lib/metric_fu_requires.rb +50 -33
- data/metric_fu.gemspec +30 -39
- data/spec/cli/helper_spec.rb +15 -0
- data/spec/metric_fu/configuration_spec.rb +40 -2
- data/spec/metric_fu/formatter/html_spec.rb +134 -0
- data/spec/metric_fu/formatter/yaml_spec.rb +59 -0
- data/spec/metric_fu/formatter_spec.rb +49 -0
- data/spec/metric_fu/metrics/base_template_spec.rb +23 -23
- data/spec/metric_fu/metrics/cane/cane_spec.rb +2 -2
- data/spec/metric_fu/metrics/churn/churn_spec.rb +1 -1
- data/spec/metric_fu/metrics/flay/flay_spec.rb +4 -4
- data/spec/metric_fu/metrics/flog/flog_spec.rb +7 -7
- data/spec/metric_fu/metrics/generator_spec.rb +21 -21
- data/spec/metric_fu/metrics/graph_spec.rb +9 -9
- data/spec/metric_fu/metrics/hotspots/hotspots_spec.rb +1 -1
- data/spec/metric_fu/metrics/rcov/rcov_spec.rb +8 -8
- data/spec/metric_fu/metrics/reek/reek_spec.rb +1 -1
- data/spec/metric_fu/metrics/saikuro/saikuro_spec.rb +5 -5
- data/spec/metric_fu/metrics/stats/stats_spec.rb +4 -4
- data/spec/metric_fu/reporter_spec.rb +41 -0
- data/spec/metric_fu/reporting/graphs/engines/gchart_spec.rb +7 -7
- data/spec/metric_fu/reporting/result_spec.rb +51 -0
- data/spec/run_spec.rb +167 -27
- data/spec/spec_helper.rb +1 -0
- data/spec/support/matcher_create_file.rb +7 -2
- data/spec/support/matcher_create_files.rb +41 -0
- data/spec/support/suite.rb +32 -0
- metadata +27 -6
- data/lib/metric_fu/reporting/report.rb +0 -111
- data/spec/metric_fu/reporting/report_spec.rb +0 -148
@@ -1,17 +1,22 @@
|
|
1
1
|
MetricFu.metrics_require { 'rcov/rcov_grapher' }
|
2
2
|
module MetricFu
|
3
3
|
class RcovGchartGrapher < RcovGrapher
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
def title
|
5
|
+
"Rcov: code coverage"
|
6
|
+
end
|
7
|
+
def data
|
8
|
+
self.rcov_percent
|
9
|
+
end
|
10
|
+
def output_filename
|
11
|
+
'rcov.png'
|
12
|
+
end
|
13
|
+
# overrides method
|
14
|
+
def y_axis_scale_options
|
15
|
+
{
|
9
16
|
:max_value => 101,
|
10
17
|
:axis_with_labels => 'x,y',
|
11
18
|
:axis_labels => [self.labels.values, [0,20,40,60,80,100]],
|
12
|
-
|
13
|
-
:filename => File.join(MetricFu.output_directory, 'rcov.png')
|
14
|
-
)
|
19
|
+
}
|
15
20
|
end
|
16
21
|
end
|
17
22
|
end
|
@@ -1,20 +1,16 @@
|
|
1
1
|
MetricFu.metrics_require { 'reek/reek_grapher' }
|
2
2
|
module MetricFu
|
3
3
|
class ReekBluffGrapher < ReekGrapher
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
def title
|
5
|
+
'Reek: code smells'
|
6
|
+
end
|
7
|
+
def data
|
8
|
+
@reek_count.map do |name, count|
|
9
|
+
[name, count.join(',')]
|
9
10
|
end
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
#{data}
|
14
|
-
g.labels = #{MultiJson.dump(@labels)};
|
15
|
-
g.draw();
|
16
|
-
EOS
|
17
|
-
File.open(File.join(MetricFu.output_directory, 'reek.js'), 'w') {|f| f << content }
|
11
|
+
end
|
12
|
+
def output_filename
|
13
|
+
'reek.js'
|
18
14
|
end
|
19
15
|
end
|
20
16
|
end
|
@@ -1,25 +1,30 @@
|
|
1
1
|
MetricFu.metrics_require { 'reek/reek_grapher' }
|
2
2
|
module MetricFu
|
3
3
|
class ReekGchartGrapher < ReekGrapher
|
4
|
-
def
|
5
|
-
|
4
|
+
def title
|
5
|
+
"Reek: code smells"
|
6
|
+
end
|
7
|
+
def legend
|
8
|
+
@legend ||= @reek_count.keys.sort
|
9
|
+
end
|
10
|
+
def data
|
6
11
|
values = []
|
7
|
-
legend = @reek_count.keys.sort
|
8
12
|
legend.collect {|k| values << @reek_count[k]}
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
13
|
+
values
|
14
|
+
end
|
15
|
+
def output_filename
|
16
|
+
'reek.png'
|
17
|
+
end
|
18
|
+
def gchart_line_options
|
19
|
+
super.merge({
|
20
|
+
:bar_colors => COLORS,
|
21
|
+
:stacked => false,
|
22
|
+
:legend => legend,
|
23
|
+
:custom => 'chdlp=t',
|
24
|
+
})
|
25
|
+
end
|
26
|
+
def y_axis_scale_argument
|
27
|
+
@reek_count.values.flatten.uniq
|
23
28
|
end
|
24
29
|
end
|
25
30
|
end
|
@@ -1,15 +1,16 @@
|
|
1
1
|
MetricFu.metrics_require { 'roodi/roodi_grapher' }
|
2
2
|
module MetricFu
|
3
3
|
class RoodiBluffGrapher < RoodiGrapher
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
4
|
+
def title
|
5
|
+
'Roodi: design problems'
|
6
|
+
end
|
7
|
+
def data
|
8
|
+
[
|
9
|
+
['roodi', @roodi_count.join(',')]
|
10
|
+
]
|
11
|
+
end
|
12
|
+
def output_filename
|
13
|
+
'roodi.js'
|
13
14
|
end
|
14
15
|
end
|
15
16
|
end
|
@@ -1,17 +1,20 @@
|
|
1
1
|
MetricFu.metrics_require { 'roodi/roodi_grapher' }
|
2
2
|
module MetricFu
|
3
3
|
class RoodiGchartGrapher < RoodiGrapher
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
4
|
+
def title
|
5
|
+
"Roodi: potential design problems"
|
6
|
+
end
|
7
|
+
def data
|
8
|
+
@roodi_count
|
9
|
+
end
|
10
|
+
def output_filename
|
11
|
+
'roodi.png'
|
12
|
+
end
|
13
|
+
def gchart_line_options
|
14
|
+
super
|
15
|
+
end
|
16
|
+
def y_axis_scale_argument
|
17
|
+
@roodi_count
|
15
18
|
end
|
16
19
|
end
|
17
20
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module MetricFu
|
2
2
|
|
3
3
|
class Saikuro < Generator
|
4
|
-
include Rake::DSL if defined?(Rake::DSL) # rake 0.8.7 and 0.9.2 compatible
|
5
|
-
|
6
4
|
def emit
|
7
5
|
options_string = MetricFu.saikuro.inject("") do |options, option|
|
8
6
|
option[0] == :input_directory ? options : options + "--#{option.join(' ')} "
|
@@ -12,36 +10,9 @@ module MetricFu
|
|
12
10
|
options_string += "--input_directory #{input_dir} "
|
13
11
|
end
|
14
12
|
|
15
|
-
|
16
|
-
mf_debug
|
17
|
-
|
18
|
-
unless ok
|
19
|
-
mf_log "Saikuro failed with exit status: #{response.exitstatus}"
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end)
|
23
|
-
end
|
24
|
-
|
25
|
-
def capture_output(&block)
|
26
|
-
old_stdout = STDOUT.clone
|
27
|
-
pipe_r, pipe_w = IO.pipe
|
28
|
-
pipe_r.sync = true
|
29
|
-
output = ""
|
30
|
-
reader = Thread.new do
|
31
|
-
begin
|
32
|
-
loop do
|
33
|
-
output << pipe_r.readpartial(1024)
|
34
|
-
end
|
35
|
-
rescue EOFError
|
36
|
-
end
|
37
|
-
end
|
38
|
-
STDOUT.reopen(pipe_w)
|
39
|
-
yield
|
40
|
-
ensure
|
41
|
-
STDOUT.reopen(old_stdout)
|
42
|
-
pipe_w.close
|
43
|
-
reader.join
|
44
|
-
return output
|
13
|
+
command = %Q(mf-saikuro #{options_string})
|
14
|
+
mf_debug "** #{command}"
|
15
|
+
`#{command}`
|
45
16
|
end
|
46
17
|
|
47
18
|
def format_directories
|
@@ -186,14 +157,14 @@ module MetricFu
|
|
186
157
|
while (line = @file_handle.readline) do
|
187
158
|
return [] if line.nil? || line !~ /\S/
|
188
159
|
element ||= nil
|
189
|
-
if line.match
|
160
|
+
if line.match(/START/)
|
190
161
|
unless element.nil?
|
191
162
|
@elements << element
|
192
163
|
element = nil
|
193
164
|
end
|
194
165
|
line = @file_handle.readline
|
195
166
|
element = Saikuro::ParsingElement.new(line)
|
196
|
-
elsif line.match
|
167
|
+
elsif line.match(/END/)
|
197
168
|
@elements << element if element
|
198
169
|
element = nil
|
199
170
|
else
|
@@ -10,7 +10,7 @@ module MetricFu
|
|
10
10
|
|
11
11
|
def analyze
|
12
12
|
output = File.open(metric_directory + '/stats.txt').read
|
13
|
-
lines = remove_noise(output)
|
13
|
+
lines = remove_noise(output).compact
|
14
14
|
|
15
15
|
@stats = {}
|
16
16
|
|
@@ -34,6 +34,7 @@ module MetricFu
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def set_global_stats(totals)
|
37
|
+
return if totals.nil?
|
37
38
|
totals = totals.split(" ").find_all {|el| ! el.empty? }
|
38
39
|
@stats[:codeLOC] = totals[0].match(/\d.*/)[0].to_i
|
39
40
|
@stats[:testLOC] = totals[1].match(/\d.*/)[0].to_i
|
@@ -1,16 +1,17 @@
|
|
1
1
|
MetricFu.metrics_require { 'stats/stats_grapher' }
|
2
2
|
module MetricFu
|
3
3
|
class StatsBluffGrapher < StatsGrapher
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
def title
|
5
|
+
'Stats: LOC & LOT'
|
6
|
+
end
|
7
|
+
def data
|
8
|
+
[
|
9
|
+
['LOC', @loc_counts.join(',')],
|
10
|
+
['LOT', @lot_counts.join(',')],
|
11
|
+
]
|
12
|
+
end
|
13
|
+
def output_filename
|
14
|
+
'stats.js'
|
14
15
|
end
|
15
16
|
end
|
16
17
|
end
|
@@ -1,20 +1,27 @@
|
|
1
1
|
MetricFu.metrics_require { 'stats/stats_grapher' }
|
2
2
|
module MetricFu
|
3
3
|
class StatsGchartGrapher < StatsGrapher
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
4
|
+
def title
|
5
|
+
"Stats: LOC & LOT"
|
6
|
+
end
|
7
|
+
def data
|
8
|
+
[@loc_counts, @lot_counts]
|
9
|
+
end
|
10
|
+
def output_filename
|
11
|
+
'stats.png'
|
12
|
+
end
|
13
|
+
def legend
|
14
|
+
['Lines of code', 'Lines of test']
|
15
|
+
end
|
16
|
+
def gchart_line_options
|
17
|
+
super.merge({
|
18
|
+
:bar_colors => COLORS[0..1],
|
19
|
+
:legend => legend,
|
20
|
+
:custom => 'chdlp=t',
|
21
|
+
})
|
22
|
+
end
|
23
|
+
def y_axis_scale_argument
|
24
|
+
@loc_counts + @lot_counts
|
18
25
|
end
|
19
26
|
end
|
20
27
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module MetricFu
|
2
|
+
class Reporter
|
3
|
+
def initialize(formatters=nil)
|
4
|
+
@formatters = Array(formatters)
|
5
|
+
end
|
6
|
+
|
7
|
+
def start
|
8
|
+
notify :start
|
9
|
+
end
|
10
|
+
|
11
|
+
def finish
|
12
|
+
notify :finish
|
13
|
+
end
|
14
|
+
|
15
|
+
def start_metric(metric)
|
16
|
+
mf_log "** STARTING METRIC #{metric}"
|
17
|
+
notify :start_metric, metric
|
18
|
+
end
|
19
|
+
|
20
|
+
def finish_metric(metric)
|
21
|
+
mf_log "** ENDING METRIC #{metric}"
|
22
|
+
notify :finish_metric, metric
|
23
|
+
end
|
24
|
+
|
25
|
+
def display_results
|
26
|
+
notify :display_results
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def notify(event, *args)
|
32
|
+
@formatters.each do |formatter|
|
33
|
+
formatter.send(event, *args) if formatter.respond_to?(event)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -9,5 +9,25 @@ module MetricFu
|
|
9
9
|
g.legend_font_size = "12px"
|
10
10
|
g.marker_font_size = "10px"
|
11
11
|
EOS
|
12
|
+
def graph!
|
13
|
+
title = send(:title)
|
14
|
+
data = send(:data)
|
15
|
+
labels = MultiJson.dump(@labels)
|
16
|
+
output_filename = send(:output_filename)
|
17
|
+
content = <<-EOS
|
18
|
+
#{BLUFF_DEFAULT_OPTIONS}
|
19
|
+
g.title = '#{title}';
|
20
|
+
#{build_data(data)}
|
21
|
+
g.labels = #{labels};
|
22
|
+
g.draw();
|
23
|
+
EOS
|
24
|
+
File.open(File.join(self.output_directory, output_filename), 'w') {|f| f << content }
|
25
|
+
end
|
26
|
+
private
|
27
|
+
def build_data(data)
|
28
|
+
Array(data).map do |label, datum|
|
29
|
+
"g.data('#{label}', [#{datum}]);"
|
30
|
+
end.join("\n")
|
31
|
+
end
|
12
32
|
end
|
13
33
|
end
|
@@ -2,9 +2,42 @@ module MetricFu
|
|
2
2
|
module GchartGrapher
|
3
3
|
COLORS = %w{009999 FF7400 A60000 008500 E6399B 344AD7 00B860 D5CCB9}
|
4
4
|
GCHART_GRAPH_SIZE = "945x317" # maximum permitted image size is 300000 pixels
|
5
|
-
|
6
5
|
NUMBER_OF_TICKS = 6
|
6
|
+
|
7
|
+
# @see gchart_line_options
|
8
|
+
def graph!
|
9
|
+
options = gchart_line_options.reject{|_,v|v.nil?}
|
10
|
+
Gchart.line(options)
|
11
|
+
end
|
12
|
+
# @note Some values are initialized as nil to maintain consistent
|
13
|
+
# key ordering for the tests. Any keys with nil values are removed
|
14
|
+
# before graphing
|
15
|
+
def gchart_line_options
|
16
|
+
{
|
17
|
+
:size => GCHART_GRAPH_SIZE,
|
18
|
+
:title => URI.encode(title),
|
19
|
+
:data => data,
|
20
|
+
:stacked => nil,
|
21
|
+
:bar_colors => nil,
|
22
|
+
:legend => nil,
|
23
|
+
:custom => nil,
|
24
|
+
:max_value => nil,
|
25
|
+
:axis_with_labels => nil,
|
26
|
+
:axis_labels => nil,
|
27
|
+
:format => 'file',
|
28
|
+
:filename => File.join(self.output_directory, output_filename),
|
29
|
+
}.merge(y_axis_scale_options)
|
30
|
+
end
|
31
|
+
def y_axis_scale_options
|
32
|
+
determine_y_axis_scale(y_axis_scale_argument)
|
33
|
+
{
|
34
|
+
:max_value => @max_value,
|
35
|
+
:axis_with_labels => 'x,y',
|
36
|
+
:axis_labels => [@labels.values, @yaxis],
|
37
|
+
}
|
38
|
+
end
|
7
39
|
def determine_y_axis_scale(values)
|
40
|
+
values = Array(values)
|
8
41
|
values.collect! {|val| val || 0.0 }
|
9
42
|
if values.empty?
|
10
43
|
@max_value = 10
|
@@ -17,13 +50,18 @@ module MetricFu
|
|
17
50
|
@max_value = @yaxis.last
|
18
51
|
end
|
19
52
|
end
|
53
|
+
def y_axis_scale_argument
|
54
|
+
raise "#{__LINE__} in #{__FILE__} from #{caller.join('\n')}"
|
55
|
+
end
|
20
56
|
end
|
21
57
|
|
22
58
|
class Grapher
|
23
|
-
include MetricFu::GchartGrapher
|
24
59
|
|
25
60
|
def self.require_graphing_gem
|
26
|
-
|
61
|
+
if MetricFu.graph_engine == :gchart
|
62
|
+
require 'gchart'
|
63
|
+
include MetricFu::GchartGrapher
|
64
|
+
end
|
27
65
|
rescue LoadError
|
28
66
|
mf_log "#"*99 + "\n" +
|
29
67
|
"If you want to use google charts for graphing, you'll need to install the googlecharts rubygem." +
|