Gathering Statistics About Your Code
Credit: Stefan Lang
Problem
You want to gather statistics about your Ruby project, like the total number of lines of code.
Solution
Heres a class that parses Ruby source files and gathers statistics. Put this in scriptlines.rb in your projects top-level directory.
# scriptlines.rb # A ScriptLines instance analyses a Ruby script and maintains # counters for the total number of lines, lines of code, etc. class ScriptLines attr_reader :name attr_accessor :bytes, :lines, :lines_of_code, :comment_lines LINE_FORMAT = \%8s %8s %8s %8s %s def self.headline sprintf LINE_FORMAT, "BYTES", "LINES", "LOC", "COMMENT", "FILE" end # The ame argument is usually a filename def initialize(name) @name = name @bytes = 0 @lines = 0 # total number of lines @lines_of_code = 0 @comment_lines = 0 end # Iterates over all the lines in io (io might be a file or a # string), analyses them and appropriately increases the counter # attributes. def read(io) in_multiline_comment = false io.each { |line| @lines += 1 @bytes += line.size case line when /^=begin(s|$)/ in_multiline_comment = true @comment_lines += 1 when /^=end(s|$)/: @comment_lines += 1 in_multiline_comment = false when /^s*#/ @comment_lines += 1 when /^s*$/ # empty/whitespace only line else if in_multiline_comment @comment_lines += 1 else @lines_of_code += 1 end end } end # Get a new ScriptLines instance whose counters hold the # sum of self and other. def +(other) sum = self.dup sum.bytes += other.bytes sum.lines += other.lines sum.lines_of_ code += other.lines_of_code sum.comment_lines += other.comment_lines sum end # Get a formatted string containing all counter numbers and the # name of this instance. def to_s sprintf LINE_FORMAT, @bytes, @lines, @lines_of_code, @comment_lines, @name end end
To tie the class into your build system, give your Rakefile a stats task like the following. This task assumes that the Rakefile and scriptlines.rb are in the same directory:
task stats do require scriptlines files = FileList[lib/**/*.rb] puts ScriptLines.headline sum = ScriptLines.new("TOTAL (#{files.size} file(s))") # Print stats for each file. files.each do |fn| File.open(fn) do |file| script_lines = ScriptLines.new(fn) script_lines.read(file) sum += script_lines puts script_lines end end # Print total stats. puts sum end
Discussion
ScriptLines performs a very basic parsing of Ruby code: it divides a source file into blank lines, comment lines, and lines containing Ruby code. If you want more detailed information, you can include each file and get more information about the defined classes and methods with reflection or an extension like Parse Tree.
Invoke the stats task to run all the Ruby scripts beneath your lib/ directory through ScriptLines. The following example output is for the highline library:
$ rake stats (in /usr/local/lib/ruby/gems/1.8/gems/highline-1.0.1) BYTES LINES LOC COMMENT FILE 18626 617 360 196 lib/highline.rb 12745 375 168 181 lib/highline/menu.rb 15760 430 181 227 lib/highline/question.rb 801 25 7 14 lib/highline/import.rb 47932 1447 716 618 TOTAL (4 scripts)
BYTES is the file size in bytes, LINES the number of total lines in each file, LOC stands for "Lines Of Code," and COMMENT is the number of comment-only lines.
These simple metrics are good for gauging the complexity of a project, but don use them as a measure of day-to-day progress. Complexity is not the same as progress, and a good days work might consist of replacing a hundred lines of code with ten.
See Also
- ri Kernel#sprintf
- The RDoc documentation for Rakes FileList class (http://rake.rubyforge.org/classes/Rake/FileList.html)
- The ParseTree extension (http://rubyforge.org/projects/parsetree/)
Категории