cdd-metric_fu 1.3.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.
Files changed (112) hide show
  1. data/.document +7 -0
  2. data/.gitignore +24 -0
  3. data/HISTORY +182 -0
  4. data/MIT-LICENSE +22 -0
  5. data/Manifest.txt +25 -0
  6. data/README.rdoc +20 -0
  7. data/Rakefile +59 -0
  8. data/TODO +9 -0
  9. data/VERSION +1 -0
  10. data/cdd-metric_fu.gemspec +200 -0
  11. data/home_page/back_all.jpg +0 -0
  12. data/home_page/churn.gif +0 -0
  13. data/home_page/flay.gif +0 -0
  14. data/home_page/flog.gif +0 -0
  15. data/home_page/footer.gif +0 -0
  16. data/home_page/header.jpg +0 -0
  17. data/home_page/img09.gif +0 -0
  18. data/home_page/index.html +277 -0
  19. data/home_page/rcov.gif +0 -0
  20. data/home_page/reek.gif +0 -0
  21. data/home_page/roodi.gif +0 -0
  22. data/home_page/saikuro.gif +0 -0
  23. data/home_page/stats.gif +0 -0
  24. data/home_page/styles.css +245 -0
  25. data/home_page/title.gif +0 -0
  26. data/home_page/title_back.gif +0 -0
  27. data/lib/base/base_template.rb +145 -0
  28. data/lib/base/configuration.rb +188 -0
  29. data/lib/base/generator.rb +167 -0
  30. data/lib/base/graph.rb +47 -0
  31. data/lib/base/md5_tracker.rb +52 -0
  32. data/lib/base/report.rb +100 -0
  33. data/lib/generators/churn.rb +34 -0
  34. data/lib/generators/flay.rb +35 -0
  35. data/lib/generators/flog.rb +172 -0
  36. data/lib/generators/rcov.rb +82 -0
  37. data/lib/generators/reek.rb +64 -0
  38. data/lib/generators/roodi.rb +33 -0
  39. data/lib/generators/saikuro.rb +221 -0
  40. data/lib/generators/stats.rb +59 -0
  41. data/lib/graphs/engines/bluff.rb +101 -0
  42. data/lib/graphs/engines/gchart.rb +120 -0
  43. data/lib/graphs/flay_grapher.rb +19 -0
  44. data/lib/graphs/flog_grapher.rb +39 -0
  45. data/lib/graphs/grapher.rb +18 -0
  46. data/lib/graphs/rails_best_practices_grapher.rb +24 -0
  47. data/lib/graphs/rcov_grapher.rb +19 -0
  48. data/lib/graphs/reek_grapher.rb +31 -0
  49. data/lib/graphs/roodi_grapher.rb +19 -0
  50. data/lib/graphs/stats_grapher.rb +22 -0
  51. data/lib/metric_fu.rb +32 -0
  52. data/lib/metric_fu/railtie.rb +10 -0
  53. data/lib/tasks/metric_fu.rake +22 -0
  54. data/lib/templates/awesome/awesome_template.rb +37 -0
  55. data/lib/templates/awesome/churn.html.erb +58 -0
  56. data/lib/templates/awesome/css/buttons.css +82 -0
  57. data/lib/templates/awesome/css/default.css +91 -0
  58. data/lib/templates/awesome/css/integrity.css +335 -0
  59. data/lib/templates/awesome/css/reset.css +7 -0
  60. data/lib/templates/awesome/flay.html.erb +34 -0
  61. data/lib/templates/awesome/flog.html.erb +53 -0
  62. data/lib/templates/awesome/index.html.erb +31 -0
  63. data/lib/templates/awesome/layout.html.erb +30 -0
  64. data/lib/templates/awesome/rcov.html.erb +42 -0
  65. data/lib/templates/awesome/reek.html.erb +40 -0
  66. data/lib/templates/awesome/roodi.html.erb +27 -0
  67. data/lib/templates/awesome/saikuro.html.erb +71 -0
  68. data/lib/templates/awesome/stats.html.erb +51 -0
  69. data/lib/templates/javascripts/bluff-min.js +1 -0
  70. data/lib/templates/javascripts/excanvas.js +35 -0
  71. data/lib/templates/javascripts/js-class.js +1 -0
  72. data/lib/templates/standard/churn.html.erb +31 -0
  73. data/lib/templates/standard/default.css +64 -0
  74. data/lib/templates/standard/flay.html.erb +34 -0
  75. data/lib/templates/standard/flog.html.erb +53 -0
  76. data/lib/templates/standard/index.html.erb +38 -0
  77. data/lib/templates/standard/rcov.html.erb +43 -0
  78. data/lib/templates/standard/reek.html.erb +42 -0
  79. data/lib/templates/standard/roodi.html.erb +29 -0
  80. data/lib/templates/standard/saikuro.html.erb +84 -0
  81. data/lib/templates/standard/standard_template.rb +26 -0
  82. data/lib/templates/standard/stats.html.erb +55 -0
  83. data/spec/base/base_template_spec.rb +161 -0
  84. data/spec/base/configuration_spec.rb +274 -0
  85. data/spec/base/generator_spec.rb +244 -0
  86. data/spec/base/graph_spec.rb +32 -0
  87. data/spec/base/md5_tracker_spec.rb +57 -0
  88. data/spec/base/report_spec.rb +139 -0
  89. data/spec/generators/churn_spec.rb +43 -0
  90. data/spec/generators/flay_spec.rb +110 -0
  91. data/spec/generators/flog_spec.rb +262 -0
  92. data/spec/generators/rcov_spec.rb +159 -0
  93. data/spec/generators/reek_spec.rb +125 -0
  94. data/spec/generators/saikuro_spec.rb +58 -0
  95. data/spec/generators/stats_spec.rb +74 -0
  96. data/spec/graphs/engines/bluff_spec.rb +17 -0
  97. data/spec/graphs/engines/gchart_spec.rb +109 -0
  98. data/spec/graphs/flay_grapher_spec.rb +37 -0
  99. data/spec/graphs/flog_grapher_spec.rb +45 -0
  100. data/spec/graphs/grapher_spec.rb +29 -0
  101. data/spec/graphs/rcov_grapher_spec.rb +37 -0
  102. data/spec/graphs/reek_grapher_spec.rb +47 -0
  103. data/spec/graphs/roodi_grapher_spec.rb +37 -0
  104. data/spec/graphs/stats_grapher_spec.rb +44 -0
  105. data/spec/resources/saikuro/app/controllers/sessions_controller.rb_cyclo.html +10 -0
  106. data/spec/resources/saikuro/app/controllers/users_controller.rb_cyclo.html +16 -0
  107. data/spec/resources/saikuro/index_cyclo.html +155 -0
  108. data/spec/resources/saikuro_sfiles/thing.rb_cyclo.html +11 -0
  109. data/spec/resources/yml/20090630.yml +7913 -0
  110. data/spec/spec.opts +6 -0
  111. data/spec/spec_helper.rb +7 -0
  112. metadata +285 -0
