indirect-metric_fu 0.8.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.
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