Skip to content

Instantly share code, notes, and snippets.

@andynu
Last active Feb 2, 2021
Embed
What would you like to do?
Find all those TODO/FIXME/HACK/etc.
#!/usr/bin/ruby
#
# gather a few statistics and find all flagged comments
#
# Usage:
# rfluff [-qf] [tag] [tag] ...
#
# -qf outputs a vim compatible quickfix format, otherwise
# the output is human readable
#
# [tag] - Default tags are listed below in `flags`, but you can add any additional tags you want on the commandline.
#
file_types = %w(rb erb haml rake cgi coffee)
particular_files = %w(README* readme* rakefile Rakefile capfile Capfile Gemfile Guardfile)
find = [
particular_files,
particular_files.map{|f|'**/'+f},
file_types.map{|ext|'**/*.'+ext}
]
flags = {
"TODO" => /\bTODO\b/,
"FIXME" => /\bFIXME\b/i,
"@deprecated" => /\b@deprecated\b/i,
"@todo" => /\b@todo\b/i,
"XXX"=> /\bXXX\b/i,
"REVIEW" => /\bREVIEW\b/,
"FEATURE" => /\bFEATURE\b/,
"PROBLEM" => /\bPROBLEM\b/,
"hack" => /\bhack\b/i,
# "relative_paths" => /\.\.\//,
}
IGNORE_PATHS = %w(
tmp
node_modules
)
ARGV.each do |arg|
next if arg==''
next if arg=='-qf'
flags[arg] = %r{\b#{arg}\b/i}
end
# initialize totals
totals = Hash.new
comments = Hash.new
#
flags.keys.each do |flag|
totals[flag] = 0
end
# iterate over the pertinent files
Dir[*find.flatten].each do |file_name|
next if IGNORE_PATHS.any?{|ignore_path| file_name.start_with?(ignore_path) }
comments[file_name] = Array.new
# examine for comments
File.open(file_name,"r") do |file|
file.each_with_index do |line, line_number|
flags.each_pair do |flag,regex|
unless line.index(regex).nil?
totals[flag] += 1
comments[file_name] << [line_number+1, line.strip.chomp]
end
end
end
end
end
# clean up a display of a hash of totals
# ala Data::Hash::Totals
def as_table(hash)
max = 0
hash.keys.each do |key|
if key.size > max
max += key.size
end
end
table = ""
unused_keys = []
hash.keys.each do |key|
if hash[key].zero?
unused_keys << key
else
table += key.rjust(max) +": "+ hash[key].to_s + "\n"
end
end
return table, unused_keys
end
def print_human(comments, totals)
# show what we've collected
comments.keys.each do |key|
unless comments[key].empty?
puts key
comments[key].each do |line_number, line|
puts "\t%s: %s" % [line_number, line]
end
puts
end
end
puts
# show the totals
table, unused_keys = as_table(totals)
puts table
puts
puts "# Unused keys: #{unused_keys}"
end
def print_vim_quickfix(comments, totals)
# show what we've collected
comments.keys.each do |filename|
next if comments[filename].empty?
comments[filename].each do |line_number, line|
puts "%s|%s| %s" % [filename, line_number, line]
end
end
## show the totals
#puts as_table(totals)
end
if ARGV[0] == '-qf'
print_vim_quickfix(comments,totals)
else
print_human(comments,totals)
end
@jstoone
Copy link

jstoone commented Feb 2, 2021

This is sweet!

And the tip you mentioned on the codequalitychallenge.com forum was baller!

Andy said:
As a bonus, if you run it with -qf you get vim compatible quickfix output. So for vim users:
command! Rfluff cexpr system('rfluff -qf ' . shellescape(expand('%:r')))|:cw

Side note: Depending on your codebase and team, though I haven’t included them by default here, I have found that adding a few swears into the tag list can find things that perhaps ought to have been TODOs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment