jscruggs-metric_fu 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +30 -0
- data/MIT-LICENSE +22 -0
- data/Manifest.txt +28 -0
- data/README +100 -0
- data/TODO.txt +4 -0
- data/lib/metric_fu.rb +7 -0
- data/lib/metric_fu/flog_reporter.rb +5 -0
- data/lib/metric_fu/flog_reporter/base.rb +59 -0
- data/lib/metric_fu/flog_reporter/flog_reporter.css +39 -0
- data/lib/metric_fu/flog_reporter/generator.rb +71 -0
- data/lib/metric_fu/flog_reporter/operator.rb +10 -0
- data/lib/metric_fu/flog_reporter/page.rb +36 -0
- data/lib/metric_fu/flog_reporter/scanned_method.rb +28 -0
- data/lib/metric_fu/md5_tracker.rb +52 -0
- data/lib/metric_fu/saikuro/SAIKURO_README +142 -0
- data/lib/metric_fu/saikuro/saikuro.rb +1216 -0
- data/lib/tasks/churn.rake +95 -0
- data/lib/tasks/coverage.rake +38 -0
- data/lib/tasks/flog.rake +58 -0
- data/lib/tasks/metric_fu.rake +11 -0
- data/lib/tasks/metric_fu.rb +6 -0
- data/lib/tasks/saikuro.rake +33 -0
- data/lib/tasks/stats.rake +14 -0
- data/metric_fu.gemspec +17 -0
- data/test/test_helper.rb +6 -0
- data/test/test_md5_tracker.rb +59 -0
- metadata +103 -0
@@ -0,0 +1,95 @@
|
|
1
|
+
namespace :metrics do
|
2
|
+
CHURN_DIR = File.join(MetricFu::BASE_DIRECTORY, 'churn')
|
3
|
+
|
4
|
+
desc "Which files change the most"
|
5
|
+
task :churn do
|
6
|
+
date_range, minimum_churn_count = churn_options()
|
7
|
+
svn_logs = `svn log #{date_range} --verbose`.split(/\n/).select {|line| line.strip =~ /^[A,M]/}
|
8
|
+
|
9
|
+
changes = {}
|
10
|
+
svn_logs.each do |line|
|
11
|
+
line.strip =~ /^[A,M] (.*)/
|
12
|
+
changes[$1] ? changes[$1] += 1 : changes[$1] = 1
|
13
|
+
end
|
14
|
+
write_churn_file(changes.reject {|file, change_count| change_count < minimum_churn_count})
|
15
|
+
system("open #{CHURN_DIR}/index.html") if PLATFORM['darwin']
|
16
|
+
end
|
17
|
+
|
18
|
+
def churn_options
|
19
|
+
options = defined?(CHURN_OPTIONS) ? CHURN_OPTIONS : {}
|
20
|
+
if options[:start_date]
|
21
|
+
require File.dirname(__FILE__) + '/../../../../config/environment'
|
22
|
+
date_range = "--revision {#{options[:start_date].call.strftime('%Y-%m-%d')}}:{#{Time.now.strftime('%Y-%m-%d')}}"
|
23
|
+
else
|
24
|
+
date_range = ""
|
25
|
+
end
|
26
|
+
minimum_churn_count = options[:minimum_churn_count] ? options[:minimum_churn_count] : 5
|
27
|
+
return date_range, minimum_churn_count
|
28
|
+
end
|
29
|
+
|
30
|
+
def write_churn_file changes
|
31
|
+
FileUtils.mkdir_p(CHURN_DIR, :verbose => false) unless File.directory?(CHURN_DIR)
|
32
|
+
File.open("#{CHURN_DIR}/index.html", "w+") do |file|
|
33
|
+
file << CHURN_FILE_BEGINING
|
34
|
+
changes.to_a.sort {|x,y| y[1] <=> x[1]}.each do |change|
|
35
|
+
file << "<tr><td>#{change[0]}</td><td class='warning'>#{change[1]}</td></tr>\n"
|
36
|
+
end
|
37
|
+
file << CHURN_FILE_END
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
CHURN_FILE_BEGINING = <<-EOS
|
42
|
+
<html><head><title>Source Control Churn Results</title></head>
|
43
|
+
<style>
|
44
|
+
body {
|
45
|
+
margin: 20px;
|
46
|
+
padding: 0;
|
47
|
+
font-size: 12px;
|
48
|
+
font-family: bitstream vera sans, verdana, arial, sans serif;
|
49
|
+
background-color: #efefef;
|
50
|
+
}
|
51
|
+
|
52
|
+
table {
|
53
|
+
border-collapse: collapse;
|
54
|
+
/*border-spacing: 0;*/
|
55
|
+
border: 1px solid #666;
|
56
|
+
background-color: #fff;
|
57
|
+
margin-bottom: 20px;
|
58
|
+
}
|
59
|
+
|
60
|
+
table, th, th+th, td, td+td {
|
61
|
+
border: 1px solid #ccc;
|
62
|
+
}
|
63
|
+
|
64
|
+
table th {
|
65
|
+
font-size: 12px;
|
66
|
+
color: #fc0;
|
67
|
+
padding: 4px 0;
|
68
|
+
background-color: #336;
|
69
|
+
}
|
70
|
+
|
71
|
+
th, td {
|
72
|
+
padding: 4px 10px;
|
73
|
+
}
|
74
|
+
|
75
|
+
td {
|
76
|
+
font-size: 13px;
|
77
|
+
}
|
78
|
+
|
79
|
+
.warning {
|
80
|
+
background-color: yellow;
|
81
|
+
}
|
82
|
+
</style>
|
83
|
+
|
84
|
+
<body>
|
85
|
+
<h1>Source Control Churn Results</h1>
|
86
|
+
<table width="100%" border="1">
|
87
|
+
<tr><th>File Path</th><th>Times Changed</th></tr>
|
88
|
+
EOS
|
89
|
+
|
90
|
+
CHURN_FILE_END = <<-EOS
|
91
|
+
</table>
|
92
|
+
</body>
|
93
|
+
</html>
|
94
|
+
EOS
|
95
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rcov'
|
5
|
+
require 'rcov/rcovtask'
|
6
|
+
|
7
|
+
namespace :metrics do
|
8
|
+
|
9
|
+
COVERAGE_DIR = File.join(MetricFu::BASE_DIRECTORY, 'coverage')
|
10
|
+
COVERAGE_DATA_FILE = File.join(MetricFu::BASE_DIRECTORY, 'coverage.data')
|
11
|
+
|
12
|
+
namespace :coverage do
|
13
|
+
rcov_output = COVERAGE_DIR
|
14
|
+
|
15
|
+
desc "Delete aggregate coverage data."
|
16
|
+
task(:clean) { rm_f("rcov_tmp", :verbose => false) }
|
17
|
+
|
18
|
+
desc "RCov task to generate report"
|
19
|
+
Rcov::RcovTask.new(:do => :clean) do |t|
|
20
|
+
FileUtils.mkdir_p(MetricFu::BASE_DIRECTORY) unless File.directory?(MetricFu::BASE_DIRECTORY)
|
21
|
+
t.test_files = FileList['test/**/*_test.rb']
|
22
|
+
t.rcov_opts = ["--sort coverage", "--aggregate '#{COVERAGE_DATA_FILE}'", "--html", "--rails"]
|
23
|
+
t.output_dir = COVERAGE_DIR
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Generate and open coverage report"
|
28
|
+
task :coverage => ['coverage:do'] do
|
29
|
+
system("open #{COVERAGE_DIR}/index.html") if PLATFORM['darwin']
|
30
|
+
end
|
31
|
+
end
|
32
|
+
rescue LoadError
|
33
|
+
if RUBY_PLATFORM =~ /java/
|
34
|
+
puts 'running in jruby - rcov tasks not available'
|
35
|
+
else
|
36
|
+
puts 'sudo gem install rcov # if you want the rcov tasks'
|
37
|
+
end
|
38
|
+
end
|
data/lib/tasks/flog.rake
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'metricks', 'md5_tracker')
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'metricks', 'flog_reporter')
|
3
|
+
|
4
|
+
begin
|
5
|
+
FLOG_DIR = File.join(MetricFu::BASE_DIRECTORY, 'flog')
|
6
|
+
|
7
|
+
def flog(output, directory)
|
8
|
+
Dir.glob("#{directory}/**/*.rb").each do |filename|
|
9
|
+
output_dir = "#{FLOG_DIR}/#{filename.split("/")[0..-2].join("/")}"
|
10
|
+
mkdir_p(output_dir, :verbose => false) unless File.directory?(output_dir)
|
11
|
+
`flog #{filename} > #{FLOG_DIR}/#{filename.split('.')[0]}.txt` if MetricFu::MD5Tracker.file_changed?(filename, FLOG_DIR)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
namespace :metrics do
|
16
|
+
|
17
|
+
task :flog => ['flog:all'] do
|
18
|
+
end
|
19
|
+
|
20
|
+
namespace :flog do
|
21
|
+
desc "Delete aggregate flog data."
|
22
|
+
task(:clean) { rm_rf(FLOG_DIR, :verbose => false) }
|
23
|
+
|
24
|
+
desc "Flog code in app/models"
|
25
|
+
task :models do
|
26
|
+
flog "models", "app/models"
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "Flog code in app/controllers"
|
30
|
+
task :controllers do
|
31
|
+
flog "controllers", "app/controllers"
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "Flog code in app/helpers"
|
35
|
+
task :helpers do
|
36
|
+
flog "helpers", "app/helpers"
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "Flog code in lib"
|
40
|
+
task :lib do
|
41
|
+
flog "lib", "lib"
|
42
|
+
end
|
43
|
+
|
44
|
+
desc "Generate and open flog report"
|
45
|
+
task :all => [:models, :controllers, :helpers, :lib] do
|
46
|
+
MetricFu::FlogReporter::Generator.generate_report(FLOG_DIR)
|
47
|
+
system("open #{FLOG_DIR}/index.html") if PLATFORM['darwin']
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
rescue LoadError
|
53
|
+
if RUBY_PLATFORM =~ /java/
|
54
|
+
puts 'running in jruby - flog tasks not available'
|
55
|
+
else
|
56
|
+
puts 'sudo gem install flog # if you want the flog tasks'
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
namespace :metrics do
|
2
|
+
task :prepare do
|
3
|
+
RAILS_ENV = 'test'
|
4
|
+
end
|
5
|
+
|
6
|
+
desc "Useful for continuous integration"
|
7
|
+
task :all_with_migrate => [:prepare, "db:migrate", :all]
|
8
|
+
|
9
|
+
desc "Generate coverage, cyclomatic complexity (saikuro), flog, stats, and churn reports"
|
10
|
+
task :all => [:coverage, :saikuro, :flog, :churn, :stats]
|
11
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
namespace :metrics do
|
2
|
+
|
3
|
+
SAIKURO_DIR = File.join(MetricFu::BASE_DIRECTORY, 'saikuro')
|
4
|
+
|
5
|
+
desc "A cyclomatic complexity report using Saikuro"
|
6
|
+
task :saikuro do
|
7
|
+
default_options = {"--output_directory" => SAIKURO_DIR,
|
8
|
+
"--input_directory" => "app",
|
9
|
+
"--cyclo" => "",
|
10
|
+
"--filter_cyclo" => "0",
|
11
|
+
"--warn_cyclo" => "5",
|
12
|
+
"--error_cyclo" => "7"}
|
13
|
+
|
14
|
+
default_options.merge!(SAIKURO_OPTIONS) if defined?(SAIKURO_OPTIONS)
|
15
|
+
options = ""
|
16
|
+
default_options.each_pair { |key, value| options << "#{key} #{value} " }
|
17
|
+
|
18
|
+
sh "ruby \"#{File.expand_path(File.join(File.dirname(__FILE__), '..', 'metricks', 'saikuro'))}/saikuro.rb\" " +
|
19
|
+
"#{options}" do |ok, response|
|
20
|
+
unless ok
|
21
|
+
puts "Saikuro failed with exit status: #{response.exitstatus}"
|
22
|
+
exit 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if File.exist? "#{SAIKURO_DIR}/index_cyclo.html"
|
27
|
+
mv "#{SAIKURO_DIR}/index_cyclo.html",
|
28
|
+
"#{SAIKURO_DIR}/index.html"
|
29
|
+
end
|
30
|
+
|
31
|
+
system("open #{SAIKURO_DIR}/index.html") if PLATFORM['darwin']
|
32
|
+
end
|
33
|
+
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 PLATFORM['darwin']
|
13
|
+
end
|
14
|
+
end
|
data/metric_fu.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "metric_fu"
|
3
|
+
s.version = "0.7.0"
|
4
|
+
s.date = "2008-09-11"
|
5
|
+
s.summary = "Generates project metrics using Flog, RCov, Saikuro and more"
|
6
|
+
s.email = "jake.scruggs@gmail.com"
|
7
|
+
s.homepage = "http://metric-fu.rubyforge.org/"
|
8
|
+
s.description = "Gives you a fist full of code metrics"
|
9
|
+
s.has_rdoc = true
|
10
|
+
s.authors = ["Jake Scruggs", "Sean Soper"]
|
11
|
+
s.files = ["History.txt", "Manifest.txt", "metric_fu.gemspec", "MIT-LICENSE", "README", "TODO.txt", "lib/metric_fu", "lib/metric_fu/flog_reporter", "lib/metric_fu/flog_reporter/base.rb", "lib/metric_fu/flog_reporter/flog_reporter.css", "lib/metric_fu/flog_reporter/generator.rb", "lib/metric_fu/flog_reporter/operator.rb", "lib/metric_fu/flog_reporter/page.rb", "lib/metric_fu/flog_reporter/scanned_method.rb", "lib/metric_fu/flog_reporter.rb", "lib/metric_fu/md5_tracker.rb", "lib/metric_fu/saikuro", "lib/metric_fu/saikuro/saikuro.rb", "lib/metric_fu/saikuro/SAIKURO_README", "lib/metric_fu.rb", "lib/tasks", "lib/tasks/churn.rake", "lib/tasks/coverage.rake", "lib/tasks/flog.rake", "lib/tasks/metric_fu.rake", "lib/tasks/metric_fu.rb", "lib/tasks/saikuro.rake", "lib/tasks/stats.rake", "test/test_helper.rb", "test/test_md5_tracker.rb"]
|
12
|
+
s.test_files = ["test/test_md5_tracker.rb"]
|
13
|
+
s.rdoc_options = ["--main", "README"]
|
14
|
+
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README"]
|
15
|
+
s.add_dependency("flog", ["> 0.0.0"])
|
16
|
+
s.add_dependency("rcov", ["> 0.0.0"])
|
17
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class TestMD5Tracker < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@tmp_dir = File.join(File.dirname(__FILE__), 'tmp')
|
7
|
+
FileUtils.mkdir_p(@tmp_dir, :verbose => false) unless File.directory?(@tmp_dir)
|
8
|
+
@file1 = File.new(File.join(@tmp_dir, 'file1.txt'), 'w')
|
9
|
+
@file2 = File.new(File.join(@tmp_dir, 'file2.txt'), 'w')
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
FileUtils.rm_rf(@tmp_dir, :verbose => false)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_identical_files_match
|
17
|
+
@file1.puts("Hello World")
|
18
|
+
@file1.close
|
19
|
+
file1_md5 = MetricFu::MD5Tracker.track(@file1.path, @tmp_dir)
|
20
|
+
|
21
|
+
@file2.puts("Hello World")
|
22
|
+
@file2.close
|
23
|
+
file2_md5 = MetricFu::MD5Tracker.track(@file2.path, @tmp_dir)
|
24
|
+
|
25
|
+
assert file1_md5 == file2_md5
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_different_files_dont_match
|
29
|
+
@file1.puts("Hello World")
|
30
|
+
@file1.close
|
31
|
+
file1_md5 = MetricFu::MD5Tracker.track(@file1.path, @tmp_dir)
|
32
|
+
|
33
|
+
@file2.puts("Goodbye World")
|
34
|
+
@file2.close
|
35
|
+
file2_md5 = MetricFu::MD5Tracker.track(@file2.path, @tmp_dir)
|
36
|
+
|
37
|
+
assert file1_md5 != file2_md5
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_file_changed
|
41
|
+
@file2.close
|
42
|
+
|
43
|
+
@file1.puts("Hello World")
|
44
|
+
@file1.close
|
45
|
+
file1_md5 = MetricFu::MD5Tracker.track(@file1.path, @tmp_dir)
|
46
|
+
|
47
|
+
@file1 = File.new(File.join(@tmp_dir, 'file1.txt'), 'w')
|
48
|
+
@file1.puts("Goodbye World")
|
49
|
+
@file1.close
|
50
|
+
assert MetricFu::MD5Tracker.file_changed?(@file1.path, @tmp_dir)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_file_changed_if_not_tracking
|
54
|
+
@file2.close
|
55
|
+
|
56
|
+
assert MetricFu::MD5Tracker.file_changed?(@file1.path, @tmp_dir)
|
57
|
+
assert File.exist?(MetricFu::MD5Tracker.md5_file(@file1.path, @tmp_dir))
|
58
|
+
end
|
59
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jscruggs-metric_fu
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.7.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jake Scruggs
|
8
|
+
- Sean Soper
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2008-09-11 00:00:00 -07:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: flog
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rcov
|
27
|
+
version_requirement:
|
28
|
+
version_requirements: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.0.0
|
33
|
+
version:
|
34
|
+
description: Gives you a fist full of code metrics
|
35
|
+
email: jake.scruggs@gmail.com
|
36
|
+
executables: []
|
37
|
+
|
38
|
+
extensions: []
|
39
|
+
|
40
|
+
extra_rdoc_files:
|
41
|
+
- History.txt
|
42
|
+
- Manifest.txt
|
43
|
+
- README
|
44
|
+
files:
|
45
|
+
- History.txt
|
46
|
+
- Manifest.txt
|
47
|
+
- metric_fu.gemspec
|
48
|
+
- MIT-LICENSE
|
49
|
+
- README
|
50
|
+
- TODO.txt
|
51
|
+
- lib/metric_fu
|
52
|
+
- lib/metric_fu/flog_reporter
|
53
|
+
- lib/metric_fu/flog_reporter/base.rb
|
54
|
+
- lib/metric_fu/flog_reporter/flog_reporter.css
|
55
|
+
- lib/metric_fu/flog_reporter/generator.rb
|
56
|
+
- lib/metric_fu/flog_reporter/operator.rb
|
57
|
+
- lib/metric_fu/flog_reporter/page.rb
|
58
|
+
- lib/metric_fu/flog_reporter/scanned_method.rb
|
59
|
+
- lib/metric_fu/flog_reporter.rb
|
60
|
+
- lib/metric_fu/md5_tracker.rb
|
61
|
+
- lib/metric_fu/saikuro
|
62
|
+
- lib/metric_fu/saikuro/saikuro.rb
|
63
|
+
- lib/metric_fu/saikuro/SAIKURO_README
|
64
|
+
- lib/metric_fu.rb
|
65
|
+
- lib/tasks
|
66
|
+
- lib/tasks/churn.rake
|
67
|
+
- lib/tasks/coverage.rake
|
68
|
+
- lib/tasks/flog.rake
|
69
|
+
- lib/tasks/metric_fu.rake
|
70
|
+
- lib/tasks/metric_fu.rb
|
71
|
+
- lib/tasks/saikuro.rake
|
72
|
+
- lib/tasks/stats.rake
|
73
|
+
- test/test_helper.rb
|
74
|
+
- test/test_md5_tracker.rb
|
75
|
+
has_rdoc: true
|
76
|
+
homepage: http://metric-fu.rubyforge.org/
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options:
|
79
|
+
- --main
|
80
|
+
- README
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: "0"
|
88
|
+
version:
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: "0"
|
94
|
+
version:
|
95
|
+
requirements: []
|
96
|
+
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 1.2.0
|
99
|
+
signing_key:
|
100
|
+
specification_version: 2
|
101
|
+
summary: Generates project metrics using Flog, RCov, Saikuro and more
|
102
|
+
test_files:
|
103
|
+
- test/test_md5_tracker.rb
|