Skip to content

Instantly share code, notes, and snippets.

@jbodah
Created September 21, 2018 21:57
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 jbodah/424a4e66cbdbfd50c0885dcc0755be02 to your computer and use it in GitHub Desktop.
Save jbodah/424a4e66cbdbfd50c0885dcc0755be02 to your computer and use it in GitHub Desktop.
autoyard spike
require 'spy'
require 'spy/util'
TypeAnalysis = Module.new
TypeAnalysis.extend(Spy::API)
singleton_spy = TypeAnalysis.on_object(NegativeKeywordSelectorTrie)
singleton_spy = Spy::Util::TypeAnalysis.new(singleton_spy).decorate
class_spy = TypeAnalysis.on_class(NegativeKeywordSelectorTrie)
class_spy = Spy::Util::TypeAnalysis.new(class_spy).decorate
require 'ast/processor'
require 'parser/current'
class Processor < AST::Processor
attr_reader :methods_to_arg_names, :singleton_methods_to_arg_names
def initialize(*args, &block)
@methods_to_arg_names = {}
@singleton_methods_to_arg_names = {}
super
end
def on_begin(node)
node.children.each { |c| process(c) }
end
def on_class(node)
node.children.each { |c| process(c) }
end
def on_def(node)
method = node.children[0]
args = node.children[1].children.map { |arg| arg.children[0] }
@methods_to_arg_names[method] = args
end
def on_defs(node)
method = node.children[1]
args = node.children[2].children.map { |arg| arg.children[0] }
@singleton_methods_to_arg_names[method] = args
end
def arg_names_for_method(method)
@methods_to_arg_names[method]
end
def arg_names_for_singleton_method(method)
@singleton_methods_to_arg_names[method]
end
end
$processor = Processor.new
ast = Parser::CurrentRuby.parse(File.read("app/helpers/negative_keyword_selector_trie.rb"))
$processor.process(ast)
def flush_spy(spy)
type_info = spy.type_info
source_location_by_method_name = {}
spy.spies.each do |spy|
next unless spy.original.owner == spy.spied || spy.original.owner == spy.spied.singleton_class
next unless type_info[spy.name]
source_location_by_method_name[spy.name] = spy.original.source_location
end
source_location_by_method_name.sort_by { |_, (_, line)| -line }.each do |method, (file, line)|
contents = File.read(file)
prev_lines = contents.each_line.to_a
new_lines = Spy::Util::YARDFormatter.new.format(type_info[method]) + "\n"
method_indent = prev_lines[line-1][/^\s+/]
new_lines = new_lines.each_line.map { |line| method_indent + line }.join
# skip if it looks like we already have a yard doc
if (/^\s*#\s*@\w/ =~ prev_lines[line-2])
puts "[WARN] Tried to add the folowing YARD doc to #{method.inspect} but it already had one:\n#{new_lines}"
next
end
new_contents = prev_lines.insert(line-1, new_lines).join
File.write(file, new_contents)
end
end
at_exit {
flush_spy(singleton_spy)
flush_spy(class_spy)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment