Skip to content

Instantly share code, notes, and snippets.

@thegedge
Last active May 25, 2016 00:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thegedge/05c6074d03eef77cb4139796c52ea5ea to your computer and use it in GitHub Desktop.
Save thegedge/05c6074d03eef77cb4139796c52ea5ea to your computer and use it in GitHub Desktop.
Find (maybe) unused functions in Ruby
#!/usr/bin/env ruby
require 'optparse'
module CLI
extend self
PATHS_TO_CHECK = %w(app bin config engines lib script)
EXTENSIONS_TO_CHECK_FOR_DEFINITIONS = %w(.rb .rake)
EXTENSIONS_TO_CHECK_FOR_USAGE = EXTENSIONS_TO_CHECK_FOR_DEFINITIONS + %w(.yml .yaml .erb)
FUNCTION_DEF_REGEX = /def\s+(\w+[!?]?)\s*\(?/
FUNCTION_USE_REGEX = /(?<!def )\w+[?!]?/
def main(at_most: 2**30)
maybe_unused_methods = {}
# Gather all function definitions
PATHS_TO_CHECK.each do |path|
Dir.glob("#{path}/**/*").each do |file|
if EXTENSIONS_TO_CHECK_FOR_DEFINITIONS.include?(File.extname(file))
File.read(file).scan(FUNCTION_DEF_REGEX).flatten.each do |method_name|
# Same method name may exist across files, but this is a pretty dumb script, so that's okay
maybe_unused_methods[method_name] ||= []
maybe_unused_methods[method_name] << file
end
end
end
end
# If a symbol exists (and not part of a 'def <sym>') then remove it from the list of methods
PATHS_TO_CHECK.each do |path|
Dir.glob("#{path}/**/*").each do |file|
if EXTENSIONS_TO_CHECK_FOR_USAGE.include?(File.extname(file))
File.read(file).scan(FUNCTION_USE_REGEX).flatten.each do |symbol|
maybe_unused_methods.delete(symbol)
end
end
end
end
maybe_unused_methods.each do |method_name, defined_in|
puts "#{method_name} #{defined_in.join(',')}" if defined_in.length <= at_most
end
end
end
if __FILE__ == $0
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: #{$0} [options]"
# If a method name is used across files, there's a good chance it's part of some library or
# superclass that we're not seeing in this codebase
opts.on("-n", "--at-most N", Integer, "Only output entries defined in at most N files") do |value|
options[:at_most] = value
end
end.parse!
CLI.main(**options)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment