jscruggs-metric_fu 1.0.2 → 1.1.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.
Files changed (56) hide show
  1. data/HISTORY +13 -0
  2. data/README +1 -1
  3. data/Rakefile +1 -29
  4. data/TODO +1 -2
  5. data/lib/base/base_template.rb +18 -6
  6. data/lib/base/configuration.rb +22 -2
  7. data/lib/base/generator.rb +15 -2
  8. data/lib/base/graph.rb +37 -0
  9. data/lib/generators/churn.rb +6 -1
  10. data/lib/generators/flay.rb +5 -0
  11. data/lib/generators/flog.rb +6 -0
  12. data/lib/generators/rcov.rb +10 -0
  13. data/lib/generators/reek.rb +5 -0
  14. data/lib/generators/roodi.rb +7 -0
  15. data/lib/generators/saikuro.rb +184 -187
  16. data/lib/graphs/flay_grapher.rb +34 -0
  17. data/lib/graphs/flog_grapher.rb +37 -0
  18. data/lib/graphs/rcov_grapher.rb +34 -0
  19. data/lib/graphs/reek_grapher.rb +44 -0
  20. data/lib/graphs/roodi_grapher.rb +34 -0
  21. data/lib/metric_fu.rb +4 -0
  22. data/lib/templates/awesome/awesome_template.rb +30 -0
  23. data/lib/templates/awesome/churn.html.erb +19 -0
  24. data/lib/templates/awesome/default.css +75 -0
  25. data/lib/templates/awesome/flay.html.erb +27 -0
  26. data/lib/templates/awesome/flog.html.erb +46 -0
  27. data/lib/templates/awesome/index.html.erb +28 -0
  28. data/lib/templates/awesome/layout.html.erb +27 -0
  29. data/lib/templates/awesome/rcov.html.erb +36 -0
  30. data/lib/templates/awesome/reek.html.erb +34 -0
  31. data/lib/templates/awesome/roodi.html.erb +21 -0
  32. data/lib/templates/awesome/saikuro.html.erb +71 -0
  33. data/lib/templates/awesome/stats.html.erb +41 -0
  34. data/lib/templates/standard/churn.html.erb +1 -0
  35. data/lib/templates/standard/flay.html.erb +1 -0
  36. data/lib/templates/standard/flog.html.erb +3 -2
  37. data/lib/templates/standard/rcov.html.erb +5 -4
  38. data/lib/templates/standard/reek.html.erb +1 -0
  39. data/lib/templates/standard/roodi.html.erb +1 -0
  40. data/lib/templates/standard/saikuro.html.erb +1 -0
  41. data/lib/templates/standard/stats.html.erb +1 -0
  42. data/spec/base/base_template_spec.rb +35 -14
  43. data/spec/base/configuration_spec.rb +4 -4
  44. data/spec/base/generator_spec.rb +23 -1
  45. data/spec/base/md5_tracker_spec.rb +1 -1
  46. data/spec/base/report_spec.rb +1 -1
  47. data/spec/generators/churn_spec.rb +8 -8
  48. data/spec/generators/flay_spec.rb +4 -1
  49. data/spec/generators/flog_spec.rb +10 -2
  50. data/spec/generators/reek_spec.rb +2 -1
  51. data/spec/generators/saikuro_spec.rb +22 -17
  52. data/spec/generators/stats_spec.rb +1 -1
  53. data/tasks/metric_fu.rake +8 -1
  54. data/vendor/_fonts/monaco.ttf +0 -0
  55. metadata +30 -20
  56. data/tasks/railroad.rake +0 -39
