Skip to content

Instantly share code, notes, and snippets.

@makaroni4
Created December 22, 2013 22:07
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 makaroni4/8089043 to your computer and use it in GitHub Desktop.
Save makaroni4/8089043 to your computer and use it in GitHub Desktop.
Simple static analyser for one-letter variable names.
require 'parser'
require 'parser/current'
module OneLetterVariableDetector
class NodeAnalyzer < Struct.new(:node, :path)
def analyze
return unless node && node.respond_to?(:type)
if node.type == :lvasgn || node.type == :lvar
if lvar_name.size == 1
puts "One letter local variable \"#{lvar_name}\" in #{path}:#{node.source_map.line}"
end
end
if node.type == :ivasgn || node.type == :ivar
if ivar_name.size == 1
puts "One letter instance variable \"@#{ivar_name}\" in #{path}:#{node.source_map.line}"
end
end
end
private
def lvar_name
node.to_a.first.to_s.gsub(":", "")
end
def ivar_name
node.to_a.first.to_s.gsub("@", "")
end
end
class CodeAnalyzer < Struct.new(:path)
def analyze
Parser::CurrentRuby.parse(code).to_a.each do |lexem|
scan_node(lexem)
end
end
private
def scan_node(node)
node_analyzer = NodeAnalyzer.new(node, path)
node_analyzer.analyze
if node.respond_to?(:to_a) && node.to_a.respond_to?(:each)
node.to_a.each do |subnode|
scan_node(subnode)
end
end
end
def code
@code ||= File.read(path)
end
end
class FileScanner
def scan(path)
if File.directory?(path)
scan_dir(path)
else
scan_file(path)
end
end
private
def scan_dir(path)
Dir["#{path}/**/*.rb"].each do |file|
scan_file(file)
end
end
def scan_file(path)
begin
analyzer = CodeAnalyzer.new(path)
analyzer.analyze
rescue Exception => e
# comment if you want to skip invalid files
raise e
end
end
end
end
scanner = OneLetterVariableDetector::FileScanner.new
scanner.scan(PATH_TO_FILE_OR_DIR)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment