3 # First assume we are installed as a gem
7 # Failing that, try to load our files from the source tree
8 $: << "#{File.dirname(__FILE__)}/../lib"
12 class OhcountCommandLine
15 def initialize(args=[])
16 args = args.clone # Because shift is destructive
17 set_option(args.shift) while args.first =~ /^-/
27 @files = nil # If we change the search paths, clear the cache filenames
31 return @files if @files
33 @files = `find #{(self.paths.any? ? self.paths : ['.']).join(' ')} \! -path "*/.*" -type f -print`.split
34 exit 1 unless @files.any?
40 sfc = Ohcount::SimpleFileContext.new(file, files)
41 polyglot = Ohcount::Detector.detect(sfc)
43 Ohcount::parse(sfc.contents, polyglot) do |language, semantic, line|
44 puts "#{language}\t#{semantic}\t#{line}"
50 # Find all source code files
53 sfc = Ohcount::SimpleFileContext.new(file, files)
54 polyglot = Ohcount::Detector.detect(sfc)
55 puts "#{polyglot}\t#{file}" if polyglot
61 Usage: ohcount [option] [paths...]
63 Ohloh source code line counter command line tool.
66 [option] can be one of the following:
72 -a, --annotate Show annotated source code
74 The contents of all source code files found within the given
75 paths will be emitted to stdout. Each line will be prefixed with
76 a tab-delimited language name and semantic categorization (code,
79 -d, --detect Find source code files
81 Recursively find all source code files within the given paths.
82 For each source code file found, the file name will be emitted to
83 stdout prefixed with a tab-delimited language name.
85 -h, --help Display this message
87 -s, --summary Count lines of code (default)
89 Count lines in all source code files within the given paths, and
90 emit a report of the total number of lines of code, comments,
91 and blanks in each language. This is the default action.
93 [paths] can refer to any number of individual files or directories.
94 Directories will be probed recursively. If no path is given,
95 the current directory will be used.
101 STDOUT.write "Examining #{files.size} file(s)"
104 any_language_file_count = 0
109 sfc = Ohcount::SimpleFileContext.new(file, files)
110 polyglot = Ohcount::Detector.detect(sfc)
112 Ohcount::parse(sfc.contents, polyglot) do |language_name, semantic, line|
113 counts[language_name] ||= {:code => 0, :comment => 0, :blank => 0}
114 counts[language_name][semantic] += 1
115 languages_found << language_name unless languages_found.include?(language_name)
119 # Keep a running total of the number of files that include a specific language
120 languages_found.each { |l| counts[l][:files] = (counts[l][:files] || 0) + 1 }
122 # Keep a running total of the number of files that include any language
123 any_language_file_count += 1 if languages_found.any?
126 if (progress % 100 == 0)
133 puts "Ohloh Line Count Summary".center(76)
136 puts "Language Files Code Comment Comment % Blank Total"
137 puts "-------------- ----- --------- --------- --------- --------- ---------"
139 counts.keys.sort{ |a,b| counts[b][:code] <=> counts[a][:code] }.each do |key|
140 write_summary_row(key, counts[key][:files], counts[key][:code], counts[key][:comment], counts[key][:blank])
143 puts "-------------- ----- --------- --------- --------- --------- ---------"
144 write_summary_row('Total', any_language_file_count,
145 counts.values.inject(0) { |sum, v| sum + v[:code] },
146 counts.values.inject(0) { |sum, v| sum + v[:comment] },
147 counts.values.inject(0) { |sum, v| sum + v[:blank] })
150 def write_summary_row(name, file_count, code, comment, blank)
151 printf("%-14s", name)
152 printf(" %6d", file_count)
153 printf(" %10d", code)
154 printf(" %10d", comment)
156 printf(" %9.1f%%", comment.to_f / (comment+code).to_f * 100.0)
158 printf(" %10d", blank)
159 printf(" %10d\n", code+comment+blank)
164 STDERR.puts "Error: Multiple commands specified."
175 def set_option(option)
177 when '-s', '--summary'
178 self.subcommand = :summary
179 when '-d', '--detect'
180 self.subcommand = :detect
181 when '-a', '--annotate'
182 self.subcommand = :annotate
183 when '-?', '-h', '--help'
184 self.subcommand = :help
186 STDERR.puts "Type 'ohcount -?' for usage."
192 self.subcommand ||= :summary
193 if self.respond_to?(self.subcommand)
194 self.send(self.subcommand)
196 STDERR.puts "Type 'ohcount -?' for usage."
202 OhcountCommandLine.new(ARGV).run!