Created
January 7, 2016 18:48
-
-
Save jbodah/3c77eded917a520bc0c4 to your computer and use it in GitHub Desktop.
list undocumented overrides
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'method_source' | |
require 'set' | |
def load_environment! | |
load 'config/environment.rb' | |
end | |
BASE_DIR = File.expand_path('../', Dir.pwd) | |
pre_objects = Set.new(ObjectSpace.each_object(Module)) | |
load_environment! | |
require 'colorize' | |
Object.class_eval do | |
# Call from UnboundMethod or Method | |
def calls_super? | |
!!source[/super/] | |
rescue | |
true | |
end | |
def override_comment? | |
!!comment[/@override/] | |
rescue | |
true | |
end | |
def defined_in_backupify? | |
!!source_location[0][/^#{Regexp.escape(BASE_DIR)}/] | |
rescue | |
true | |
end | |
end | |
Module.class_eval do | |
def owned_instance_methods | |
instance_methods.select {|m| instance_method(m).owner == self} | |
end | |
end | |
# Format: | |
# Module => { method_symbol => overridden_implementations_array } | |
backupify_mod_to_missing_override_map = {} | |
ObjectSpace.each_object(Module).each do |mod| | |
begin | |
next if pre_objects.include?(mod) # Don't analyze base modules | |
ancestors = mod.ancestors | |
next if ancestors.none? | |
ancestor_imeth_map = (ancestors - [mod]).reduce({}) do |memo, anc| | |
anc.owned_instance_methods.each do |imeth| | |
memo[imeth] ||= [] | |
memo[imeth] << anc | |
end | |
memo | |
end | |
# Array of method_symbols | |
missing_overrides = [] | |
mod.owned_instance_methods.each do |imeth| | |
next if ancestor_imeth_map[imeth].nil? | |
m = mod.instance_method(imeth) | |
#next if m.calls_super? | |
next if m.override_comment? | |
next if !m.defined_in_backupify? | |
missing_overrides << imeth | |
end | |
next if missing_overrides.empty? | |
backupify_mod_to_missing_override_map[mod] = missing_overrides.reduce({}) do |memo, sym| | |
memo[sym] = ancestor_imeth_map[sym] | |
memo | |
end | |
puts mod.name | |
puts missing_overrides.map {|m| "\t- ##{m.to_s.green} overrides #{ancestor_imeth_map[m].map(&:name).map(&:yellow).join(', ')}"}.join("\n") | |
puts | |
rescue => e | |
puts "#{mod}: #{e.to_s}".red | |
next | |
end | |
end | |
if ENV['AUTOADD_DOC_LINE'] | |
def add_override_comment(file, lines, def_line_idx) | |
curr = def_line_idx | |
until curr == 0 || !lines[curr - 1][/^\s*#{Regexp.escape('#')}/] # until previous line is not a comment | |
curr -= 1 | |
end | |
indent = lines[curr][/^\s*/] | |
is_adding_to_existing_comment = !!lines[curr][/^\s*#/] | |
lines.insert(curr, indent + "#\n") if is_adding_to_existing_comment # add extra comment line if was comment | |
lines.insert(curr, indent + "# @override\n") | |
File.open(file, 'w') {|f| f.write lines.join} | |
end | |
backupify_mod_to_missing_override_map.each do |mod, missing_overrides| | |
begin | |
missing_overrides.keys.each do |sym| | |
m = mod.instance_method(sym) | |
next if m.override_comment? # skip if we already wound up adding an override comment (e.g. dynamic getter/setter definitions) | |
file_defined_in, source_line = m.source_location | |
source_line = source_line - 1 # Deal with 0-indexing | |
raise "#{file_defined_in} not in #{BASE_DIR}" unless file_defined_in[/^#{Regexp.escape(BASE_DIR)}/] | |
lines = File.read(file_defined_in).each_line.to_a | |
puts "Sanity check: #{lines[source_line]}".green # sanity check: should be def line | |
raise "Couldn't find method definition: #{lines[source_line]}" unless lines[source_line][/(def |define|attr)/] | |
unless ENV['DRY_RUN'] | |
add_override_comment(file_defined_in, lines, source_line) | |
# Reload the file so we can refesh Method#source_location | |
load file_defined_in | |
end | |
end | |
rescue => e | |
puts "#{mod}: #{e.to_s}".red | |
next | |
end | |
end | |
end | |
vcount = backupify_mod_to_missing_override_map.map {|mod, missing_overrides| missing_overrides.count}.reduce(:+) || 0 | |
puts "Violations found: #{vcount}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment