p8-metric_fu 0.8.4 → 0.8.4.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/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