@@ -0,0 +1,120 @@
1
+ module MetricFu
2
+ module GchartGrapher
3
+ COLORS = %w{009999 FF7400 A60000 008500 E6399B 344AD7 00B860 D5CCB9}
4
+ GCHART_GRAPH_SIZE = "945x317" # maximum permitted image size is 300000 pixels
5
+
6
+ NUMBER_OF_TICKS = 6
7
+ def determine_y_axis_scale(values)
8
+ values.collect! {|val| val || 0.0 }
9
+ if values.empty?
10
+ @max_value = 10
11
+ @yaxis = [0, 2, 4, 6, 8, 10]
12
+ else
13
+ @max_value = values.max + Integer(0.1 * values.max)
14
+ portion_size = (@max_value / (NUMBER_OF_TICKS - 1).to_f).ceil
15
+ @yaxis = []
16
+ NUMBER_OF_TICKS.times {|n| @yaxis << Integer(portion_size * n) }
17
+ @max_value = @yaxis.last
18
+ end
19
+ end
20
+ end
21
+
22
+ class Grapher
23
+ include MetricFu::GchartGrapher
24
+
25
+ def self.require_graphing_gem
26
+ require 'gchart'
27
+ rescue LoadError
28
+ puts "#"*99 + "\n" +
29
+ "If you want to use google charts for graphing, you'll need to install the googlecharts rubygem." +
30
+ "\n" + "#"*99
31
+ end
32
+ end
33
+
34
+ class FlayGchartGrapher < FlayGrapher
35
+ def graph!
36
+ determine_y_axis_scale(@flay_score)
37
+ url = Gchart.line(
38
+ :size => GCHART_GRAPH_SIZE,
39
+ :title => URI.escape("Flay: duplication"),
40
+ :data => @flay_score,
41
+ :max_value => @max_value,
42
+ :axis_with_labels => 'x,y',
43
+ :axis_labels => [@labels.values, @yaxis],
44
+ :format => 'file',
45
+ :filename => File.join(MetricFu.output_directory, 'flay.png'))
46
+ end
47
+ end
48
+
49
+ class FlogGchartGrapher < FlogGrapher
50
+ def graph!
51
+ determine_y_axis_scale(@top_five_percent_average + @flog_average)
52
+ url = Gchart.line(
53
+ :size => GCHART_GRAPH_SIZE,
54
+ :title => URI.escape("Flog: code complexity"),
55
+ :data => [@flog_average, @top_five_percent_average],
56
+ :stacked => false,
57
+ :bar_colors => COLORS[0..1],
58
+ :legend => ['average', 'top 5% average'],
59
+ :custom => "chdlp=t",
60
+ :max_value => @max_value,
61
+ :axis_with_labels => 'x,y',
62
+ :axis_labels => [@labels.values, @yaxis],
63
+ :format => 'file',
64
+ :filename => File.join(MetricFu.output_directory, 'flog.png'))
65
+ end
66
+ end
67
+
68
+ class RcovGchartGrapher < RcovGrapher
69
+ def graph!
70
+ url = Gchart.line(
71
+ :size => GCHART_GRAPH_SIZE,
72
+ :title => URI.escape("Rcov: code coverage"),
73
+ :data => self.rcov_percent,
74
+ :max_value => 101,
75
+ :axis_with_labels => 'x,y',
76
+ :axis_labels => [self.labels.values, [0,20,40,60,80,100]],
77
+ :format => 'file',
78
+ :filename => File.join(MetricFu.output_directory, 'rcov.png')
79
+ )
80
+ end
81
+ end
82
+
83
+ class ReekGchartGrapher < ReekGrapher
84
+ def graph!
85
+ determine_y_axis_scale(@reek_count.values.flatten.uniq)
86
+ values = []
87
+ legend = @reek_count.keys.sort
88
+ legend.collect {|k| values << @reek_count[k]}
89
+
90
+ url = Gchart.line(
91
+ :size => GCHART_GRAPH_SIZE,
92
+ :title => URI.escape("Reek: code smells"),
93
+ :data => values,
94
+ :stacked => false,
95
+ :bar_colors => COLORS,
96
+ :legend => legend,
97
+ :custom => "chdlp=t",
98
+ :max_value => @max_value,
99
+ :axis_with_labels => 'x,y',
100
+ :axis_labels => [@labels.values, @yaxis],
101
+ :format => 'file',
102
+ :filename => File.join(MetricFu.output_directory, 'reek.png'))
103
+ end
104
+ end
105
+
106
+ class RoodiGchartGrapher < RoodiGrapher
107
+ def graph!
108
+ determine_y_axis_scale(@roodi_count)
109
+ url = Gchart.line(
110
+ :size => GCHART_GRAPH_SIZE,
111
+ :title => URI.escape("Roodi: potential design problems"),
112
+ :data => @roodi_count,
113
+ :max_value => @max_value,
114
+ :axis_with_labels => 'x,y',
115
+ :axis_labels => [@labels.values, @yaxis],
116
+ :format => 'file',
117
+ :filename => File.join(MetricFu.output_directory, 'roodi.png'))
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,19 @@
1
+ module MetricFu
2
+
3
+ class FlayGrapher < Grapher
4
+
5
+ attr_accessor :flay_score
6
+
7
+ def initialize
8
+ super
9
+ @flay_score = []
10
+ end
11
+
12
+ def get_metrics(metrics, date)
13
+ super
14
+ @flay_score.push(metrics[:flay][:total_score].to_i)
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,39 @@
1
+ module MetricFu
2
+
3
+ class FlogGrapher < Grapher
4
+
5
+ attr_accessor :flog_average, :top_five_percent_average
6
+
7
+ def initialize
8
+ super
9
+ @flog_average = []
10
+ @top_five_percent_average =[]
11
+ end
12
+
13
+ def get_metrics(metrics, date)
14
+ super
15
+ @top_five_percent_average.push(calc_top_five_percent_average(metrics))
16
+ @flog_average.push(metrics[:flog][:average])
17
+ end
18
+
19
+ private
20
+
21
+ def calc_top_five_percent_average(metrics)
22
+ methods = metrics[:flog][:pages].inject([]) {|methods, page| methods << page[:scanned_methods]}
23
+ methods.flatten!
24
+ methods = methods.sort_by {|method| method[:score]}.reverse
25
+
26
+ number_of_methods_that_is_five_percent = (methods.size * 0.05).ceil
27
+
28
+ total_for_five_percent =
29
+ methods[0...number_of_methods_that_is_five_percent].inject(0) {|total, method| total += method[:score] }
30
+ if number_of_methods_that_is_five_percent == 0
31
+ 0.0
32
+ else
33
+ total_for_five_percent / number_of_methods_that_is_five_percent.to_f
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,18 @@
1
+ module MetricFu
2
+ class Grapher
3
+ attr_accessor :labels
4
+
5
+ def initialize
6
+ self.class.require_graphing_gem
7
+ @labels = {}
8
+ end
9
+
10
+ def self.require_graphing_gem
11
+ # to be overridden by charting engines
12
+ end
13
+
14
+ def get_metrics(metrics, date)
15
+ @labels.update( { @labels.size => date })
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ module MetricFu
2
+
3
+ class RailsBestPracticesGrapher < Grapher
4
+
5
+ attr_accessor :rails_best_practices_count
6
+
7
+ def initialize
8
+ super
9
+ @rails_best_practices_count = []
10
+ end
11
+
12
+ def get_metrics(metrics, date)
13
+ super
14
+ if metrics[:rails_best_practices] && metrics[:rails_best_practices][:problems]
15
+ size = metrics[:rails_best_practices][:problems].size
16
+ else
17
+ size = 0
18
+ end
19
+ @rails_best_practices_count.push(size)
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,19 @@
1
+ module MetricFu
2
+
3
+ class RcovGrapher < Grapher
4
+
5
+ attr_accessor :rcov_percent
6
+
7
+ def initialize
8
+ super
9
+ @rcov_percent = []
10
+ end
11
+
12
+ def get_metrics(metrics, date)
13
+ super
14
+ @rcov_percent.push(metrics[:rcov][:global_percent_run])
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,31 @@
1
+ module MetricFu
2
+
3
+ class ReekGrapher < Grapher
4
+
5
+ attr_accessor :reek_count
6
+
7
+ def initialize
8
+ super
9
+ @reek_count = {}
10
+ end
11
+
12
+ def get_metrics(metrics, date)
13
+ counter = @labels.size
14
+ super
15
+
16
+ metrics[:reek][:matches].each do |reek_chunk|
17
+ reek_chunk[:code_smells].each do |code_smell|
18
+ # speaking of code smell...
19
+ @reek_count[code_smell[:type]] = [] if @reek_count[code_smell[:type]].nil?
20
+ if @reek_count[code_smell[:type]][counter].nil?
21
+ @reek_count[code_smell[:type]][counter] = 1
22
+ else
23
+ @reek_count[code_smell[:type]][counter] += 1
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,19 @@
1
+ module MetricFu
2
+
3
+ class RoodiGrapher < Grapher
4
+
5
+ attr_accessor :roodi_count
6
+
7
+ def initialize
8
+ super
9
+ @roodi_count = []
10
+ end
11
+
12
+ def get_metrics(metrics, date)
13
+ super
14
+ @roodi_count.push(metrics[:roodi][:problems].size)
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,22 @@
1
+
2
+ module MetricFu
3
+
4
+ class StatsGrapher < Grapher
5
+
6
+ attr_accessor :loc_counts, :lot_counts
7
+
8
+ def initialize
9
+ super
10
+ self.loc_counts = []
11
+ self.lot_counts = []
12
+ end
13
+
14
+ def get_metrics(metrics, date)
15
+ super
16
+ self.loc_counts.push(metrics[:stats][:codeLOC].to_i)
17
+ self.lot_counts.push(metrics[:stats][:testLOC].to_i)
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,32 @@
1
+ require 'rake'
2
+ require 'yaml'
3
+ require File.join(File.dirname(__FILE__), *%w[metric_fu railtie]) if defined?(::Rails::Railtie)
4
+ # Load a few things to make our lives easier elsewhere.
5
+ module MetricFu
6
+ LIB_ROOT = File.dirname(__FILE__)
7
+ end
8
+ base_dir = File.join(MetricFu::LIB_ROOT, 'base')
9
+ generator_dir = File.join(MetricFu::LIB_ROOT, 'generators')
10
+ template_dir = File.join(MetricFu::LIB_ROOT, 'templates')
11
+ graph_dir = File.join(MetricFu::LIB_ROOT, 'graphs')
12
+
13
+ # We need to require these two things first because our other classes
14
+ # depend on them.
15
+ require File.join(base_dir, 'report')
16
+ require File.join(base_dir, 'generator')
17
+ require File.join(base_dir, 'graph')
18
+
19
+ # prevent the task from being run multiple times.
20
+ unless Rake::Task.task_defined? "metrics:all"
21
+ # Load the rakefile so users of the gem get the default metric_fu task
22
+ load File.join(MetricFu::LIB_ROOT, 'tasks', 'metric_fu.rake')
23
+ end
24
+
25
+ # Now load everything else that's in the directory
26
+ Dir[File.join(base_dir, '*.rb')].each{|l| require l }
27
+ Dir[File.join(generator_dir, '*.rb')].each {|l| require l }
28
+ Dir[File.join(template_dir, 'standard/*.rb')].each {|l| require l}
29
+ Dir[File.join(template_dir, 'awesome/*.rb')].each {|l| require l}
30
+ require graph_dir + "/grapher"
31
+ Dir[File.join(graph_dir, '*.rb')].each {|l| require l}
32
+ Dir[File.join(graph_dir, 'engines', '*.rb')].each {|l| require l}
@@ -0,0 +1,10 @@
1
+ require 'metric_fu'
2
+ require 'rails'
3
+
4
+ module MetricFu
5
+ class Railtie < Rails::Railtie
6
+ rake_tasks do
7
+ load "tasks/metric_fu.rake"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,22 @@
1
+ require 'rake'
2
+ namespace :metrics do
3
+ desc "Generate all metrics reports"
4
+ task :all do
5
+ MetricFu::Configuration.run {}
6
+ MetricFu.metrics.each {|metric| MetricFu.report.add(metric) }
7
+ MetricFu.report.save_output(MetricFu.report.to_yaml,
8
+ MetricFu.base_directory,
9
+ "report.yml")
10
+ MetricFu.report.save_output(MetricFu.report.to_yaml,
11
+ MetricFu.data_directory,
12
+ "#{Time.now.strftime("%Y%m%d")}.yml")
13
+ MetricFu.report.save_templatized_report
14
+
15
+ MetricFu.graphs.each {|graph| MetricFu.graph.add(graph, MetricFu.graph_engine) }
16
+ MetricFu.graph.generate
17
+
18
+ if MetricFu.report.open_in_browser?
19
+ MetricFu.report.show_in_browser(MetricFu.output_directory)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ require 'fileutils'
2
+
3
+ class AwesomeTemplate < MetricFu::Template
4
+
5
+ def write
6
+ # Getting rid of the crap before and after the project name from integrity
7
+ @name = File.basename(Dir.pwd).gsub(/^\w+-|-\w+$/, "")
8
+
9
+ # Copy Bluff javascripts to output directory
10
+ Dir[File.join(this_directory, '..', 'javascripts', '*')].each do |f|
11
+ FileUtils.copy(f, File.join(MetricFu.output_directory, File.basename(f)))
12
+ end
13
+
14
+ report.each_pair do |section, contents|
15
+ if template_exists?(section)
16
+ create_instance_var(section, contents)
17
+ @html = erbify(section)
18
+ html = erbify('layout')
19
+ fn = output_filename(section)
20
+ MetricFu.report.save_output(html, MetricFu.output_directory, fn)
21
+ end
22
+ end
23
+
24
+ # Instance variables we need should already be created from above
25
+ if template_exists?('index')
26
+ @html = erbify('index')
27
+ html = erbify('layout')
28
+ fn = output_filename('index')
29
+ MetricFu.report.save_output(html, MetricFu.output_directory, fn)
30
+ end
31
+ end
32
+
33
+ def this_directory
34
+ File.dirname(__FILE__)
35
+ end
36
+ end
37
+
@@ -0,0 +1,58 @@
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
+
20
+ <% if @churn[:class_churn] %>
21
+ <p>Classes that change a lot in your project may be bad a sign.</p>
22
+ <table>
23
+ <tr>
24
+ <th>File Path</th>
25
+ <th>Times Changed</th>
26
+ </tr>
27
+ <% count = 0 %>
28
+ <% @churn[:class_churn].each do |change| %>
29
+ <tr>
30
+ <td><%= link_to_filename(change['klass']['file']) %> <%= change['klass']['klass'] %></td>
31
+ <td><%= change['times_changed'] %></td>
32
+ </tr>
33
+ <% count += 1 %>
34
+ <% end %>
35
+ </table>
36
+ <% end %>
37
+
38
+ <% if @churn[:method_churn] %>
39
+ <p>Methods that change a lot in your project may be bad a sign.</p>
40
+ <table>
41
+ <tr>
42
+ <th>File Path</th>
43
+ <th>Times Changed</th>
44
+ </tr>
45
+ <% count = 0 %>
46
+ <% @churn[:method_churn].each do |change| %>
47
+ <tr>
48
+ <td><%= link_to_filename(change['method']['file']) %> <%= change['method']['method'] %></td>
49
+ <td><%= change['times_changed'] %></td>
50
+ </tr>
51
+ <% count += 1 %>
52
+ <% end %>
53
+ </table>
54
+ <% end %>
55
+
56
+
57
+
58
+ <p>Generated on <%= Time.now.localtime %></p>