@@ -0,0 +1,34 @@
1
+ require 'gruff'
2
+ module MetricFu
3
+
4
+ class FlayGrapher
5
+
6
+ attr_accessor :flay_score, :labels
7
+
8
+ def initialize
9
+ self.flay_score = []
10
+ self.labels = {}
11
+ end
12
+
13
+ def get_metrics(metrics, date)
14
+ self.flay_score.push(metrics[:flay][:total_score].to_i)
15
+ self.labels.update( { self.labels.size => date })
16
+ end
17
+
18
+ def graph!
19
+ g = Gruff::Line.new(MetricFu.graph_size)
20
+ g.title = "Flay: duplication"
21
+ g.theme = MetricFu.graph_theme
22
+ g.font = MetricFu.graph_font
23
+ g.data('flay', self.flay_score)
24
+ g.labels = self.labels
25
+ g.title_font_size = MetricFu.graph_title_font_size
26
+ g.legend_box_size = MetricFu.graph_legend_box_size
27
+ g.legend_font_size = MetricFu.graph_legend_font_size
28
+ g.marker_font_size = MetricFu.graph_marker_font_size
29
+ g.write(File.join(MetricFu.output_directory, 'flay.png'))
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,37 @@
1
+ require 'gruff'
2
+ module MetricFu
3
+
4
+ class FlogGrapher
5
+
6
+ attr_accessor :flog_total, :flog_average, :labels
7
+
8
+ def initialize
9
+ self.flog_total = []
10
+ self.flog_average = []
11
+ self.labels = {}
12
+ end
13
+
14
+ def get_metrics(metrics, date)
15
+ self.flog_total.push(metrics[:flog][:total])
16
+ self.flog_average.push(metrics[:flog][:average])
17
+ self.labels.update( { self.labels.size => date })
18
+ end
19
+
20
+ def graph!
21
+ g = Gruff::Line.new(MetricFu.graph_size)
22
+ g.title = "Flog: code complexity"
23
+ g.theme = MetricFu.graph_theme
24
+ g.font = MetricFu.graph_font
25
+ g.data('flog total', self.flog_total)
26
+ g.data('flog average', self.flog_average)
27
+ g.labels = self.labels
28
+ g.title_font_size = MetricFu.graph_title_font_size
29
+ g.legend_box_size = MetricFu.graph_legend_box_size
30
+ g.legend_font_size = MetricFu.graph_legend_font_size
31
+ g.marker_font_size = MetricFu.graph_marker_font_size
32
+ g.write(File.join(MetricFu.output_directory, 'flog.png'))
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,34 @@
1
+ require 'gruff'
2
+ module MetricFu
3
+
4
+ class RcovGrapher
5
+
6
+ attr_accessor :rcov_percent, :labels
7
+
8
+ def initialize
9
+ self.rcov_percent = []
10
+ self.labels = {}
11
+ end
12
+
13
+ def get_metrics(metrics, date)
14
+ self.rcov_percent.push(metrics[:rcov][:global_percent_run])
15
+ self.labels.update( { self.labels.size => date })
16
+ end
17
+
18
+ def graph!
19
+ g = Gruff::Line.new(MetricFu.graph_size)
20
+ g.title = "Rcov: code coverage"
21
+ g.theme = MetricFu.graph_theme
22
+ g.font = MetricFu.graph_font
23
+ g.data('rcov', self.rcov_percent)
24
+ g.labels = self.labels
25
+ g.title_font_size = MetricFu.graph_title_font_size
26
+ g.legend_box_size = MetricFu.graph_legend_box_size
27
+ g.legend_font_size = MetricFu.graph_legend_font_size
28
+ g.marker_font_size = MetricFu.graph_marker_font_size
29
+ g.write(File.join(MetricFu.output_directory, 'rcov.png'))
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,44 @@
1
+ require 'gruff'
2
+ module MetricFu
3
+
4
+ class ReekGrapher
5
+
6
+ attr_accessor :reek_count, :labels
7
+
8
+ def initialize
9
+ self.reek_count = {}
10
+ self.labels= {}
11
+ end
12
+
13
+ def get_metrics(metrics, date)
14
+ counter = self.labels.size
15
+ self.labels.update( { counter => date })
16
+
17
+ metrics[:reek][:matches].each do |reek_chunk|
18
+ reek_chunk[:code_smells].each do |code_smell|
19
+ # speaking of code smell...
20
+ self.reek_count[code_smell[:type]] = [] if self.reek_count[code_smell[:type]].nil?
21
+ self.reek_count[code_smell[:type]][counter].nil? ? self.reek_count[code_smell[:type]][counter] = 1 : self.reek_count[code_smell[:type]][counter] += 1
22
+ end
23
+ end
24
+ end
25
+
26
+ def graph!
27
+ g = Gruff::Line.new(MetricFu.graph_size)
28
+ g.title = "Reek: code smells"
29
+ g.theme = MetricFu.graph_theme
30
+ g.font = MetricFu.graph_font
31
+ self.reek_count.each_pair do |type, count|
32
+ g.data(type, count)
33
+ end
34
+ g.labels = self.labels
35
+ g.title_font_size = MetricFu.graph_title_font_size
36
+ g.legend_box_size = MetricFu.graph_legend_box_size
37
+ g.legend_font_size = MetricFu.graph_legend_font_size
38
+ g.marker_font_size = MetricFu.graph_marker_font_size
39
+ g.write(File.join(MetricFu.output_directory, 'reek.png'))
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,34 @@
1
+ require 'gruff'
2
+ module MetricFu
3
+
4
+ class RoodiGrapher
5
+
6
+ attr_accessor :roodi_count, :labels
7
+
8
+ def initialize
9
+ self.roodi_count = []
10
+ self.labels = {}
11
+ end
12
+
13
+ def get_metrics(metrics, date)
14
+ self.roodi_count.push(metrics[:roodi][:problems].size)
15
+ self.labels.update( { self.labels.size => date })
16
+ end
17
+
18
+ def graph!
19
+ g = Gruff::Line.new(MetricFu.graph_size)
20
+ g.title = "Roodi: design problems"
21
+ g.theme = MetricFu.graph_theme
22
+ g.font = MetricFu.graph_font
23
+ g.data('roodi', self.roodi_count)
24
+ g.labels = self.labels
25
+ g.title_font_size = MetricFu.graph_title_font_size
26
+ g.legend_box_size = MetricFu.graph_legend_box_size
27
+ g.legend_font_size = MetricFu.graph_legend_font_size
28
+ g.marker_font_size = MetricFu.graph_marker_font_size
29
+ g.write(File.join(MetricFu.output_directory, 'roodi.png'))
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -5,11 +5,13 @@ end
5
5
  base_dir = File.join(MetricFu::LIB_ROOT, 'base')
6
6
  generator_dir = File.join(MetricFu::LIB_ROOT, 'generators')
7
7
  template_dir = File.join(MetricFu::LIB_ROOT, 'templates')
8
+ graph_dir = File.join(MetricFu::LIB_ROOT, 'graphs')
8
9
 
9
10
  # We need to require these two things first because our other classes
10
11
  # depend on them.
11
12
  require File.join(base_dir, 'report')
12
13
  require File.join(base_dir, 'generator')
14
+ require File.join(base_dir, 'graph')
13
15
 
14
16
  # Load the rakefile so users of the gem get the default metric_fu task
15
17
  load File.join(MetricFu::LIB_ROOT, '..', 'tasks', 'metric_fu.rake')
@@ -18,3 +20,5 @@ load File.join(MetricFu::LIB_ROOT, '..', 'tasks', 'metric_fu.rake')
18
20
  Dir[File.join(base_dir, '*.rb')].each{|l| require l }
19
21
  Dir[File.join(generator_dir, '*.rb')].each {|l| require l }
20
22
  Dir[File.join(template_dir, 'standard/*.rb')].each {|l| require l}
23
+ Dir[File.join(template_dir, 'awesome/*.rb')].each {|l| require l}
24
+ Dir[File.join(graph_dir, '*.rb')].each {|l| require l}
@@ -0,0 +1,30 @@
1
+ class AwesomeTemplate < MetricFu::Template
2
+
3
+ def write
4
+ # Getting rid of the crap before and after the project name from integrity
5
+ @name = File.basename(Dir.pwd).gsub(/^\w+-|-\w+$/, "")
6
+
7
+ report.each_pair do |section, contents|
8
+ if template_exists?(section)
9
+ create_instance_var(section, contents)
10
+ @html = erbify(section)
11
+ html = erbify('layout')
12
+ fn = output_filename(section)
13
+ MetricFu.report.save_output(html, MetricFu.output_directory, fn)
14
+ end
15
+ end
16
+
17
+ # Instance variables we need should already be created from above
18
+ if template_exists?('index')
19
+ @html = erbify('index')
20
+ html = erbify('layout')
21
+ fn = output_filename('index')
22
+ MetricFu.report.save_output(html, MetricFu.output_directory, fn)
23
+ end
24
+ end
25
+
26
+ def this_directory
27
+ File.dirname(__FILE__)
28
+ end
29
+ end
30
+
@@ -0,0 +1,19 @@
1
+ <h3>Source Control Churn Results</h3>
2
+ <p>Files that change a lot in your project may be bad a sign.
3
+ This task uses your source control log to identify those files.
4
+ </p>
5
+ <table>
6
+ <tr>
7
+ <th>File Path</th>
8
+ <th>Times Changed</th>
9
+ </tr>
10
+ <% count = 0 %>
11
+ <% @churn[:changes].each do |change| %>
12
+ <tr>
13
+ <td><%= link_to_filename(change[:file_path]) %></td>
14
+ <td><%= change[:times_changed] %></td>
15
+ </tr>
16
+ <% count += 1 %>
17
+ <% end %>
18
+ </table>
19
+ <p>Generated on <%= Time.now.localtime %></p>
@@ -0,0 +1,75 @@
1
+ table {
2
+ margin-top: 20px;
3
+ border-collapse: collapse;
4
+ border: 1px solid #666;
5
+ background: #fff;
6
+ margin-bottom: 20px;
7
+ }
8
+
9
+ table tr.light {
10
+ background: #fff;
11
+ }
12
+
13
+ table tr.dark {
14
+ background: #f9f9f9;
15
+ }
16
+
17
+ table tr:hover {
18
+ background: #FFFFC0;
19
+ }
20
+
21
+ table td, table th {
22
+ padding: 4px;
23
+ font-size: 11px;
24
+ }
25
+ table th {
26
+ text-align: center;
27
+ color: #337022;
28
+ background: #DDFFCC;
29
+ font-weight: bold;
30
+ border: #99D688 1px solid;
31
+ }
32
+
33
+ table td {
34
+ border: #d0d0d0 1px solid;
35
+ }
36
+
37
+ table td.score {
38
+ text-align: right;
39
+ }
40
+
41
+ .warning {
42
+ background: yellow;
43
+ }
44
+ .rcov_code td {
45
+ border-bottom: 1px solid #ddd ;
46
+ padding: 0;
47
+ margin: 0;
48
+ }
49
+ .rcov_code tr {
50
+ border: 0px;
51
+ padding:0px;
52
+ margin: 0px;
53
+ }
54
+ .rcov_code pre {
55
+ border: 0px;
56
+ padding: 0px;
57
+ margin: 0px;
58
+ }
59
+ .rcov_run {}
60
+ .rcov_not_run {
61
+ background-color: #d88;
62
+ }
63
+ .rcov_run a, .rcov_not_run a {
64
+ text-decoration: none;
65
+ }
66
+ .rcov_run a {
67
+ color: #333;
68
+ }
69
+ .rcov_not_run a {
70
+ color: #000;
71
+ }
72
+ .rcov_overflow {
73
+ overflow: auto;
74
+ font-size: 50%;
75
+ }
@@ -0,0 +1,27 @@
1
+ <h3>Flay Results</h3>
2
+
3
+ <p><a href='http://ruby.sadi.st/Flay.html'>Flay</a> analyzes ruby code for structural similarities.</p>
4
+
5
+ <img src="flay.png?<%= Time.now %>">
6
+
7
+ <h4>Total Score (lower is better): <%= @flay[:total_score] %></h4>
8
+
9
+ <table>
10
+ <tr>
11
+ <th>Files</th>
12
+ <th>Matches</th>
13
+ </tr>
14
+ <% count = 0 %>
15
+ <% @flay[:matches].each do |match| %>
16
+ <tr class='<%= cycle("light", "dark", count) %>'>
17
+ <td>
18
+ <% match[:matches].each do |file| %>
19
+ <%= link_to_filename(file[:name], file[:line]) %><br/>
20
+ <% end %>
21
+ </td>
22
+ <td><%= match[:reason] %></td>
23
+ </tr>
24
+ <% count += 1 %>
25
+ <% end %>
26
+ </table>
27
+ <p>Generated on <%= Time.now.localtime %></p>
@@ -0,0 +1,46 @@
1
+ <h3>Flog Results</h3>
2
+ <p><a href='http://ruby.sadi.st/Flog.html'>Flog</a> measures code complexity.</p>
3
+
4
+ <img src="flog.png?<%= Time.now %>">
5
+
6
+ <h2>Total Flog score for all methods: <%= @flog[:total]%></h2>
7
+ <h2>Average Flog score for all methods: <%= @flog[:average]%></h2>
8
+
9
+ <table>
10
+ <tr>
11
+ <th>File</th>
12
+ <th>Total score</th>
13
+ <th>Methods</th>
14
+ <th>Average score</th>
15
+ <th>Highest score</th>
16
+ </tr>
17
+ <% @flog[:pages].each do |page| %>
18
+ <tr>
19
+ <td><a href="#<%= page[:path].gsub(/[^a-z]+/, '_') %>"><%= page[:path] %></a></td>
20
+ <td><%= page[:score].round %></td>
21
+ <td><%= page[:scanned_methods].length %></td>
22
+ <td><%= page[:average_score].round %></td>
23
+ <td><%= page[:highest_score].round %></td>
24
+ </tr>
25
+ <% end %>
26
+ </table>
27
+
28
+ <% @flog[:pages].each do |page| %>
29
+ <h2 id="<%= page[:path].gsub(/[^a-z]+/, '_') %>"><%= link_to_filename page[:path] %></h2>
30
+ <% page[:scanned_methods].each do |sm| %>
31
+ <p><%= sm[:name] %></p>
32
+ <table>
33
+ <tr>
34
+ <th>Score</th>
35
+ <th>Operator</th>
36
+ </tr>
37
+ <% sm[:operators].each do |operator| %>
38
+ <tr>
39
+ <td><%= operator[:score] %></td>
40
+ <td><%= operator[:operator] %></td>
41
+ </tr>
42
+ <% end %>
43
+ </table>
44
+ <% end %>
45
+ <% end %>
46
+ <p>Generated on <%= Time.now.localtime %></p>
@@ -0,0 +1,28 @@
1
+ <h3>Metric Fu Results</h3>
2
+ <ul id='projects'>
3
+ <% if @churn %>
4
+ <li class='even failure'><a href="churn.html">Churn</a></li>
5
+ <% end %>
6
+ <% if @flay %>
7
+ <li class='even failure'><a href="flay.html">Flay</a></li>
8
+ <% end %>
9
+ <% if @flog %>
10
+ <li class='even failure'><a href="flog.html">Flog</a></li>
11
+ <% end %>
12
+ <% if @rcov %>
13
+ <li class='even failure'><a href="rcov.html">Rcov</a></li>
14
+ <% end %>
15
+ <% if @reek %>
16
+ <li class='even failure'><a href="reek.html">Reek</a></li>
17
+ <% end %>
18
+ <% if @roodi %>
19
+ <li class='even failure'><a href="roodi.html">Roodi</a></li>
20
+ <% end %>
21
+ <% if @saikuro %>
22
+ <li class='even failure'><a href="saikuro.html">Saikuro</a></li>
23
+ <% end %>
24
+ <% if @stats %>
25
+ <li class='even failure'><a href="stats.html">Stats</a></li>
26
+ <% end %>
27
+ </ul>
28
+ <p>Generated on <%= Time.now.localtime %></p>
@@ -0,0 +1,27 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'>
3
+ <head>
4
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type' />
5
+ <meta content='en' http-equiv='Content-Language' />
6
+ <title>metrics</title>
7
+ <link href='/reset.css' rel='stylesheet' type='text/css' />
8
+ <link href='/buttons.css' rel='stylesheet' type='text/css' />
9
+ <link href='/integrity.css' rel='stylesheet' type='text/css' />
10
+ <style>
11
+ <%= inline_css("default.css") %>
12
+ </style>
13
+ <link REL="SHORTCUT ICON" HREF="/favicon.ico">
14
+ </head>
15
+ <body>
16
+ <div id='header'>
17
+ <h1><a href="/">metrics</a> | <a href="index.html"><%= @name %></a></h1>
18
+ <address class='watermark'>
19
+ built with
20
+ <a href='http://metric-fu.rubyforge.org/'>metric-fu</a>
21
+ </address>
22
+ </div>
23
+ <div id='content'>
24
+ <%= @html %>
25
+ </div>
26
+ </body>
27
+ </html>