p8-metric_fu 0.9.0.1 → 0.9.0.2

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.
@@ -0,0 +1,9 @@
1
+ require File.join(File.dirname(__FILE__), '../metric_fu/churn')
2
+
3
+ namespace :metrics do
4
+
5
+ desc "Which files change the most"
6
+ task :churn do
7
+ MetricFu.generate_churn_report
8
+ end
9
+ end
@@ -0,0 +1,54 @@
1
+ require 'fileutils'
2
+
3
+ begin
4
+ require 'rcov'
5
+ require 'rcov/rcovtask'
6
+ require 'spec/rake/spectask'
7
+
8
+ namespace :metrics do
9
+
10
+ COVERAGE_DIR = File.join(MetricFu::BASE_DIRECTORY, 'coverage')
11
+ COVERAGE_DATA_FILE = File.join(MetricFu::BASE_DIRECTORY, 'coverage.data')
12
+ SPEC_HTML_FILE = File.join(MetricFu::BASE_DIRECTORY, 'specs.html')
13
+
14
+ namespace :coverage do
15
+ rcov_output = COVERAGE_DIR
16
+
17
+ desc "Delete aggregate coverage data."
18
+ task(:clean) { rm_f("rcov_tmp", :verbose => false) }
19
+
20
+ desc "RCov task to generate report"
21
+ Rcov::RcovTask.new(:do => :clean) do |t|
22
+ FileUtils.mkdir_p(MetricFu::BASE_DIRECTORY) unless File.directory?(MetricFu::BASE_DIRECTORY)
23
+ t.test_files = FileList[*MetricFu.coverage[:test_files]]
24
+ t.rcov_opts = MetricFu.coverage[:rcov_opts]
25
+ t.output_dir = COVERAGE_DIR
26
+ # this line is a fix for Rails 2.1 relative loading issues
27
+ t.libs << 'test'
28
+ end
29
+ # TODO not sure what this improves but it requires the diff-lcs gem
30
+ # http://github.com/indirect/metric_fu/commit/b9c1cf75f09d5b531b388cd01661eb16b5126968#diff-1
31
+ # Spec::Rake::SpecTask.new(:do => :clean) do |t|
32
+ # FileUtils.mkdir_p(MetricFu::BASE_DIRECTORY) unless File.directory?(MetricFu::BASE_DIRECTORY)
33
+ # t.ruby_opts = ['-rtest/unit']
34
+ # t.spec_files = FileList['test/**/*_test.rb', 'spec/**/*spec.rb']
35
+ # t.spec_opts = ["--format", "html:#{SPEC_HTML_FILE}", "--diff"]
36
+ # t.rcov = true
37
+ # t.rcov_opts = ["--sort coverage", "--html", "--rails", "--exclude /gems/,/Library/"]
38
+ # t.rcov_dir = COVERAGE_DIR
39
+ # end
40
+ end
41
+
42
+ desc "Generate and open coverage report"
43
+ task :coverage => ['coverage:do'] do
44
+ system("open #{COVERAGE_DIR}/index.html") if MetricFu.open_in_browser?
45
+ end
46
+ end
47
+ rescue LoadError
48
+ if RUBY_PLATFORM =~ /java/
49
+ puts 'running in jruby - rcov tasks not available'
50
+ else
51
+ puts 'sudo gem install rcov # if you want the rcov tasks'
52
+
53
+ end
54
+ end
@@ -0,0 +1,6 @@
1
+ namespace :metrics do
2
+ desc "Generate code duplication report with flay"
3
+ task :flay do
4
+ MetricFu.generate_flay_report
5
+ end
6
+ end
@@ -0,0 +1,69 @@
1
+ begin
2
+
3
+ def flog(output, directory)
4
+ metric_dir = MetricFu::Flog::Generator.metric_dir
5
+ Dir.glob("#{directory}/**/*.rb").each do |filename|
6
+ output_dir = "#{metric_dir}/#{filename.split("/")[0..-2].join("/")}"
7
+ mkdir_p(output_dir, :verbose => false) unless File.directory?(output_dir)
8
+ if MetricFu::MD5Tracker.file_changed?(filename, metric_dir)
9
+ `flog #{filename} > #{metric_dir}/#{filename.split('.')[0]}.txt`
10
+ end
11
+ end
12
+ end
13
+
14
+ namespace :metrics do
15
+
16
+ task :flog => ['flog:all'] do
17
+ end
18
+
19
+ namespace :flog do
20
+ desc "Delete aggregate flog data."
21
+ task(:clean) { rm_rf(MetricFu::Flog.metric_dir, :verbose => false) }
22
+
23
+ desc "Flog code in app/models"
24
+ task :models do
25
+ flog "models", "app/models"
26
+ end
27
+
28
+ desc "Flog code in app/controllers"
29
+ task :controllers do
30
+ flog "controllers", "app/controllers"
31
+ end
32
+
33
+ desc "Flog code in app/helpers"
34
+ task :helpers do
35
+ flog "helpers", "app/helpers"
36
+ end
37
+
38
+ desc "Flog code in lib"
39
+ task :lib do
40
+ flog "lib", "lib"
41
+ end
42
+
43
+ desc "Generate a flog report from specified directories"
44
+ task :custom do
45
+ MetricFu::flog[:dirs_to_flog].each { |directory| flog(directory, directory) }
46
+ MetricFu.generate_flog_report
47
+ end
48
+
49
+ desc "Generate and open flog report"
50
+ if MetricFu::RAILS
51
+ task :all => [:models, :controllers, :helpers, :lib] do
52
+ MetricFu.generate_flog_report
53
+ end
54
+ else
55
+ task :all => [:custom] do
56
+ MetricFu.generate_flog_report
57
+ end
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+ rescue LoadError
64
+ if RUBY_PLATFORM =~ /java/
65
+ puts 'running in jruby - flog tasks not available'
66
+ else
67
+ puts 'sudo gem install flog # if you want the flog tasks'
68
+ end
69
+ end
@@ -0,0 +1,24 @@
1
+ # only load configured metrics
2
+ MetricFu.metrics.each { |task| import "#{File.dirname(__FILE__)}/#{task}.rake" }
3
+
4
+ namespace :metrics do
5
+ if MetricFu::RAILS
6
+
7
+ desc "Generate coverage, cyclomatic complexity, flog, flay, railroad, reek, roodi, stats and churn reports"
8
+ task :all => MetricFu.metrics
9
+
10
+ task :set_testing_env do
11
+ RAILS_ENV = 'test'
12
+ end
13
+
14
+ desc "Generate metrics after migrating (for continuous integration)"
15
+ task :all_with_migrate => [:set_testing_env, "db:migrate", :all]
16
+
17
+ else
18
+
19
+ desc "Generate coverage, cyclomatic complexity, flog, flay, railroad and churn reports"
20
+ task :all => MetricFu.metrics
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,6 @@
1
+ require 'fileutils'
2
+ require 'rubygems'
3
+ require 'rake'
4
+
5
+ # Load rake files
6
+ import "#{File.dirname(__FILE__)}/metric_fu.rake"
@@ -0,0 +1,39 @@
1
+ namespace :metrics do
2
+
3
+ RAILROAD_DIR = File.join(MetricFu::BASE_DIRECTORY, 'railroad')
4
+ RAILROAD_FILE = File.join(RAILROAD_DIR, 'index.html')
5
+
6
+ task :railroad => ['railroad:all'] do
7
+ end
8
+
9
+ namespace :railroad do
10
+
11
+ desc "Create all railroad reports"
12
+ task :all => [:models, :controllers, :aasm] do
13
+ #system("open #{RAILROAD_INDEX}") if PLATFORM['darwin']
14
+ end
15
+
16
+ desc "Create a railroad models report"
17
+ task :models do
18
+ #mkdir_p(RAILROAD_DIR) unless File.directory?(RAILROAD_DIR)
19
+ `railroad -M -a -m -l -v | neato -Tpng > #{File.join(MetricFu::BASE_DIRECTORY,'model-diagram.png')}`
20
+ #`echo "<a href=\"railroad/models.png\">Model diagram</a><br />" >> #{RAILROAD_FILE}`
21
+ end
22
+
23
+ desc "Create a railroad controllers report"
24
+ task :controllers do
25
+ #mkdir_p(RAILROAD_DIR) unless File.directory?(RAILROAD_DIR)
26
+ `railroad -C -l -v | neato -Tpng > #{File.join(MetricFu::BASE_DIRECTORY,'controller-diagram.png')}`
27
+ #`echo "<a href=\"railroad/controllers.png\">Controller diagram</a><br />" >> #{RAILROAD_FILE}`
28
+ end
29
+
30
+ desc "Create a railroad acts_as_state_machine report"
31
+ task :aasm do
32
+ #mkdir_p(RAILROAD_DIR) unless File.directory?(RAILROAD_DIR)
33
+ `railroad -A -l -v | neato -Tpng > #{File.join(MetricFu::BASE_DIRECTORY,'aasm-diagram.png')}`
34
+ #`echo "<a href=\"railroad/aasm.png\">State machine diagram</a><br />" >> #{RAILROAD_FILE}`
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,6 @@
1
+ namespace :metrics do
2
+ desc "A code smell report using Reek"
3
+ task :reek do
4
+ MetricFu.generate_reek_report
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ namespace :metrics do
2
+
3
+ desc "A Ruby coding standards report using Roodi"
4
+ task :roodi do
5
+ MetricFu.generate_roodi_report
6
+ end
7
+ end
@@ -0,0 +1,35 @@
1
+ require 'fileutils'
2
+
3
+ namespace :metrics do
4
+
5
+ desc "A cyclomatic complexity report using Saikuro"
6
+ task :saikuro do
7
+ SAIKURO_DIR = File.join(MetricFu::BASE_DIRECTORY, 'saikuro')
8
+ SAIKURO = File.expand_path(File.join(File.dirname(__FILE__), '..', 'metric_fu', 'saikuro', 'saikuro.rb'))
9
+
10
+ raise "SAIKURO_OPTIONS is now MetricFu::SAIKURO_OPTIONS" if defined?(SAIKURO_OPTIONS)
11
+ options = { :output_directory => SAIKURO_DIR,
12
+ :input_directory => MetricFu::CODE_DIRS,
13
+ :cyclo => "",
14
+ :filter_cyclo => "0",
15
+ :warn_cyclo => "5",
16
+ :error_cyclo => "7"}
17
+
18
+ options.merge!(MetricFu::SAIKURO_OPTIONS) if defined?(MetricFu::SAIKURO_OPTIONS)
19
+ options_string = options.inject(""){ |o, h| o + "--#{h.join(' ')} " }
20
+
21
+ sh %{ruby "#{SAIKURO}" #{options_string}} do |ok, response|
22
+ unless ok
23
+ puts "Saikuro failed with exit status: #{response.exitstatus}"
24
+ exit 1
25
+ end
26
+ end
27
+
28
+ if File.exist? "#{SAIKURO_DIR}/index_cyclo.html"
29
+ mv "#{SAIKURO_DIR}/index_cyclo.html",
30
+ "#{SAIKURO_DIR}/index.html"
31
+ end
32
+
33
+ system("open #{SAIKURO_DIR}/index.html") if MetricFu.open_in_browser?
34
+ end
35
+ end
@@ -0,0 +1,14 @@
1
+ namespace :metrics do
2
+
3
+ STATS_DIR = File.join(MetricFu::BASE_DIRECTORY, 'stats')
4
+ STATS_FILE = File.join(STATS_DIR, 'index.html')
5
+
6
+ desc "A stats report"
7
+ task :stats do
8
+ mkdir_p(STATS_DIR) unless File.directory?(STATS_DIR)
9
+ `echo '<pre>' > #{STATS_FILE}`
10
+ `rake stats >> #{STATS_FILE}`
11
+ `echo '</pre>' >> #{STATS_FILE}`
12
+ system("open #{STATS_FILE}") if MetricFu.open_in_browser?
13
+ end
14
+ end
@@ -0,0 +1,22 @@
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><th>File Path</th><th>Times Changed</th></tr>
16
+ <% @changes.to_a.sort {|x,y| y[1] <=> x[1]}.each do |change| %>
17
+ <tr><td><%= link_to_filename(change[0]) %></td><td class='warning'><%= change[1] %></td></tr>
18
+ <% end %>
19
+ </table>
20
+ <p>Generated on <%= Time.now.localtime %></p>
21
+ </body>
22
+ </html>
@@ -0,0 +1,45 @@
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
+ }
@@ -0,0 +1,30 @@
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
+ <p><a href='http://ruby.sadi.st/Flay.html'>Flay</a> analyzes ruby code for structural similarities.</p>
12
+ <table>
13
+ <tr>
14
+ <th>Files</th>
15
+ <th>Matches</th>
16
+ </tr>
17
+ <% @matches.each_with_index do |match, count| %>
18
+ <tr class='<%= cycle("light", "dark", count) %>'>
19
+ <td>
20
+ <% match[1..-1].each do |filename| %>
21
+ <%= link_to_filename(*filename.split(":")) %><br>
22
+ <% end %>
23
+ </td>
24
+ <td><%= match.first %></td>
25
+ </tr>
26
+ <% end %>
27
+ </table>
28
+ <p>Generated on <%= Time.now.localtime %></p>
29
+ </body>
30
+ </html>
@@ -0,0 +1,38 @@
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
+ <table>
12
+ <tr>
13
+ <th>File</th>
14
+ <th>Total score</th>
15
+ <th>Methods</th>
16
+ <th>Average score</th>
17
+ <th>Highest score</th>
18
+ </tr>
19
+ <% pages.sort {|x,y| y.highest_score <=> x.highest_score }.each_with_index do |page, count| %>
20
+ <tr class='<%= cycle("light", "dark", count) %>'>
21
+ <td><a href='<%= page.path %>'><%= page.path.sub('.html', '.rb') %></a></td>
22
+ <td class='score'><%= sprintf(SCORE_FORMAT, page.score) %></td>
23
+ <td class='score'><%= page.scanned_methods.length %></td>
24
+ <td class='score'><%= sprintf(SCORE_FORMAT, page.average_score) %></td>
25
+ <td class='score'><%= sprintf(SCORE_FORMAT, page.highest_score) %></td>
26
+ </tr>
27
+ <% end %>
28
+ <tr>
29
+ <td><strong>Totals</strong></td>
30
+ <td class='score'><strong><%= sprintf(SCORE_FORMAT, pages.inject(0){|sum, page| sum + page.score }) %></strong></td>
31
+ <td class='score'><strong><%= pages.inject(0){|sum, page| sum + page.scanned_methods.length } %></strong></td>
32
+ <td class='score'></td>
33
+ <td class='score'></td>
34
+ </tr>
35
+ </table>
36
+ <p>Generated on <%= Time.now.localtime %></p>
37
+ </body>
38
+ </html>
@@ -0,0 +1,25 @@
1
+ <html>
2
+ <head>
3
+ <style>
4
+ <%= inline_css("default.css") %>
5
+ </style>
6
+ </head>
7
+ <body>
8
+ <p>Score: <%= score %></p>
9
+ <% scanned_methods.each do |sm| %>
10
+ <p><strong><%= sm.name %> (<%= sm.score %>)</strong></p>
11
+ <table>
12
+ <tr>
13
+ <th>Score</th>
14
+ <th>Operator</th>
15
+ </tr>
16
+ <% sm.operators.each_with_index do |operator, count| %>
17
+ <tr class='<%= cycle("light", "dark", count) %>'>
18
+ <td class='score'><%= sprintf(SCORE_FORMAT, operator.score) %></td>
19
+ <td class='score'><%= operator.operator %></td>
20
+ </tr>
21
+ <% end %>
22
+ </table>
23
+ <% end %>
24
+ </body>
25
+ </html>