p8-metric_fu 0.8.4 → 0.8.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt ADDED
@@ -0,0 +1,28 @@
1
+ History.txt
2
+ Manifest.txt
3
+ metric_fu-0.7.gem
4
+ metric_fu.gemspec
5
+ MIT-LICENSE
6
+ Rakefile
7
+ README
8
+ TODO.txt
9
+ lib/metric_fu.rb
10
+ lib/metric_fu/flog_reporter.rb
11
+ lib/metric_fu/md5_tracker.rb
12
+ lib/metric_fu/flog_reporter/base.rb
13
+ lib/metric_fu/flog_reporter/flog_reporter.css
14
+ lib/metric_fu/flog_reporter/generator.rb
15
+ lib/metric_fu/flog_reporter/operator.rb
16
+ lib/metric_fu/flog_reporter/page.rb
17
+ lib/metric_fu/flog_reporter/scanned_method.rb
18
+ lib/metric_fu/saikuro/saikuro.rb
19
+ lib/metric_fu/saikuro/SAIKURO_README
20
+ lib/tasks/churn.rake
21
+ lib/tasks/coverage.rake
22
+ lib/tasks/flog.rake
23
+ lib/tasks/metric_fu.rake
24
+ lib/tasks/metric_fu.rb
25
+ lib/tasks/saikuro.rake
26
+ lib/tasks/stats.rake
27
+ test/test_helper.rb
28
+ test/test_md5_tracker.rb
@@ -1,3 +1,4 @@
1
+ require 'erb'
1
2
  module MetricFu
2
3
 
3
4
  TEMPLATE_DIR = File.join(File.dirname(__FILE__), '..', 'templates')
@@ -11,12 +12,17 @@ module MetricFu
11
12
  end
12
13
 
13
14
  module Base
15
+
16
+ ######################################################################
17
+ # Base class for report Generators
18
+ #
14
19
  class Generator
15
20
 
16
21
  def initialize(base_dir, options={})
17
22
  @base_dir = base_dir
18
23
  end
19
24
 
25
+ # generates a report for base_dir
20
26
  def self.generate_report(base_dir, options={})
21
27
  FileUtils.mkdir_p(base_dir, :verbose => false) unless File.directory?(base_dir)
22
28
  self.new(base_dir, options).generate_report
@@ -36,11 +42,22 @@ module MetricFu
36
42
  analyze
37
43
  html = ERB.new(File.read(template_file)).result(binding)
38
44
  end
45
+
46
+ def template_name
47
+ self.class.to_s.split('::').last.downcase
48
+ end
39
49
 
40
50
  def template_file
41
51
  File.join(MetricFu::TEMPLATE_DIR, "#{template_name}.html.erb")
42
52
  end
43
-
53
+
54
+ ########################
55
+ # Template methods
56
+
57
+ def inline_css(css)
58
+ open(File.join(MetricFu::TEMPLATE_DIR, css)) { |f| f.read }
59
+ end
60
+
44
61
  def link_to_filename(name, line = nil)
45
62
  filename = File.expand_path(name)
46
63
  if PLATFORM['darwin']
@@ -49,6 +66,11 @@ module MetricFu
49
66
  %{<a href="file://#{filename}">#{name}</a>}
50
67
  end
51
68
  end
69
+
70
+ def cycle(first_value, second_value, iteration)
71
+ return first_value if iteration % 2 == 0
72
+ return second_value
73
+ end
52
74
  end
53
75
  end
54
76
  end
@@ -1,4 +1,11 @@
1
+ CHURN_DIR = File.join(MetricFu::BASE_DIRECTORY, 'churn')
2
+
1
3
  module MetricFu
4
+
5
+ def generate_churn_report
6
+ MetricFu::Churn.generate_report(CHURN_DIR, defined?(MetricFu::CHURN_OPTIONS) ? MetricFu::CHURN_OPTIONS : {} )
7
+ end
8
+
2
9
  class Churn < Base::Generator
3
10
 
4
11
  def initialize(base_dir, options={})
@@ -18,11 +25,6 @@ module MetricFu
18
25
  @changes = parse_log_for_changes.reject! {|file, change_count| change_count < @minimum_churn_count}
19
26
  end
20
27
 
21
- # should be dynamically read from the class
22
- def template_name
23
- 'churn'
24
- end
25
-
26
28
  private
27
29
 
28
30
  def parse_log_for_changes
@@ -1,7 +1,12 @@
1
- require 'erb'
1
+ FLAY_DIR = File.join(MetricFu::BASE_DIRECTORY, 'flay')
2
2
 
3
3
  module MetricFu
4
- class FlayReporter < Base::Generator
4
+
5
+ def generate_flay_report
6
+ MetricFu::Flay.generate_report(FLAY_DIR)
7
+ end
8
+
9
+ class Flay < Base::Generator
5
10
 
6
11
  def analyze
7
12
  files_to_flay = MetricFu::CODE_DIRS.map{|dir| Dir[File.join(dir, "**/*.rb")] }
@@ -9,9 +14,5 @@ module MetricFu
9
14
  @matches = output.chomp.split("\n\n").map{|m| m.split("\n ") }
10
15
  end
11
16
 
12
- def template_name
13
- 'flay'
14
- end
15
-
16
17
  end
17
18
  end
@@ -0,0 +1,139 @@
1
+ FLOG_DIR = File.join(MetricFu::BASE_DIRECTORY, 'flog')
2
+
3
+ module MetricFu
4
+
5
+ def generate_flog_report
6
+ MetricFu::Flog::Generator.generate_report(FLOG_DIR)
7
+ end
8
+
9
+ module Flog
10
+ class Generator < Base::Generator
11
+ def generate_report
12
+ pages = []
13
+ flog_results.each do |filename|
14
+ page = Base.parse(open(filename, "r") { |f| f.read })
15
+ if page
16
+ page.filename = filename
17
+ pages << page
18
+ end
19
+ end
20
+ generate_pages(pages)
21
+ end
22
+
23
+ def generate_pages(pages)
24
+ pages.each do |page|
25
+ unless MetricFu::MD5Tracker.file_already_counted?(page.filename)
26
+ generate_page(page)
27
+ end
28
+ end
29
+ save_html(ERB.new(File.read(template_file)).result(binding))
30
+ end
31
+
32
+ def generate_page(page)
33
+ save_html(page.to_html, page.path)
34
+ end
35
+
36
+ def flog_results
37
+ Dir.glob("#{@base_dir}/**/*.txt")
38
+ end
39
+
40
+ def template_name
41
+ "flog"
42
+ end
43
+ end
44
+
45
+ SCORE_FORMAT = "%0.2f"
46
+
47
+ class Base
48
+ MODULE_NAME = "([A-Za-z]+)+"
49
+ METHOD_NAME = "#([a-z0-9]+_?)+\\??\\!?"
50
+ SCORE = "\\d+\\.\\d+"
51
+
52
+ METHOD_NAME_RE = Regexp.new("#{MODULE_NAME}#{METHOD_NAME}")
53
+ SCORE_RE = Regexp.new(SCORE)
54
+
55
+ METHOD_LINE_RE = Regexp.new("#{MODULE_NAME}#{METHOD_NAME}:\\s\\(#{SCORE}\\)")
56
+ OPERATOR_LINE_RE = Regexp.new("\\s+(#{SCORE}):\\s(.*)$")
57
+
58
+ class << self
59
+
60
+ def parse(text)
61
+ score = text[/\w+ = (\d+\.\d+)/, 1]
62
+ return nil unless score
63
+ page = Page.new(score)
64
+
65
+ text.each_line do |method_line|
66
+ if METHOD_LINE_RE =~ method_line and
67
+ method_name = method_line[METHOD_NAME_RE] and
68
+ score = method_line[SCORE_RE]
69
+ page.scanned_methods << ScannedMethod.new(method_name, score)
70
+ end
71
+
72
+ if OPERATOR_LINE_RE =~ method_line and
73
+ operator = method_line[OPERATOR_LINE_RE, 2] and
74
+ score = method_line[SCORE_RE]
75
+ return if page.scanned_methods.empty?
76
+ page.scanned_methods.last.operators << Operator.new(score, operator)
77
+ end
78
+ end
79
+ page
80
+ end
81
+ end
82
+ end
83
+
84
+ class Page < MetricFu::Base::Generator
85
+ attr_accessor :filename, :score, :scanned_methods
86
+
87
+ def initialize(score, scanned_methods = [])
88
+ @score = score.to_f
89
+ @scanned_methods = scanned_methods
90
+ end
91
+
92
+ def path
93
+ File.basename(filename, ".txt") + '.html'
94
+ end
95
+
96
+ def to_html
97
+ ERB.new(File.read(template_file)).result(binding)
98
+ end
99
+
100
+ def average_score
101
+ return 0 if scanned_methods.length == 0
102
+ sum = 0
103
+ scanned_methods.each do |m|
104
+ sum += m.score
105
+ end
106
+ sum / scanned_methods.length
107
+ end
108
+
109
+ def highest_score
110
+ scanned_methods.inject(0) do |highest, m|
111
+ m.score > highest ? m.score : highest
112
+ end
113
+ end
114
+
115
+ def template_name
116
+ 'flog_page'
117
+ end
118
+ end
119
+
120
+ class Operator
121
+ attr_accessor :score, :operator
122
+
123
+ def initialize(score, operator)
124
+ @score = score.to_f
125
+ @operator = operator
126
+ end
127
+ end
128
+
129
+ class ScannedMethod
130
+ attr_accessor :name, :score, :operators
131
+
132
+ def initialize(name, score, operators = [])
133
+ @name = name
134
+ @score = score.to_f
135
+ @operators = operators
136
+ end
137
+ end
138
+ end
139
+ end
data/lib/tasks/churn.rake CHANGED
@@ -4,8 +4,7 @@ namespace :metrics do
4
4
 
5
5
  desc "Which files change the most"
6
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']
7
+ MetricFu.generate_churn_report
8
+ system("open #{CHURN_DIR}/index.html") if PLATFORM['darwin']
10
9
  end
11
10
  end
@@ -23,6 +23,8 @@ begin
23
23
  t.test_files = FileList['test/**/*_test.rb', 'spec/**/*_spec.rb']
24
24
  t.rcov_opts = ["--sort coverage", "--html", "--rails", "--exclude /gems/,/Library/"]
25
25
  t.output_dir = COVERAGE_DIR
26
+ # this line is a fix for Rails 2.1 relative loading issues
27
+ t.libs << 'test'
26
28
  end
27
29
  # TODO not sure what this improves but it requires the diff-lcs gem
28
30
  # http://github.com/indirect/metric_fu/commit/b9c1cf75f09d5b531b388cd01661eb16b5126968#diff-1
data/lib/tasks/flay.rake CHANGED
@@ -1,9 +1,7 @@
1
- FLAY_DIR = File.join(MetricFu::BASE_DIRECTORY, 'flay')
2
-
3
1
  namespace :metrics do
4
2
  desc "Generate code duplication report with flay"
5
3
  task :flay do
6
- MetricFu::FlayReporter.generate_report(FLAY_DIR)
4
+ MetricFu.generate_flay_report
7
5
  system("open #{FLAY_DIR}/index.html") if PLATFORM['darwin']
8
6
  end
9
7
  end
data/lib/tasks/flog.rake CHANGED
@@ -1,5 +1,4 @@
1
1
  begin
2
- FLOG_DIR = File.join(MetricFu::BASE_DIRECTORY, 'flog')
3
2
 
4
3
  def flog(output, directory)
5
4
  Dir.glob("#{directory}/**/*.rb").each do |filename|
@@ -41,18 +40,19 @@ begin
41
40
  desc "Generate a flog report from specified directories"
42
41
  task :custom do
43
42
  MetricFu::CODE_DIRS.each { |directory| flog(directory, directory) }
44
- MetricFu::FlogReporter::Generator.generate_report(FLOG_DIR)
43
+ MetricFu.generate_flog_report
44
+ system("open #{FLOG_DIR}/index.html") if PLATFORM['darwin']
45
45
  end
46
46
 
47
47
  desc "Generate and open flog report"
48
48
  if MetricFu::RAILS
49
49
  task :all => [:models, :controllers, :helpers, :lib] do
50
- MetricFu::FlogReporter::Generator.generate_report(FLOG_DIR)
50
+ MetricFu.generate_flog_report
51
51
  system("open #{FLOG_DIR}/index.html") if PLATFORM['darwin']
52
52
  end
53
53
  else
54
54
  task :all => [:custom] do
55
- MetricFu::FlogReporter::Generator.generate_report(FLOG_DIR)
55
+ MetricFu.generate_flog_report
56
56
  system("open #{FLOG_DIR}/index.html") if PLATFORM['darwin']
57
57
  end
58
58
  end
@@ -1,8 +1,8 @@
1
1
  namespace :metrics do
2
2
  if MetricFu::RAILS
3
3
 
4
- desc "Generate coverage, cyclomatic complexity, flog, stats, duplication and churn reports"
5
- task :all => [:coverage, :stats, :saikuro, :churn, :flog, :flay]
4
+ desc "Generate coverage, cyclomatic complexity, flog, flay, railroad, reek, roodi, stats and churn reports"
5
+ task :all => [:coverage, :stats, :saikuro, :churn, :flog, :flay, :railroad, :reek, :roodi]
6
6
 
7
7
  task :set_testing_env do
8
8
  RAILS_ENV = 'test'
@@ -13,8 +13,9 @@ namespace :metrics do
13
13
 
14
14
  else
15
15
 
16
- desc "Generate coverage, cyclomatic complexity, flog, duplication and churn reports"
17
- task :all => [:coverage, :saikuro, :churn, :flog, :flay]
16
+ desc "Generate coverage, cyclomatic complexity, flog, flay, railroad, reek, roodi and churn reports"
17
+ task :all => [:coverage, :saikuro, :churn, :flog, :flay, :railroad, :reek, :roodi]
18
18
 
19
19
  end
20
+
20
21
  end
@@ -0,0 +1,36 @@
1
+ namespace :metrics do
2
+
3
+ RAILROAD_DIR = File.join(MetricFu::BASE_DIRECTORY, 'railroad')
4
+ RAILROAD_INDEX = 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(RAILROAD_DIR,'models.png')}`
20
+ end
21
+
22
+ desc "Create a railroad controllers report"
23
+ task :controllers do
24
+ mkdir_p(RAILROAD_DIR) unless File.directory?(RAILROAD_DIR)
25
+ `railroad -C -l -v | neato -Tpng > #{File.join(RAILROAD_DIR,'controllers.png')}`
26
+ end
27
+
28
+ desc "Create a railroad acts_as_state_machine report"
29
+ task :aasm do
30
+ mkdir_p(RAILROAD_DIR) unless File.directory?(RAILROAD_DIR)
31
+ `railroad -A -l -v | neato -Tpng > #{File.join(RAILROAD_DIR,'aasm.png')}`
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,14 @@
1
+ namespace :metrics do
2
+
3
+ REEK_DIR = File.join(MetricFu::BASE_DIRECTORY, 'reek')
4
+ REEK_FILE = File.join(REEK_DIR, 'index.html')
5
+
6
+ desc "A code smell report using Reek"
7
+ task :reek do
8
+ mkdir_p(REEK_DIR) unless File.directory?(REEK_DIR)
9
+ `echo '<pre>' > #{REEK_FILE}`
10
+ `reek #{RAILS_ROOT}/test/**/*.rb #{RAILS_ROOT}/app/**/*.rb >> #{REEK_FILE}`
11
+ `echo '</pre>' >> #{REEK_FILE}`
12
+ system("open #{REEK_FILE}") if PLATFORM['darwin']
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ namespace :metrics do
2
+
3
+ ROODI_DIR = File.join(MetricFu::BASE_DIRECTORY, 'roodi')
4
+ ROODI_FILE = File.join(ROODI_DIR, 'index.html')
5
+
6
+ desc "A Ruby coding standards report using Roodi"
7
+ task :roodi do
8
+ mkdir_p(ROODI_DIR) unless File.directory?(ROODI_DIR)
9
+ `echo '<pre>' > #{ROODI_FILE}`
10
+ `roodi #{RAILS_ROOT}/lib/**/*.rb #{RAILS_ROOT}/app/**/*.rb >> #{ROODI_FILE}`
11
+ `echo '</pre>' >> #{ROODI_FILE}`
12
+ system("open #{ROODI_FILE}") if PLATFORM['darwin']
13
+ end
14
+ end
@@ -2,7 +2,7 @@
2
2
  <head>
3
3
  <title>Source Control Churn Results</title>
4
4
  <style>
5
- <%= open(File.join(MetricFu::TEMPLATE_DIR, "#{template_name}.css")) { |f| f.read } %>
5
+ <%= inline_css("#{template_name}.css") %>
6
6
  </style>
7
7
  </head>
8
8
 
@@ -2,7 +2,7 @@
2
2
  <head>
3
3
  <title>Flay Results</title>
4
4
  <style>
5
- <%= open(File.join(MetricFu::TEMPLATE_DIR, "#{template_name}.css")) { |f| f.read } %>
5
+ <%= inline_css("#{template_name}.css") %>
6
6
  </style>
7
7
  </head>
8
8
 
@@ -2,7 +2,7 @@
2
2
  <head>
3
3
  <title>Flog Reporter</title>
4
4
  <style>
5
- <%= open(File.join(MetricFu::TEMPLATE_DIR, "#{template_name}.css")) { |f| f.read } %>
5
+ <%= inline_css("#{template_name}.css") %>
6
6
  </style>
7
7
  </head>
8
8
  <body>
@@ -10,16 +10,14 @@
10
10
  <p>Generated on <%= Time.now.localtime %> with <a href='http://ruby.sadi.st/Flog.html'>flog</a></p>
11
11
  <table class='report'>
12
12
  <tr><th>File</th><th>Total score</th><th>Methods</th><th>Average score</th><th>Highest score</th></tr>
13
- <% count = 0 %>
14
- <% flog_hashes.sort {|x,y| y[:page].highest_score <=> x[:page].highest_score }.each do |flog_hash| %>
15
- <tr class='<%= Base.cycle("light", "dark", count) %>'>
16
- <td><a href='<%= flog_hash[:path]%>'><%= flog_hash[:path].sub('.html', '.rb') %></a></td>
17
- <td class='score'><%= sprintf(SCORE_FORMAT, flog_hash[:page].score) %></td>
18
- <td class='score'><%= flog_hash[:page].scanned_methods.length %></td>
19
- <td class='score'><%= sprintf(SCORE_FORMAT, flog_hash[:page].average_score) %></td>
20
- <td class='score'><%= sprintf(SCORE_FORMAT, flog_hash[:page].highest_score) %></td>
13
+ <% pages.sort {|x,y| y.highest_score <=> x.highest_score }.each_with_index do |page, count| %>
14
+ <tr class='<%= cycle("light", "dark", count) %>'>
15
+ <td><a href='<%= page.path %>'><%= page.path.sub('.html', '.rb') %></a></td>
16
+ <td class='score'><%= sprintf(SCORE_FORMAT, page.score) %></td>
17
+ <td class='score'><%= page.scanned_methods.length %></td>
18
+ <td class='score'><%= sprintf(SCORE_FORMAT, page.average_score) %></td>
19
+ <td class='score'><%= sprintf(SCORE_FORMAT, page.highest_score) %></td>
21
20
  </tr>
22
- <% count += 1 %>
23
21
  <% end %>
24
22
  </table>
25
23
  </body>
@@ -1,13 +1,22 @@
1
1
  <html>
2
2
  <head>
3
3
  <style>
4
- <%= open(File.join(MetricFu::TEMPLATE_DIR, "flog.css")) { |f| f.read } %>
4
+ <%= inline_css("flog.css") %>
5
5
  </style>
6
6
  </head>
7
7
  <body>
8
8
  <p>Score: <%= score %></p>
9
9
  <% scanned_methods.each do |sm| %>
10
- <%= sm.to_html %>
11
- <% end %>
10
+ <p><strong><%= sm.name %> (<%= sm.score %>)</strong></p>
11
+ <table>
12
+ <tr><th>Score</th><th>Operator</th></tr>
13
+ <% sm.operators.each_with_index do |operator, count| %>
14
+ <tr class='<%= cycle("light", "dark", count) %>'>
15
+ <td class='score'><%= sprintf(SCORE_FORMAT, operator.score) %></td>
16
+ <td class='score'><%= operator.operator %></td>
17
+ </tr>
18
+ <% end %>
19
+ </table>
20
+ <% end %>
12
21
  </body>
13
22
  </html>
data/spec/base_spec.rb CHANGED
@@ -32,4 +32,19 @@ describe MetricFu::Base::Generator do
32
32
  @generator.generate_report
33
33
  end
34
34
  end
35
+
36
+ describe "cycle" do
37
+ it "should create a new Generator and call generate_report on it" do
38
+ @generator = MetricFu::Base::Generator.new('other_dir')
39
+ @generator.cycle("light", "dark", 0).should == 'light'
40
+ @generator.cycle("light", "dark", 1).should == 'dark'
41
+ end
42
+ end
43
+
44
+ describe "template_name" do
45
+ it "should return the class name in lowercase" do
46
+ @generator = MetricFu::Base::Generator.new('other_dir')
47
+ @generator.template_name.should == 'generator'
48
+ end
49
+ end
35
50
  end
data/spec/churn_spec.rb CHANGED
@@ -22,6 +22,13 @@ describe MetricFu::Churn do
22
22
  end
23
23
 
24
24
  end
25
+
26
+ describe "template_name" do
27
+ it "should return the class name in lowercase" do
28
+ churn = Churn.new('base_dir')
29
+ churn.template_name.should == 'churn'
30
+ end
31
+ end
25
32
 
26
33
  describe "parse_log_for_changes" do
27
34
  it "should count the changes with git" do
@@ -1,12 +1,19 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper.rb'
2
2
 
3
- describe MetricFu::FlayReporter do
3
+ describe MetricFu::Flay do
4
4
 
5
5
  describe "generate_html" do
6
6
  it "should create a new Generator and call generate_report on it" do
7
- @generator = MetricFu::FlayReporter.new('other_dir')
7
+ @generator = MetricFu::Flay.new('other_dir')
8
8
  @generator.should_receive(:`).and_return("Matches found in :call (mass = 55)\n\tlib/metric_fu/flog_reporter.rb:2\n\tlib/metric_fu/flog_reporter.rb:3")
9
9
  @generator.generate_html
10
10
  end
11
11
  end
12
+
13
+ describe "template_name" do
14
+ it "should return the class name in lowercase" do
15
+ flay = MetricFu::Flay.new('base_dir')
16
+ flay.template_name.should == 'flay'
17
+ end
18
+ end
12
19
  end
data/spec/flog_spec.rb ADDED
@@ -0,0 +1,147 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ include MetricFu::Flog
3
+
4
+ describe "Flog::Base" do
5
+ before do
6
+ @alpha_only_method = <<-AOM
7
+ Total flog = 13.6283678106927
8
+
9
+ ErrorMailer#errormail: (12.5)
10
+ 12.0: assignment
11
+ 1.2: []
12
+ 1.2: now
13
+ 1.2: content_type
14
+ AOM
15
+
16
+ @method_that_has_digits = <<-MTHD
17
+ Total flog = 7.08378429936994
18
+
19
+ NoImmunizationReason#to_c32: (7.1)
20
+ 3.0: code
21
+ 2.3: branch
22
+ 1.4: templateId
23
+ 1.2: act
24
+ 1.1: entryRelationship
25
+ MTHD
26
+
27
+ @bang_method = <<-BM
28
+ Total flog = 7.08378429936994
29
+
30
+ NoImmunizationReason#to_c32!: (7.1)
31
+ 3.0: code
32
+ 2.3: branch
33
+ 1.4: templateId
34
+ 1.2: act
35
+ 1.1: entryRelationship
36
+ BM
37
+
38
+ @invalid_method = <<-IM
39
+ Total flog = 7.08378429936994
40
+
41
+ 3.0: code
42
+ 2.3: branch
43
+ 1.4: templateId
44
+ 1.2: act
45
+ 1.1: entryRelationship
46
+ IM
47
+
48
+ end
49
+
50
+ it "should be able to parse an alpha only method" do
51
+ page = Base.parse(@alpha_only_method)
52
+ page.should_not be_nil
53
+ page.score.should == 13.6283678106927
54
+ page.scanned_methods.size.should == 1
55
+ sm = page.scanned_methods.first
56
+ sm.name.should == 'ErrorMailer#errormail'
57
+ sm.score.should == 12.5
58
+ end
59
+
60
+ it "should be able to parse method that has digits" do
61
+ page = Base.parse(@method_that_has_digits)
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
+
70
+ it "should be able to parse bang method" do
71
+ page = Base.parse(@bang_method)
72
+ page.should_not be_nil
73
+ page.score.should == 7.08378429936994
74
+ page.scanned_methods.size.should == 1
75
+ sm = page.scanned_methods.first
76
+ sm.name.should == 'NoImmunizationReason#to_c32!'
77
+ sm.score.should == 7.1
78
+ end
79
+
80
+ it "should return nil when parsing invalid method" do
81
+ page = Base.parse(@invalid_method)
82
+ page.should be_nil
83
+ end
84
+ end
85
+
86
+ IM = <<-IM
87
+ Total flog = 7.08378429936994
88
+
89
+ 3.0: code
90
+ 2.3: branch
91
+ 1.4: templateId
92
+ 1.2: act
93
+ 1.1: entryRelationship
94
+ IM
95
+ describe MetricFu::Flog do
96
+
97
+ describe "generate_report" do
98
+ it "should generate reports" do
99
+ generator = Flog::Generator.new('other_dir')
100
+ generator.should_receive(:flog_results).and_return(['A', 'B'])
101
+ generator.should_receive(:save_html).at_least(3).times.and_return('')
102
+ generator.should_receive(:open).any_number_of_times.and_return(['Total Flog = 1273.9 (9.3 +/- 259.2 flog / method)', 'TokenCounter#list_tokens_per_line: (15.2)', '9.0: assignment'].join("\n"))
103
+ generator.generate_report
104
+ end
105
+
106
+ it "should be able to handle InvalidFlogs" do
107
+ generator = Flog::Generator.new('other_dir')
108
+ generator.should_receive(:flog_results).and_return(['A', 'B'])
109
+ generator.should_receive(:inline_css).any_number_of_times.and_return('')
110
+ generator.should_receive(:save_html).once
111
+ generator.should_receive(:open).any_number_of_times.and_return(IM)
112
+ generator.generate_report
113
+ end
114
+ end
115
+
116
+ describe "template_name" do
117
+ it "should return the class name in lowercase" do
118
+ flog = Flog::Generator.new('base_dir')
119
+ flog.template_name.should == 'flog'
120
+ end
121
+ end
122
+ end
123
+
124
+ describe MetricFu::Flog::Page do
125
+
126
+ describe "average_score" do
127
+ it "should calculate the average score" do
128
+ page = Page.new(10)
129
+ page.should_receive(:scanned_methods).any_number_of_times.and_return([ScannedMethod.new(:test, 10), ScannedMethod.new(:test, 20)])
130
+ page.average_score.should == 15
131
+ end
132
+
133
+ it "should be able to handle divide by zero" do
134
+ page = Page.new(10)
135
+ page.should_receive(:scanned_methods).any_number_of_times.and_return([])
136
+ page.average_score.should == 0
137
+ end
138
+ end
139
+
140
+ describe "highest_score" do
141
+ it "should calculate the average score" do
142
+ page = Page.new(10)
143
+ page.should_receive(:scanned_methods).any_number_of_times.and_return([ScannedMethod.new(:test, 10), ScannedMethod.new(:test, 20)])
144
+ page.highest_score.should == 20
145
+ end
146
+ end
147
+ end
data/spec/spec_helper.rb CHANGED
@@ -3,8 +3,8 @@ require 'spec'
3
3
  require 'date'
4
4
 
5
5
  require File.join(File.dirname(__FILE__), '/../lib/metric_fu/base')
6
- require File.join(File.dirname(__FILE__), '/../lib/metric_fu/flay_reporter')
7
- require File.join(File.dirname(__FILE__), '/../lib/metric_fu/flog_reporter')
6
+ require File.join(File.dirname(__FILE__), '/../lib/metric_fu/flay')
7
+ require File.join(File.dirname(__FILE__), '/../lib/metric_fu/flog')
8
8
  require File.join(File.dirname(__FILE__), '/../lib/metric_fu/md5_tracker')
9
9
  require File.join(File.dirname(__FILE__), '/../lib/metric_fu/churn')
10
10
  include MetricFu
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: p8-metric_fu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.4
4
+ version: 0.8.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jake Scruggs
@@ -15,12 +15,30 @@ cert_chain: []
15
15
  date: 2008-12-22 00:00:00 -08:00
16
16
  default_executable:
17
17
  dependencies:
18
+ - !ruby/object:Gem::Dependency
19
+ name: factorylabs-railroad
20
+ version_requirement:
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">"
24
+ - !ruby/object:Gem::Version
25
+ version: 0.0.0
26
+ version:
27
+ - !ruby/object:Gem::Dependency
28
+ name: flay
29
+ version_requirement:
30
+ version_requirements: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">"
33
+ - !ruby/object:Gem::Version
34
+ version: 0.0.0
35
+ version:
18
36
  - !ruby/object:Gem::Dependency
19
37
  name: flog
20
38
  version_requirement:
21
39
  version_requirements: !ruby/object:Gem::Requirement
22
40
  requirements:
23
- - - ">="
41
+ - - ">"
24
42
  - !ruby/object:Gem::Version
25
43
  version: 1.2.0
26
44
  version:
@@ -29,12 +47,12 @@ dependencies:
29
47
  version_requirement:
30
48
  version_requirements: !ruby/object:Gem::Requirement
31
49
  requirements:
32
- - - ">="
50
+ - - ">"
33
51
  - !ruby/object:Gem::Version
34
52
  version: 0.8.1
35
53
  version:
36
54
  - !ruby/object:Gem::Dependency
37
- name: flay
55
+ name: reek
38
56
  version_requirement:
39
57
  version_requirements: !ruby/object:Gem::Requirement
40
58
  requirements:
@@ -43,7 +61,7 @@ dependencies:
43
61
  version: 0.0.0
44
62
  version:
45
63
  - !ruby/object:Gem::Dependency
46
- name: diff-lcs
64
+ name: roodi
47
65
  version_requirement:
48
66
  version_requirements: !ruby/object:Gem::Requirement
49
67
  requirements:
@@ -59,6 +77,7 @@ extensions: []
59
77
 
60
78
  extra_rdoc_files:
61
79
  - HISTORY
80
+ - Manifest.txt
62
81
  - README
63
82
  files:
64
83
  - README
@@ -68,13 +87,8 @@ files:
68
87
  - Rakefile
69
88
  - lib/metric_fu/base.rb
70
89
  - lib/metric_fu/churn.rb
71
- - lib/metric_fu/flay_reporter.rb
72
- - lib/metric_fu/flog_reporter/base.rb
73
- - lib/metric_fu/flog_reporter/generator.rb
74
- - lib/metric_fu/flog_reporter/operator.rb
75
- - lib/metric_fu/flog_reporter/page.rb
76
- - lib/metric_fu/flog_reporter/scanned_method.rb
77
- - lib/metric_fu/flog_reporter.rb
90
+ - lib/metric_fu/flay.rb
91
+ - lib/metric_fu/flog.rb
78
92
  - lib/metric_fu/md5_tracker.rb
79
93
  - lib/metric_fu/saikuro/saikuro.rb
80
94
  - lib/metric_fu.rb
@@ -84,6 +98,9 @@ files:
84
98
  - lib/tasks/flay.rake
85
99
  - lib/tasks/flog.rake
86
100
  - lib/tasks/metric_fu.rake
101
+ - lib/tasks/railroad.rake
102
+ - lib/tasks/reek.rake
103
+ - lib/tasks/roodi.rake
87
104
  - lib/tasks/saikuro.rake
88
105
  - lib/tasks/stats.rake
89
106
  - lib/templates/churn.css
@@ -93,6 +110,7 @@ files:
93
110
  - lib/templates/flog.css
94
111
  - lib/templates/flog.html.erb
95
112
  - lib/templates/flog_page.html.erb
113
+ - Manifest.txt
96
114
  has_rdoc: true
97
115
  homepage: http://metric-fu.rubyforge.org/
98
116
  post_install_message:
@@ -123,7 +141,7 @@ summary: A fistful of code metrics
123
141
  test_files:
124
142
  - spec/base_spec.rb
125
143
  - spec/churn_spec.rb
126
- - spec/flay_reporter_spec.rb
127
- - spec/flog_reporter/base_spec.rb
144
+ - spec/flay_spec.rb
145
+ - spec/flog_spec.rb
128
146
  - spec/md5_tracker_spec.rb
129
147
  - spec/spec_helper.rb
@@ -1,5 +0,0 @@
1
- require File.join(File.dirname(__FILE__), 'flog_reporter', 'base')
2
- require File.join(File.dirname(__FILE__), 'flog_reporter', 'page')
3
- require File.join(File.dirname(__FILE__), 'flog_reporter', 'scanned_method')
4
- require File.join(File.dirname(__FILE__), 'flog_reporter', 'operator')
5
- require File.join(File.dirname(__FILE__), 'flog_reporter', 'generator')
@@ -1,49 +0,0 @@
1
- module MetricFu::FlogReporter
2
-
3
- SCORE_FORMAT = "%0.2f"
4
-
5
- class InvalidFlog < RuntimeError
6
- end
7
-
8
- class Base
9
- MODULE_NAME = "([A-Za-z]+)+"
10
- METHOD_NAME = "#([a-z0-9]+_?)+\\??\\!?"
11
- SCORE = "\\d+\\.\\d+"
12
-
13
- METHOD_NAME_RE = Regexp.new("#{MODULE_NAME}#{METHOD_NAME}")
14
- SCORE_RE = Regexp.new(SCORE)
15
-
16
- METHOD_LINE_RE = Regexp.new("#{MODULE_NAME}#{METHOD_NAME}:\\s\\(#{SCORE}\\)")
17
- OPERATOR_LINE_RE = Regexp.new("\\s+(#{SCORE}):\\s(.*)$")
18
-
19
- class << self
20
- def cycle(first_value, second_value, iteration)
21
- return first_value if iteration % 2 == 0
22
- return second_value
23
- end
24
-
25
- def parse(text)
26
- score = text[/\w+ = (\d+\.\d+)/, 1]
27
- return nil unless score
28
- page = Page.new(score)
29
-
30
- text.each_line do |method_line|
31
- if METHOD_LINE_RE =~ method_line and
32
- method_name = method_line[METHOD_NAME_RE] and
33
- score = method_line[SCORE_RE]
34
- page.scanned_methods << ScannedMethod.new(method_name, score)
35
- end
36
-
37
- if OPERATOR_LINE_RE =~ method_line and
38
- operator = method_line[OPERATOR_LINE_RE, 2] and
39
- score = method_line[SCORE_RE]
40
- raise InvalidFlog if page.scanned_methods.empty?
41
- page.scanned_methods.last.operators << Operator.new(score, operator)
42
- end
43
- end
44
-
45
- page
46
- end
47
- end
48
- end
49
- end
@@ -1,39 +0,0 @@
1
- module MetricFu::FlogReporter
2
- class Generator < MetricFu::Base::Generator
3
- def generate_report
4
- flog_hashes = []
5
- Dir.glob("#{@base_dir}/**/*.txt").each do |filename|
6
- begin
7
- page = Base.parse(open(filename, "r") { |f| f.read })
8
- rescue InvalidFlog
9
- puts "Invalid flog for #{filename}"
10
- next
11
- end
12
-
13
- next unless page
14
-
15
- unless MetricFu::MD5Tracker.file_already_counted?(filename)
16
- generate_page(filename, page)
17
- end
18
- flog_hashes << { :path => File.basename(filename, ".txt") + '.html',
19
- :page => page }
20
- end
21
-
22
- generate_index(flog_hashes)
23
- end
24
-
25
- def generate_page(filename, page)
26
- save_html(page.to_html, File.basename(filename, ".txt"))
27
- end
28
-
29
- # should be dynamically read from the class
30
- def template_name
31
- 'flog'
32
- end
33
-
34
- def generate_index(flog_hashes)
35
- html = ERB.new(File.read(template_file)).result(binding)
36
- save_html(html)
37
- end
38
- end
39
- end
@@ -1,10 +0,0 @@
1
- module MetricFu::FlogReporter
2
- class Operator
3
- attr_accessor :score, :operator
4
-
5
- def initialize(score, operator)
6
- @score = score.to_f
7
- @operator = operator
8
- end
9
- end
10
- end
@@ -1,34 +0,0 @@
1
- module MetricFu::FlogReporter
2
- class Page < MetricFu::Base::Generator
3
- attr_accessor :score, :scanned_methods
4
-
5
- def initialize(score, scanned_methods = [])
6
- @score = score.to_f
7
- @scanned_methods = scanned_methods
8
- end
9
-
10
- def to_html
11
- ERB.new(File.read(template_file)).result(binding)
12
- end
13
-
14
- def average_score
15
- return 0 if scanned_methods.length == 0
16
- sum = 0
17
- scanned_methods.each do |m|
18
- sum += m.score
19
- end
20
- sum / scanned_methods.length
21
- end
22
-
23
- def highest_score
24
- scanned_methods.inject(0) do |highest, m|
25
- m.score > highest ? m.score : highest
26
- end
27
- end
28
-
29
- # should be dynamically read from the class
30
- def template_name
31
- 'flog_page'
32
- end
33
- end
34
- end
@@ -1,28 +0,0 @@
1
- module MetricFu::FlogReporter
2
- class ScannedMethod
3
- attr_accessor :name, :score, :operators
4
-
5
- def initialize(name, score, operators = [])
6
- @name = name
7
- @score = score.to_f
8
- @operators = operators
9
- end
10
-
11
- def to_html
12
- output = "<p><strong>#{name} (#{score})</strong></p>\n"
13
- output << "<table>\n"
14
- output << "<tr><th>Score</th><th>Operator</th></tr>\n"
15
- count = 0
16
- operators.each do |operator|
17
- output << <<-EOF
18
- <tr class='#{Base.cycle("light", "dark", count)}'>
19
- <td class='score'>#{sprintf(SCORE_FORMAT, operator.score)}</td>
20
- <td class='score'>#{operator.operator}</td>
21
- </tr>
22
- EOF
23
- count += 1
24
- end
25
- output << "</table>\n\n"
26
- end
27
- end
28
- end
@@ -1,86 +0,0 @@
1
- require File.dirname(__FILE__) + '/../spec_helper.rb'
2
- include MetricFu::FlogReporter
3
-
4
- describe "FlogReporter::Base" do
5
- before do
6
- @alpha_only_method = <<-AOM
7
- Total flog = 13.6283678106927
8
-
9
- ErrorMailer#errormail: (12.5)
10
- 12.0: assignment
11
- 1.2: []
12
- 1.2: now
13
- 1.2: content_type
14
- AOM
15
-
16
- @method_that_has_digits = <<-MTHD
17
- Total flog = 7.08378429936994
18
-
19
- NoImmunizationReason#to_c32: (7.1)
20
- 3.0: code
21
- 2.3: branch
22
- 1.4: templateId
23
- 1.2: act
24
- 1.1: entryRelationship
25
- MTHD
26
-
27
- @bang_method = <<-BM
28
- Total flog = 7.08378429936994
29
-
30
- NoImmunizationReason#to_c32!: (7.1)
31
- 3.0: code
32
- 2.3: branch
33
- 1.4: templateId
34
- 1.2: act
35
- 1.1: entryRelationship
36
- BM
37
- end
38
-
39
- it "should be able to parse an alpha only method" do
40
- page = Base.parse(@alpha_only_method)
41
- page.should_not be_nil
42
- page.score.should == 13.6283678106927
43
- page.scanned_methods.size.should == 1
44
- sm = page.scanned_methods.first
45
- sm.name.should == 'ErrorMailer#errormail'
46
- sm.score.should == 12.5
47
- end
48
-
49
- it "should be able to parse method that has digits" do
50
- page = Base.parse(@method_that_has_digits)
51
- page.should_not be_nil
52
- page.score.should == 7.08378429936994
53
- page.scanned_methods.size.should == 1
54
- sm = page.scanned_methods.first
55
- sm.name.should == 'NoImmunizationReason#to_c32'
56
- sm.score.should == 7.1
57
- end
58
-
59
- it "should be able to parse bang method" do
60
- page = Base.parse(@bang_method)
61
- page.should_not be_nil
62
- page.score.should == 7.08378429936994
63
- page.scanned_methods.size.should == 1
64
- sm = page.scanned_methods.first
65
- sm.name.should == 'NoImmunizationReason#to_c32!'
66
- sm.score.should == 7.1
67
- end
68
- end
69
-
70
-
71
- describe MetricFu::FlogReporter::Page do
72
-
73
- describe "average_score" do
74
- it "should calculate the average score" do
75
- page = MetricFu::FlayReporter::Page.new('other_dir')
76
- page.should_receive(:scanned_methods).any_number_of_times.and_return([ScannedMethod.new(:test, 10), ScannedMethod.new(:test, 20)])
77
- page.average_score.should == 15
78
- end
79
-
80
- it "should be able to handle divide by zero" do
81
- page = MetricFu::FlayReporter::Page.new('other_dir')
82
- page.should_receive(:scanned_methods).any_number_of_times.and_return([])
83
- page.average_score.should == 0
84
- end
85
- end
86
- end