1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/railties/lib/rails/code_statistics.rb
George Claghorn 6e0eb9235a Make code statistics rake task handle new test locations properly
As of 2a68f68aea:

- Unit tests are now in test/models, instead of test/units
- Functional tests are now in test/controllers, instead of
  test/functional
- Helper tests are now in test/helpers, instead of test/units/helpers
- Mailer tests are now in test/mailers, instead of test/functional

Update the rake task for code statistics (`rake stats`) so that it
recognizes files in the above locations as tests, and accurately
calculates statistics such as "Test LOC" and "Code to Test Ratio."
Safely handle Rails apps that still have tests in the old locations.
2012-12-09 00:04:36 -05:00

127 lines
3.7 KiB
Ruby

class CodeStatistics #:nodoc:
TEST_TYPES = ['Controller tests',
'Helper tests',
'Model tests',
'Mailer tests',
'Integration tests',
'Functional tests (old)',
'Unit tests (old)']
def initialize(*pairs)
@pairs = pairs
@statistics = calculate_statistics
@total = calculate_total if pairs.length > 1
end
def to_s
print_header
@pairs.each { |pair| print_line(pair.first, @statistics[pair.first]) }
print_splitter
if @total
print_line("Total", @total)
print_splitter
end
print_code_test_stats
end
private
def calculate_statistics
Hash[@pairs.map{|pair| [pair.first, calculate_directory_statistics(pair.last)]}]
end
def calculate_directory_statistics(directory, pattern = /.*\.(rb|js|coffee)$/)
stats = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 }
Dir.foreach(directory) do |file_name|
if File.directory?(directory + "/" + file_name) and (/^\./ !~ file_name)
newstats = calculate_directory_statistics(directory + "/" + file_name, pattern)
stats.each { |k, v| stats[k] += newstats[k] }
end
next unless file_name =~ pattern
comment_started = false
case file_name
when /.*\.js$/
comment_pattern = /^\s*\/\//
else
comment_pattern = /^\s*#/
end
File.open(directory + "/" + file_name) do |f|
while line = f.gets
stats["lines"] += 1
if(comment_started)
if line =~ /^=end/
comment_started = false
end
next
else
if line =~ /^=begin/
comment_started = true
next
end
end
stats["classes"] += 1 if line =~ /^\s*class\s+[_A-Z]/
stats["methods"] += 1 if line =~ /^\s*def\s+[_a-z]/
stats["codelines"] += 1 unless line =~ /^\s*$/ || line =~ comment_pattern
end
end
end
stats
end
def calculate_total
total = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 }
@statistics.each_value { |pair| pair.each { |k, v| total[k] += v } }
total
end
def calculate_code
code_loc = 0
@statistics.each { |k, v| code_loc += v['codelines'] unless TEST_TYPES.include? k }
code_loc
end
def calculate_tests
test_loc = 0
@statistics.each { |k, v| test_loc += v['codelines'] if TEST_TYPES.include? k }
test_loc
end
def print_header
print_splitter
puts "| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |"
print_splitter
end
def print_splitter
puts "+----------------------+-------+-------+---------+---------+-----+-------+"
end
def print_line(name, statistics)
m_over_c = (statistics["methods"] / statistics["classes"]) rescue m_over_c = 0
loc_over_m = (statistics["codelines"] / statistics["methods"]) - 2 rescue loc_over_m = 0
puts "| #{name.ljust(20)} " +
"| #{statistics["lines"].to_s.rjust(5)} " +
"| #{statistics["codelines"].to_s.rjust(5)} " +
"| #{statistics["classes"].to_s.rjust(7)} " +
"| #{statistics["methods"].to_s.rjust(7)} " +
"| #{m_over_c.to_s.rjust(3)} " +
"| #{loc_over_m.to_s.rjust(5)} |"
end
def print_code_test_stats
code = calculate_code
tests = calculate_tests
puts " Code LOC: #{code} Test LOC: #{tests} Code to Test Ratio: 1:#{sprintf("%.1f", tests.to_f/code)}"
puts ""
end
end