Last active
June 24, 2017 16:49
-
-
Save ochaochaocha3/0db14de62b57b4a318798faf497914b1 to your computer and use it in GitHub Desktop.
指定したキーワードからDodontoFServer.rb内のコールグラフを作るスクリプト
This file contains 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
IDENTIFIER_PATTERN = /[A-Za-z_][A-Za-z0-9_]*/ | |
FUNC_PATTERN = /\Adef\s*((?:DodontoFServer|self)\.)?(#{IDENTIFIER_PATTERN})/o | |
class DodontoFMethod < Struct.new(:name, :decl_line, :lines, :class_method) | |
def to_s | |
"<#{self.class_method ? 'class_method' : 'method'} #{self.name}>" | |
end | |
end | |
dodontof_methods = [] | |
current_method = nil | |
File.open('DodontoFServer.rb') do |f| | |
n_line = 0 | |
loop do | |
line = f.gets | |
n_line += 1 | |
break if line.start_with?('class DodontoFServer') | |
end | |
end_level = 0 | |
state = :class | |
state_proc = { | |
class: lambda { |line| | |
m = line.lstrip.match(FUNC_PATTERN) | |
next :class unless m | |
method_name = m[2] | |
class_method = !!m[1] | |
current_method = DodontoFMethod.new(method_name, n_line, [], class_method) | |
dodontof_methods << current_method | |
end_level = 0 | |
next :method | |
}, | |
method: lambda { |line| | |
if end_level == 0 && /\A\s*end\s*/ === line | |
next :class | |
end | |
current_method.lines << line.rstrip | |
case line | |
when /\A\s*end\b/ | |
end_level -= 1 | |
next :class if end_level < 0 | |
#syn match rubyControl "\<\%(case\|begin\|do\|for\|if\|unless\|while\|until\|else\|elsif\|ensure\|then\|when\|end\)\>[?!]\@!" | |
when /\A\s*(?:if|unless|case|while|until)\b/, /\b(?:begin|do)\b/ | |
end_level += 1 | |
end | |
next :method | |
} | |
} | |
loop do | |
line = f.gets | |
n_line += 1 | |
break if /\Aend\s*$/ === line | |
state = state_proc[state][line] | |
end | |
end | |
class CallTree < Struct.new(:query, :parents, :visited_methods, :methods, :line_nums) | |
def walk! | |
corresponding_method = methods.find { |method| method.name == query } | |
self.visited_methods << corresponding_method if corresponding_method | |
targets = self.methods - self.visited_methods | |
containing_methods = targets.reduce([]) { |acc, method| | |
line_nums = method.lines.each.with_index(1).reduce([]) { |acc_line_nums, (line, i)| | |
line.include?(self.query) ? (acc_line_nums + [method.decl_line + i]) : acc_line_nums | |
} | |
line_nums.length > 0 ? (acc + [[method, line_nums]]) : acc | |
} | |
containing_methods.each do |method, line_nums| | |
parent_tree = CallTree.new(method.name, [], self.visited_methods, targets, line_nums) | |
self.parents << parent_tree | |
parent_tree.walk! | |
end | |
end | |
def print_tree | |
def print_inner(call_tree, level) | |
print(' ' * level) | |
print('<- ') if level > 0 | |
print(call_tree.query) | |
unless call_tree.line_nums.empty? | |
line_nums_str = call_tree.line_nums.map { |n| "L#{n}" }.join(', ') | |
print(" (#{line_nums_str})") | |
end | |
puts | |
call_tree.parents.each do |parent| | |
print_inner(parent, level + 1) | |
end | |
end | |
print_inner(self, 0) | |
end | |
end | |
ARGV.each_with_index do |keyword, i| | |
puts if i > 0 | |
puts("[#{keyword}]") | |
leaf = CallTree.new(keyword, [], [], dodontof_methods, []) | |
leaf.walk! | |
leaf.print_tree | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment