indirect-metric_fu 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/metric_fu.rb ADDED
@@ -0,0 +1,14 @@
1
+ module MetricFu
2
+ TEMPLATE_DIR = File.join(File.dirname(__FILE__), "templates")
3
+ BASE_DIRECTORY = ENV['CC_BUILD_ARTIFACTS'] || 'tmp/metric_fu'
4
+ RAILS = File.exist?("config/environment.rb")
5
+
6
+ if RAILS
7
+ CODE_DIRS = ['app', 'lib']
8
+ else
9
+ CODE_DIRS = ['lib']
10
+ end
11
+ end
12
+
13
+ require File.join(File.dirname(__FILE__), 'tasks', 'metric_fu')
14
+ Dir[File.join(File.dirname(__FILE__), 'metric_fu/*.rb')].each{|l| require l }
@@ -0,0 +1,11 @@
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
+ churn_dir = File.join(MetricFu::BASE_DIRECTORY, 'churn')
8
+ MetricFu::Churn.generate_report(churn_dir, defined?(MetricFu::CHURN_OPTIONS) ? MetricFu::CHURN_OPTIONS : {} )
9
+ system("open #{churn_dir}/index.html") if PLATFORM['darwin']
10
+ end
11
+ end
@@ -0,0 +1,42 @@
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
+ Spec::Rake::SpecTask.new(:do => :clean) do |t|
21
+ FileUtils.mkdir_p(MetricFu::BASE_DIRECTORY) unless File.directory?(MetricFu::BASE_DIRECTORY)
22
+ t.ruby_opts = ['-rtest/unit']
23
+ t.spec_files = FileList['test/**/*_test.rb', 'spec/**/*spec.rb']
24
+ t.spec_opts = ["--format", "html:#{SPEC_HTML_FILE}", "--diff"]
25
+ t.rcov = true
26
+ t.rcov_opts = ["--sort coverage", "--html", "--rails", "--exclude /gems/,/Library/"]
27
+ t.rcov_dir = COVERAGE_DIR
28
+ end
29
+ end
30
+
31
+ desc "Generate RCov report"
32
+ task :coverage => ['coverage:do'] do
33
+ system("open #{SPEC_HTML_FILE}") if PLATFORM['darwin']
34
+ end
35
+ end
36
+ rescue LoadError
37
+ if RUBY_PLATFORM =~ /java/
38
+ puts 'running in jruby - rcov tasks not available'
39
+ else
40
+ puts 'sudo gem install rcov # if you want the rcov tasks'
41
+ end
42
+ end
@@ -0,0 +1,69 @@
1
+ begin
2
+ FLOG_DIR = File.join(MetricFu::BASE_DIRECTORY, 'flog')
3
+
4
+ def flog(output, directory)
5
+ Dir.glob("#{directory}/**/*.rb").each do |filename|
6
+ output_dir = "#{FLOG_DIR}/#{filename.split("/")[0..-2].join("/")}"
7
+ mkdir_p(output_dir, :verbose => false) unless File.directory?(output_dir)
8
+ `flog #{filename} > #{FLOG_DIR}/#{filename.split('.')[0]}.txt` if MetricFu::MD5Tracker.file_changed?(filename, FLOG_DIR)
9
+ end
10
+ end
11
+
12
+ namespace :metrics do
13
+
14
+ task :flog => ['flog:all'] do
15
+ end
16
+
17
+ namespace :flog do
18
+ desc "Delete aggregate flog data."
19
+ task(:clean) { rm_rf(FLOG_DIR, :verbose => false) }
20
+
21
+ desc "Flog code in app/models"
22
+ task :models do
23
+ flog "models", "app/models"
24
+ end
25
+
26
+ desc "Flog code in app/controllers"
27
+ task :controllers do
28
+ flog "controllers", "app/controllers"
29
+ end
30
+
31
+ desc "Flog code in app/helpers"
32
+ task :helpers do
33
+ flog "helpers", "app/helpers"
34
+ end
35
+
36
+ desc "Flog code in lib"
37
+ task :lib do
38
+ flog "lib", "lib"
39
+ end
40
+
41
+ desc "Generate a flog report from specified directories"
42
+ task :custom do
43
+ MetricFu::CODE_DIRS.each { |directory| flog(directory, directory) }
44
+ MetricFu::FlogReporter::Generator.generate_report(FLOG_DIR)
45
+ end
46
+
47
+ desc "Generate and open flog report"
48
+ if MetricFu::RAILS
49
+ task :all => [:models, :controllers, :helpers, :lib] do
50
+ MetricFu::FlogReporter::Generator.generate_report(FLOG_DIR)
51
+ system("open #{FLOG_DIR}/index.html") if PLATFORM['darwin']
52
+ end
53
+ else
54
+ task :all => [:custom] do
55
+ MetricFu::FlogReporter::Generator.generate_report(FLOG_DIR)
56
+ system("open #{FLOG_DIR}/index.html") if PLATFORM['darwin']
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,16 @@
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
+ if MetricFu::RAILS
10
+ desc "Generate coverage, cyclomatic complexity, flog, stats, and churn reports"
11
+ task :all => [:coverage, :saikuro, :flog, :churn, :stats]
12
+ else
13
+ desc "Generate coverage, cyclomatic complexity, flog, and churn reports"
14
+ task :all => [:coverage, :saikuro, :flog, :churn]
15
+ end
16
+ end
@@ -0,0 +1,6 @@
1
+ require 'fileutils'
2
+ require 'rubygems'
3
+ require 'rake'
4
+
5
+ # Load rake files
6
+ Dir["#{File.dirname(__FILE__)}/*.rake"].each { |ext| load ext }
@@ -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 PLATFORM['darwin']
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 PLATFORM['darwin']
13
+ end
14
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec'
2
+ require File.dirname(__FILE__) + '/../lib/metric_fu/churn'
3
+ include MetricFu
4
+
5
+ describe MetricFu::Churn do
6
+ describe "generate_report" do
7
+ after do
8
+ load File.dirname(__FILE__) + '/../lib/metric_fu/churn.rb' #need to reload file to wipe out mock of private static
9
+ end
10
+
11
+ it "should strip out files that have less than the min count" do
12
+ Churn.should_receive(:churn_options).and_return(["", 5, :git])
13
+ Churn.should_receive(:parse_log_for_changes).with(:git, "").and_return({"reject" => 4, "accept" => 5})
14
+ Churn.should_receive(:write_churn_file).with({"accept" => 5}, "output_dir")
15
+ Churn.generate_report("output_dir", {})
16
+ end
17
+ end
18
+
19
+ describe "parse_log_for_changes" do
20
+ it "should count the changes with git" do
21
+ logs = ["home_page/index.html", "README", "History.txt", "README", "History.txt", "README"]
22
+ Churn.should_receive(:get_logs).with(:git, "").and_return(logs)
23
+ changes = Churn.send(:parse_log_for_changes, :git, "")
24
+
25
+ changes["home_page/index.html"].should == 1
26
+ changes["History.txt"].should == 2
27
+ changes["README"].should == 3
28
+ end
29
+
30
+ it "should count the changes with svn" do
31
+ logs = ["home_page/index.html", "README", "History.txt", "README", "History.txt", "README"]
32
+ Churn.should_receive(:get_logs).with(:svn, "").and_return(logs)
33
+ changes = Churn.send(:parse_log_for_changes, :svn, "")
34
+
35
+ changes["home_page/index.html"].should == 1
36
+ changes["History.txt"].should == 2
37
+ changes["README"].should == 3
38
+ end
39
+ end
40
+
41
+ describe "clean_up_svn_line" do
42
+ it "should return nil for non matches" do
43
+ Churn.send(:clean_up_svn_line, "Adding Google analytics").should be_nil
44
+ Churn.send(:clean_up_svn_line, "A bunch of new files").should be_nil
45
+ end
46
+
47
+ it "should strip out all but the full path" do
48
+ Churn.send(:clean_up_svn_line, " A /trunk/lib/server.rb ").should == "/trunk/lib/server.rb"
49
+ Churn.send(:clean_up_svn_line, "A /trunk/lib/server.rb ").should == "/trunk/lib/server.rb"
50
+ Churn.send(:clean_up_svn_line, " A /trunk/lib/server.rb ").should == "/trunk/lib/server.rb"
51
+ Churn.send(:clean_up_svn_line, " A /trunk/lib/server.rb").should == "/trunk/lib/server.rb"
52
+ Churn.send(:clean_up_svn_line, "A /trunk/lib/server.rb").should == "/trunk/lib/server.rb"
53
+ Churn.send(:clean_up_svn_line, "A /trunk/lib/server.rb").should == "/trunk/lib/server.rb"
54
+
55
+ Churn.send(:clean_up_svn_line, " M /trunk/lib/server.rb ").should == "/trunk/lib/server.rb"
56
+ Churn.send(:clean_up_svn_line, "M /trunk/lib/server.rb ").should == "/trunk/lib/server.rb"
57
+ Churn.send(:clean_up_svn_line, " M /trunk/lib/server.rb ").should == "/trunk/lib/server.rb"
58
+ Churn.send(:clean_up_svn_line, " M /trunk/lib/server.rb").should == "/trunk/lib/server.rb"
59
+ Churn.send(:clean_up_svn_line, "M /trunk/lib/server.rb").should == "/trunk/lib/server.rb"
60
+ Churn.send(:clean_up_svn_line, "M /trunk/lib/server.rb").should == "/trunk/lib/server.rb"
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,69 @@
1
+ require 'spec'
2
+ require File.dirname(__FILE__) + '/../../lib/metric_fu'
3
+ include MetricFu::FlogReporter
4
+
5
+ describe "FlogReporter::Base" do
6
+ before do
7
+ @alpha_only_method = <<-AOM
8
+ Total flog = 13.6283678106927
9
+
10
+ ErrorMailer#errormail: (12.5)
11
+ 12.0: assignment
12
+ 1.2: []
13
+ 1.2: now
14
+ 1.2: content_type
15
+ AOM
16
+
17
+ @method_that_has_digits = <<-MTHD
18
+ Total flog = 7.08378429936994
19
+
20
+ NoImmunizationReason#to_c32: (7.1)
21
+ 3.0: code
22
+ 2.3: branch
23
+ 1.4: templateId
24
+ 1.2: act
25
+ 1.1: entryRelationship
26
+ MTHD
27
+
28
+ @bang_method = <<-BM
29
+ Total flog = 7.08378429936994
30
+
31
+ NoImmunizationReason#to_c32!: (7.1)
32
+ 3.0: code
33
+ 2.3: branch
34
+ 1.4: templateId
35
+ 1.2: act
36
+ 1.1: entryRelationship
37
+ BM
38
+ end
39
+
40
+ it "should be able to parse an alpha only method" do
41
+ page = Base.parse(@alpha_only_method)
42
+ page.should_not be_nil
43
+ page.score.should == 13.6283678106927
44
+ page.scanned_methods.size.should == 1
45
+ sm = page.scanned_methods.first
46
+ sm.name.should == 'ErrorMailer#errormail'
47
+ sm.score.should == 12.5
48
+ end
49
+
50
+ it "should be able to parse method that has digits" do
51
+ page = Base.parse(@method_that_has_digits)
52
+ page.should_not be_nil
53
+ page.score.should == 7.08378429936994
54
+ page.scanned_methods.size.should == 1
55
+ sm = page.scanned_methods.first
56
+ sm.name.should == 'NoImmunizationReason#to_c32'
57
+ sm.score.should == 7.1
58
+ end
59
+
60
+ it "should be able to parse bang method" do
61
+ page = Base.parse(@bang_method)
62
+ page.should_not be_nil
63
+ page.score.should == 7.08378429936994
64
+ page.scanned_methods.size.should == 1
65
+ sm = page.scanned_methods.first
66
+ sm.name.should == 'NoImmunizationReason#to_c32!'
67
+ sm.score.should == 7.1
68
+ end
69
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec'
2
+ require File.join(File.dirname(__FILE__), '../lib/metric_fu/md5_tracker')
3
+ include MetricFu
4
+
5
+ describe MetricFu::MD5Tracker do
6
+ before do
7
+ @tmp_dir = File.join(File.dirname(__FILE__), 'tmp')
8
+ FileUtils.mkdir_p(@tmp_dir, :verbose => false) unless File.directory?(@tmp_dir)
9
+ @file1 = File.new(File.join(@tmp_dir, 'file1.txt'), 'w')
10
+ @file2 = File.new(File.join(@tmp_dir, 'file2.txt'), 'w')
11
+ end
12
+
13
+ after do
14
+ FileUtils.rm_rf(@tmp_dir, :verbose => false)
15
+ end
16
+
17
+ it "identical files should match" do
18
+ @file1.puts("Hello World")
19
+ @file1.close
20
+ file1_md5 = MD5Tracker.track(@file1.path, @tmp_dir)
21
+
22
+ @file2.puts("Hello World")
23
+ @file2.close
24
+ file2_md5 = MD5Tracker.track(@file2.path, @tmp_dir)
25
+
26
+ file2_md5.should == file1_md5
27
+ end
28
+
29
+ it "different files should not match" do
30
+ @file1.puts("Hello World")
31
+ @file1.close
32
+ file1_md5 = MD5Tracker.track(@file1.path, @tmp_dir)
33
+
34
+ @file2.puts("Goodbye World")
35
+ @file2.close
36
+ file2_md5 = MD5Tracker.track(@file2.path, @tmp_dir)
37
+
38
+ file2_md5.should_not == file1_md5
39
+ end
40
+
41
+ it "file_changed? should detect a change" do
42
+ @file2.close
43
+
44
+ @file1.puts("Hello World")
45
+ @file1.close
46
+ file1_md5 = MD5Tracker.track(@file1.path, @tmp_dir)
47
+
48
+ @file1 = File.new(File.join(@tmp_dir, 'file1.txt'), 'w')
49
+ @file1.puts("Goodbye World")
50
+ @file1.close
51
+ MD5Tracker.file_changed?(@file1.path, @tmp_dir).should be_true
52
+ end
53
+
54
+ it "should detect a new file" do
55
+ @file2.close
56
+ MD5Tracker.file_changed?(@file1.path, @tmp_dir).should be_true
57
+ File.exist?(MD5Tracker.md5_file(@file1.path, @tmp_dir)).should be_true
58
+ end
59
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: indirect-metric_fu
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.1
5
+ platform: ruby
6
+ authors:
7
+ - Jake Scruggs
8
+ - Sean Soper
9
+ - Andre Arko
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2008-10-27 00:00:00 -07:00
15
+ default_executable:
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: flog
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 1.2.0
25
+ version:
26
+ - !ruby/object:Gem::Dependency
27
+ name: rcov
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.8.1
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: flay
37
+ version_requirement:
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">"
41
+ - !ruby/object:Gem::Version
42
+ version: 0.0.0
43
+ version:
44
+ description: Code metrics from Flog, RCov, Saikuro, Churn, and Rails' stats task
45
+ email: jake.scruggs@gmail.com
46
+ executables: []
47
+
48
+ extensions: []
49
+
50
+ extra_rdoc_files:
51
+ - HISTORY
52
+ - README
53
+ files:
54
+ - README
55
+ - HISTORY
56
+ - TODO
57
+ - MIT-LICENSE
58
+ - Rakefile
59
+ - lib/metric_fu/churn.rb
60
+ - lib/metric_fu/flay.rb
61
+ - lib/metric_fu/flog_reporter/base.rb
62
+ - lib/metric_fu/flog_reporter/generator.rb
63
+ - lib/metric_fu/flog_reporter/operator.rb
64
+ - lib/metric_fu/flog_reporter/page.rb
65
+ - lib/metric_fu/flog_reporter/scanned_method.rb
66
+ - lib/metric_fu/flog_reporter.rb
67
+ - lib/metric_fu/md5_tracker.rb
68
+ - lib/metric_fu/saikuro/saikuro.rb
69
+ - lib/metric_fu.rb
70
+ - lib/tasks/metric_fu.rb
71
+ - lib/tasks/churn.rake
72
+ - lib/tasks/coverage.rake
73
+ - lib/tasks/flog.rake
74
+ - lib/tasks/metric_fu.rake
75
+ - lib/tasks/saikuro.rake
76
+ - lib/tasks/stats.rake
77
+ has_rdoc: true
78
+ homepage: http://metric-fu.rubyforge.org/
79
+ post_install_message:
80
+ rdoc_options:
81
+ - --main
82
+ - README
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: "0"
90
+ version:
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: "0"
96
+ version:
97
+ requirements: []
98
+
99
+ rubyforge_project:
100
+ rubygems_version: 1.2.0
101
+ signing_key:
102
+ specification_version: 2
103
+ summary: A fistful of code metrics
104
+ test_files:
105
+ - spec/churn_spec.rb
106
+ - spec/flog_reporter/base_spec.rb
107
+ - spec/md5_tracker_spec.rb