-
Notifications
You must be signed in to change notification settings - Fork 1
/
classy.rb
executable file
·160 lines (131 loc) · 3.36 KB
/
classy.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/usr/bin/ruby
###############################################################
### Copyright 2015 by Santiago Gonzalez <[email protected]> ###
###############################################################
require 'colorize'
def usage
puts "Usage: classy directory"
puts " classy directory ClassName"
end
# Recursively inserts a class under its parent
def recurse_insert_the_tree(tree, item)
# check if in this layer
tree.keys.each do |key|
if key == item[3]
tree[key][4][item[1]] = item
return true
end
end
# check if in subtrees
tree.values.each do |entry|
if recurse_insert_the_tree(entry[4], item)
return true
end
end
return false
end
# Recursively search for a specific class in the provided tree
def find_node_named(tree, name)
# check if in this layer
tree.keys.each do |key|
if key == name
return tree[name]
end
end
# check if in subtrees
tree.values.each do |entry|
return find_node_named(entry[4], name)
end
return false
end
# Recursively print out the class tree for a given root node
$tree_print_scopes = {}
def print_tree(root, indentation = 0, is_last = false)
if !$tree_print_scopes.key? indentation
$tree_print_scopes[indentation] = true
end
(indentation-1).times do |i|
if $tree_print_scopes[i] == true
print " │ "
else
print " "
end
end
if indentation != 0
if is_last
print " └── "
else
print " ├── "
end
end
print root[1]
print " #{root[0]}".cyan
print " #{root[2]}".blue
print " #{root[5]}".magenta
print "\n"
root[4].values.each_with_index do |child, i|
is_last = (i == root[4].values.size-1)
if is_last
$tree_print_scopes[indentation] = false
else
$tree_print_scopes[indentation] = true
end
print_tree(child, indentation+1, is_last)
end
end
################
## Control start
# Argument processing
if ARGV.size != 1 && ARGV.size != 2
usage
exit
end
target_dir = ARGV[0]
explicit_root = ""
if ARGV.size == 2
explicit_root = ARGV[1]
end
roots = {}
children = []
# Read in class declarations from all the files in the target directory
filenames = Dir.glob("#{target_dir}/**/*.h") + Dir.glob("#{target_dir}/**/*.hpp")
filenames.each do |filename|
contents = File.open(filename, 'rb') { |f| f.read }
captures = contents.scan(/^(class|struct) (\w+)(\s?:\s?(public|private)?\s?(\w+))?\s?{/)
captures.each do |capture|
type = capture[0]
name = capture[1]
inheritance = capture[3]
parent = capture[4]
if !capture[4] # root class
roots[name] = [type, name, inheritance, parent, {}, File.basename(filename)]
# puts "ROOT: #{name}"
else # child class
children << [type, name, inheritance, parent, {}, File.basename(filename)]
# puts "CHILD: #{name} #{parent}"
end
end
end
# Make the classes a tree
loop do
children.each do |child|
if recurse_insert_the_tree(roots, child)
children.delete child
break
end
end
break if children.size == 0
end
# Print out the hierarchy
if explicit_root.empty? # no explicit root specified, print everything
roots.values.each do |root|
print_tree root
end
else # print tree for explicit root
result = find_node_named(roots, explicit_root)
if result
print_tree(result)
else
puts "No tree available."
end
end