codegraph 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +27 -0
- data/bin/codegraph +174 -0
- data/gemspec +21 -0
- data/lib/codegraph.rb +280 -0
- metadata +79 -0
data/LICENSE
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Copyright (c) 2009, Ralf Mueller (stark.dreamdetective@googlemail.com)
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
* Redistributions in binary form must reproduce the above copyright
|
11
|
+
notice, this list of conditions and the following disclaimer in the
|
12
|
+
documentation and/or other materials provided with the distribution.
|
13
|
+
|
14
|
+
* The names of its contributors may not be used to endorse or promote
|
15
|
+
products derived from this software without specific prior written
|
16
|
+
permission.
|
17
|
+
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
19
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
20
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
21
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
22
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
23
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
24
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
25
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
26
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/bin/codegraph
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "codegraph"
|
3
|
+
require "getoptlong"
|
4
|
+
|
5
|
+
def show_usage
|
6
|
+
puts <<-END
|
7
|
+
Usage: #{__FILE__}:
|
8
|
+
--help, -h guess what
|
9
|
+
|
10
|
+
--file-list, -F "<list>"
|
11
|
+
fill the graph with every function,
|
12
|
+
that has a definiton inside the given files
|
13
|
+
|
14
|
+
--function, -f "<funcname>"
|
15
|
+
take the given func as the root knode
|
16
|
+
|
17
|
+
--show-body, -s "<funcname>"
|
18
|
+
display the function code in the terminal
|
19
|
+
|
20
|
+
--upper-funx, -u "<funcname>"
|
21
|
+
scan for all funx, which depends directly or
|
22
|
+
indirectly on <funcname>
|
23
|
+
|
24
|
+
--8-funx, -8 "<funcname>"
|
25
|
+
scan for all funx, which depends (in)directly
|
26
|
+
<funcname> AND which call <funcname>
|
27
|
+
(in)directly
|
28
|
+
|
29
|
+
--exclude, -x "<list>"
|
30
|
+
exclude a list of functions from the graph
|
31
|
+
|
32
|
+
--depth, -d <integer>
|
33
|
+
Set maximal Graph depth
|
34
|
+
|
35
|
+
--to-ps, -p <filename>
|
36
|
+
create a postscript file from the graph
|
37
|
+
|
38
|
+
--to-svg, -S <filename>
|
39
|
+
create a SVG file from the graph
|
40
|
+
|
41
|
+
--to-png, -P <filename>
|
42
|
+
create a PNG file from the graph
|
43
|
+
|
44
|
+
--to-jpg, -J <filename>
|
45
|
+
create a JPG file from the graph
|
46
|
+
|
47
|
+
--to-dot, -D <filename>
|
48
|
+
creates a <filename>.dot-file
|
49
|
+
|
50
|
+
--to-txt, -T
|
51
|
+
writes the relations to stdout
|
52
|
+
END
|
53
|
+
end
|
54
|
+
# Which options are availabile ------------------------------------------------
|
55
|
+
options = GetoptLong.new(
|
56
|
+
["--help", "-h", GetoptLong::NO_ARGUMENT],
|
57
|
+
# ["--local", "-l", GetoptLong::NO_ARGUMENT],
|
58
|
+
# ["--source", "-s", GetoptLong::NO_ARGUMENT],
|
59
|
+
# ["--with-internal", "-w", GetoptLong::NO_ARGUMENT],
|
60
|
+
["--function", "-f", GetoptLong::REQUIRED_ARGUMENT],
|
61
|
+
["--show-body", "-s", GetoptLong::REQUIRED_ARGUMENT],
|
62
|
+
["--upper-funx", "-u", GetoptLong::REQUIRED_ARGUMENT],
|
63
|
+
["--8-funx", "-8", GetoptLong::REQUIRED_ARGUMENT],
|
64
|
+
["--file-list", "-F", GetoptLong::REQUIRED_ARGUMENT],
|
65
|
+
["--depth", "-d", GetoptLong::REQUIRED_ARGUMENT],
|
66
|
+
["--to-ps", "-p", GetoptLong::REQUIRED_ARGUMENT],
|
67
|
+
["--to-svg", "-S", GetoptLong::REQUIRED_ARGUMENT],
|
68
|
+
["--to-png", "-P", GetoptLong::REQUIRED_ARGUMENT],
|
69
|
+
["--to-jpg", "-J", GetoptLong::REQUIRED_ARGUMENT],
|
70
|
+
["--to-dot", "-D", GetoptLong::REQUIRED_ARGUMENT],
|
71
|
+
["--to-txt", "-T", GetoptLong::NO_ARGUMENT],
|
72
|
+
["--exclude", "-x", GetoptLong::REQUIRED_ARGUMENT],
|
73
|
+
)
|
74
|
+
options.ordering = GetoptLong::RETURN_IN_ORDER
|
75
|
+
# Default values --------------------------------------------------------------
|
76
|
+
filelist = ""
|
77
|
+
mode = "multiple"
|
78
|
+
output = ""
|
79
|
+
internal = false
|
80
|
+
filename = ""
|
81
|
+
dotfile = ""
|
82
|
+
function = ""
|
83
|
+
depth = nil
|
84
|
+
exclude = Array.new
|
85
|
+
files = Array.new
|
86
|
+
# option parsing --------------------------------------------------------------
|
87
|
+
options.each do |opt, arg|
|
88
|
+
case opt
|
89
|
+
when "--file-list"
|
90
|
+
filelist = arg
|
91
|
+
files = Dir.glob(filelist.split(' '))
|
92
|
+
when "--function"
|
93
|
+
mode = "single"
|
94
|
+
function = arg
|
95
|
+
when "--show-body"
|
96
|
+
mode = "show"
|
97
|
+
function = arg
|
98
|
+
when "--upper-funx"
|
99
|
+
mode = "upper"
|
100
|
+
function = arg
|
101
|
+
when "--8-funx"
|
102
|
+
mode = 8
|
103
|
+
function = arg
|
104
|
+
when "--depth"
|
105
|
+
depth = arg.to_i
|
106
|
+
when "--to-ps"
|
107
|
+
output = "ps"
|
108
|
+
filename = arg
|
109
|
+
when "--to-svg"
|
110
|
+
output = "svg"
|
111
|
+
filename = arg
|
112
|
+
when "--to-png"
|
113
|
+
output = "png"
|
114
|
+
filename = arg
|
115
|
+
when "--to-jpg"
|
116
|
+
output = "jpg"
|
117
|
+
filename = arg
|
118
|
+
when "--to-dot"
|
119
|
+
output = "dot"
|
120
|
+
filename = arg
|
121
|
+
when "--to-txt"
|
122
|
+
output = "txt"
|
123
|
+
when "--exclude"
|
124
|
+
exclude = arg.split(/ /)
|
125
|
+
else
|
126
|
+
show_usage
|
127
|
+
exit
|
128
|
+
end
|
129
|
+
end
|
130
|
+
options.terminate
|
131
|
+
# script controlling ----------------------------------------------------------
|
132
|
+
# Is the filelist correct?
|
133
|
+
if files.size == 0
|
134
|
+
puts 'Please use --file-list "<list>"'
|
135
|
+
show_usage
|
136
|
+
exit
|
137
|
+
end
|
138
|
+
|
139
|
+
# What kind of graph should be generated?
|
140
|
+
case mode
|
141
|
+
when "upper"
|
142
|
+
g = UpperFunctionGraph.new(function)
|
143
|
+
when "single","show"
|
144
|
+
g = SingleFunctionGraph.new(function)
|
145
|
+
when 8
|
146
|
+
g = EightFunctionGraph.new(function)
|
147
|
+
else
|
148
|
+
g = FunctionGraph.new
|
149
|
+
end
|
150
|
+
|
151
|
+
# Include the internal functions of the language?
|
152
|
+
g.internal = internal
|
153
|
+
|
154
|
+
# Creates the Knodes/Edges of the graph
|
155
|
+
g.fill(files,exclude)
|
156
|
+
|
157
|
+
# Remove edges
|
158
|
+
g.limit(depth) if depth
|
159
|
+
|
160
|
+
# What sort of output should be created?
|
161
|
+
case output
|
162
|
+
when "ps", "svg", "png", "jpg"
|
163
|
+
g.to_type(filename,output)
|
164
|
+
when "dot"
|
165
|
+
g.to_dot(filename)
|
166
|
+
when "txt"
|
167
|
+
g.to_txt
|
168
|
+
else
|
169
|
+
if mode == "show"
|
170
|
+
puts g.display_functionbody(function)
|
171
|
+
else
|
172
|
+
g.display
|
173
|
+
end
|
174
|
+
end
|
data/gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
spec = Gem::Specification.new do |s|
|
4
|
+
s.name = "codegraph"
|
5
|
+
s.version = "0.7.1"
|
6
|
+
s.date = "2010-11-01"
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.bindir = 'bin'
|
9
|
+
s.files = ["lib/codegraph.rb","bin/codegraph"] + ["gemspec","LICENSE"]
|
10
|
+
s.executables << 'codegraph'
|
11
|
+
s.add_dependency('rgl')
|
12
|
+
s.rubyforge_project = "codegraph"
|
13
|
+
s.description = "Display functional dependencies in source code (C, Fortran, PHP, Perl)."
|
14
|
+
s.summary = "Display functional dependencies in source code (C, Fortran, PHP, Perl)"
|
15
|
+
s.author = "Ralf Mueller"
|
16
|
+
s.email = "stark.dreamdetective@gmail.com"
|
17
|
+
s.homepage = "http://codegraph.rubyforge.org"
|
18
|
+
s.has_rdoc = true
|
19
|
+
end
|
20
|
+
|
21
|
+
# vim:ft=ruby
|
data/lib/codegraph.rb
ADDED
@@ -0,0 +1,280 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rgl/adjacency'
|
3
|
+
require 'rgl/dot'
|
4
|
+
require 'rgl/rdot'
|
5
|
+
require 'rgl/traversal'
|
6
|
+
|
7
|
+
class FunctionGraph < RGL::DirectedAdjacencyGraph
|
8
|
+
attr_accessor :funx, :internal
|
9
|
+
|
10
|
+
# Theses Parameters are used by interactive representation and for the file
|
11
|
+
# generation function to_dot and to_type. They can only be given for the
|
12
|
+
# whole graph, not for a singel node. This could be done by extending the
|
13
|
+
# dot.rb file of the Ruby Graph Library
|
14
|
+
Params = {'rankdir' => 'LR',
|
15
|
+
'ranksep' => '4.0',
|
16
|
+
'concentrate' => 'TRUE',
|
17
|
+
'label' => '',
|
18
|
+
'fontsize' => '12'}
|
19
|
+
|
20
|
+
# Hash of supported langs and the ctags marker for functions
|
21
|
+
Types = {"php" => "f",
|
22
|
+
"perl" => "s",
|
23
|
+
"c" => "f",
|
24
|
+
"f" => "fs",
|
25
|
+
"sh" => "f"}
|
26
|
+
|
27
|
+
# Hash of how ctags calls function for each lang
|
28
|
+
Funx = {"php" => "function",
|
29
|
+
"perl" => "subroutine",
|
30
|
+
"c" => "function",
|
31
|
+
"f" => "subroutine",
|
32
|
+
"sh" => "function"}
|
33
|
+
|
34
|
+
@@home = `echo $HOME`.chomp
|
35
|
+
@@codehomedir = "#{@@home}/.codegraph"
|
36
|
+
@@internal_funx = []
|
37
|
+
@@matchBeforFuncName = '[^A-z0-9_]'
|
38
|
+
@@matchAfterFuncName = '\('
|
39
|
+
|
40
|
+
# Generate the codegraph storage directory
|
41
|
+
if not FileTest.directory?(@@codehomedir)
|
42
|
+
system("mkdir #{@@codehomedir}")
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize
|
46
|
+
super
|
47
|
+
# the following attribute will hold the functionnames and their bodies
|
48
|
+
@funx = Hash.new
|
49
|
+
|
50
|
+
# Should the internal functions be displayed?
|
51
|
+
@internal = false
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
# Generates the necessary files:
|
56
|
+
# 1. One for the whole source code
|
57
|
+
# 2. One for functions inside the file 1
|
58
|
+
# and fill the @funx hash
|
59
|
+
def genFiles(graph, filelist, exclude=[])
|
60
|
+
names, kinds, lines, files = [],[],[],[]
|
61
|
+
|
62
|
+
funxFile = "funxnames"
|
63
|
+
ctagsKinds='--c-kinds=f --fortran-kinds=fs --php-kinds=f --perl-kinds=f'
|
64
|
+
filelist.each {|file|
|
65
|
+
puts "Processing #{file} ..."
|
66
|
+
basefile = File.basename(file)
|
67
|
+
temfile = "_" + basefile
|
68
|
+
case File.extname(file)
|
69
|
+
when '.c','.h'
|
70
|
+
cppCommand = "cpp -w -fpreprocessed -E -fdirectives-only #{file} -o #{@@codehomedir}/#{temfile}"
|
71
|
+
grep = "grep -v -e '^$' #{temfile} | grep -v -e '^#' > #{basefile}"
|
72
|
+
when '.f','.f77','.f90','.f95'
|
73
|
+
cppCommand = "cp #{file} #{@@codehomedir}/#{temfile}"
|
74
|
+
grep = "grep -v -e '^$' #{temfile} | grep -v -e '^ *!' > #{basefile}"
|
75
|
+
else
|
76
|
+
cppCommand = "cp #{file} #{@@codehomedir}/#{temfile}"
|
77
|
+
grep = "grep -v -e '^$' #{temfile} | grep -v -e '^#' > #{basefile}"
|
78
|
+
end
|
79
|
+
cd = "cd #{@@codehomedir}"
|
80
|
+
gen4ctags = "ctags -x #{ctagsKinds} #{basefile} | sort -n -k 3 > " + funxFile
|
81
|
+
command = [cppCommand,cd,grep,gen4ctags].join(";")
|
82
|
+
|
83
|
+
puts command
|
84
|
+
system(command)
|
85
|
+
|
86
|
+
open(@@codehomedir+'/'+funxFile).readlines.each {|line|
|
87
|
+
name, kind, lineno, file = line.split[0,4]
|
88
|
+
names << name
|
89
|
+
kinds << kind
|
90
|
+
lines << lineno.to_i
|
91
|
+
files << file
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
unless File.size?(@@codehomedir+'/'+funxFile)
|
96
|
+
puts "no functions found"
|
97
|
+
exit
|
98
|
+
end
|
99
|
+
|
100
|
+
meta = [names, kinds, lines, files]
|
101
|
+
|
102
|
+
# read the source once and save the function bodies as values
|
103
|
+
# of the function names
|
104
|
+
|
105
|
+
metasize = meta[2].size
|
106
|
+
lastfile,code = nil,nil
|
107
|
+
meta.transpose.each_with_index {|ary,i|
|
108
|
+
name, kind, line, file = ary
|
109
|
+
|
110
|
+
if file != lastfile
|
111
|
+
code = open(@@codehomedir+'/'+ File.basename(file)).readlines
|
112
|
+
codeLength = code.length
|
113
|
+
end
|
114
|
+
startLineIndex = meta[2][i]-1
|
115
|
+
endLineIndex = (i+1 < metasize) ? meta[2][i+1] - 2 : -1
|
116
|
+
# code-Index starts with 0 vs. line numbbers in (meta|m).lines start with 1
|
117
|
+
body = code[startLineIndex..endLineIndex].join
|
118
|
+
|
119
|
+
@funx.store(name,body)
|
120
|
+
lastfile = file
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
# fill the graph with all functions found in <filelist>
|
125
|
+
# while all functions from <exclude> aren't recognized
|
126
|
+
def fill(filelist,exclude=[])
|
127
|
+
# generate the necessary files and fill @funx
|
128
|
+
genFiles(self,filelist,exclude)
|
129
|
+
|
130
|
+
# scan functions for the function names
|
131
|
+
names = @funx.keys
|
132
|
+
@funx.each_pair {|name,body|
|
133
|
+
add_vertex(name)
|
134
|
+
(names - [name] + @@internal_funx).each { |func|
|
135
|
+
add_edge("#{name}","#{func}") if /#@@matchBeforFuncName#{func}/.match(body)
|
136
|
+
}
|
137
|
+
}
|
138
|
+
end
|
139
|
+
|
140
|
+
def limit(depth)
|
141
|
+
dv = RGL::DFSVisitor.new(self)
|
142
|
+
dv.attach_distance_map
|
143
|
+
self.depth_first_search(dv) {|u|
|
144
|
+
self.remove_vertex(u) if dv.distance_to_root(u) > depth
|
145
|
+
}
|
146
|
+
end
|
147
|
+
|
148
|
+
def display_functionbody(name)
|
149
|
+
@funx[name]
|
150
|
+
end
|
151
|
+
# Creates a simple dot file according to the above <Params>.
|
152
|
+
# Parameters for the nodes are not supported by rgl.
|
153
|
+
def to_dot(filename)
|
154
|
+
File.open("#{filename}","w") {|f|
|
155
|
+
print_dotted_on(Params,f)
|
156
|
+
}
|
157
|
+
end
|
158
|
+
|
159
|
+
# Generates pairs of "func_A -> func_B" to stdout
|
160
|
+
def to_txt
|
161
|
+
each_edge do |left,right|
|
162
|
+
print left,' -> ',right,"\n"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# This function generates a file of the given type using the dot utility.
|
167
|
+
# Supported Types are PS, PNG, JPG, DOT and SVG.
|
168
|
+
def to_type(filename,type)
|
169
|
+
if File.exist?(filename)
|
170
|
+
system("rm #{filename}")
|
171
|
+
end
|
172
|
+
if File.exist?(filename+"."+type)
|
173
|
+
system("rm #{filename}."+type)
|
174
|
+
end
|
175
|
+
to_dot(filename+".dot")
|
176
|
+
system("dot -T#{type} -o #{filename} -Nshape=box #{filename}.dot")
|
177
|
+
system("rm #{filename}.dot")
|
178
|
+
end
|
179
|
+
|
180
|
+
# Display the graph with an interactive viewer
|
181
|
+
def display
|
182
|
+
dotty(Params)
|
183
|
+
system("rm graph.dot") if File.exist?("graph.dot")
|
184
|
+
end
|
185
|
+
private :genFiles
|
186
|
+
end
|
187
|
+
|
188
|
+
class SingleFunctionGraph < FunctionGraph
|
189
|
+
attr_accessor :func
|
190
|
+
|
191
|
+
# Constructor, which creates an empty graph for the rootfunction <func>
|
192
|
+
def initialize(func)
|
193
|
+
# Holds the func'n names, that are allready scanned
|
194
|
+
@scannednames = []
|
195
|
+
# Root func
|
196
|
+
@func = func
|
197
|
+
super()
|
198
|
+
end
|
199
|
+
|
200
|
+
# Works like the one from FunctionGraph except, that it calls 'scan'
|
201
|
+
# for the recursive descent throug all functions given in <filelist> - exclude
|
202
|
+
def fill(filelist,exclude=[])
|
203
|
+
genFiles(self,filelist,exclude)
|
204
|
+
scan(self, func)
|
205
|
+
end
|
206
|
+
|
207
|
+
# For the given root function f, scan walks through the graph, and finds any
|
208
|
+
# other function, that calls f
|
209
|
+
def scan(graph,f)
|
210
|
+
if (@scannednames.include?(f))
|
211
|
+
else
|
212
|
+
names = graph.funx.keys
|
213
|
+
if not names.include?(func)
|
214
|
+
puts "Function #{func} not found."
|
215
|
+
exit
|
216
|
+
end
|
217
|
+
@scannednames << f
|
218
|
+
body = graph.funx[f]
|
219
|
+
# scan for any other function in the body of f
|
220
|
+
(names - [f] + @@internal_funx).each {|g|
|
221
|
+
if /#@@matchBeforFuncName#{g}#@@matchAfterFuncName/.match(body)
|
222
|
+
graph.add_edge(f,g)
|
223
|
+
# unless its not an internal function, go downstairs
|
224
|
+
scan(graph,g) if names.include?(g)
|
225
|
+
end
|
226
|
+
}
|
227
|
+
end
|
228
|
+
end
|
229
|
+
private :scan
|
230
|
+
end
|
231
|
+
|
232
|
+
class UpperFunctionGraph < SingleFunctionGraph
|
233
|
+
|
234
|
+
# scanning upwards unlike SingleFunctionGraph.scan
|
235
|
+
def scan(graph,func)
|
236
|
+
if @scannednames.include?(func)
|
237
|
+
else
|
238
|
+
if not (graph.funx.keys + @@internal_funx).include?(func)
|
239
|
+
puts "Function '#{func}' not found. If this is an internal function, " +
|
240
|
+
"please try again with the '-w' option to include the internal " +
|
241
|
+
"funx before scanning."
|
242
|
+
#system("rm ~/.codegraph/all.#{ng} ~/.codegraph/code-names")
|
243
|
+
exit
|
244
|
+
end
|
245
|
+
@scannednames << func
|
246
|
+
graph.funx.each_pair {|g,gbody|
|
247
|
+
# dont scan a function for itself
|
248
|
+
next if g == func
|
249
|
+
|
250
|
+
if/#@@matchBeforFuncName#{func}#@@matchAfterFuncName/.match(gbody)
|
251
|
+
graph.add_edge(g,func)
|
252
|
+
scan(graph,g)
|
253
|
+
end
|
254
|
+
}
|
255
|
+
end
|
256
|
+
end
|
257
|
+
private :scan
|
258
|
+
end
|
259
|
+
|
260
|
+
class EightFunctionGraph < FunctionGraph
|
261
|
+
def initialize(func)
|
262
|
+
super()
|
263
|
+
@func = func
|
264
|
+
end
|
265
|
+
def fill(*args)
|
266
|
+
g_down = SingleFunctionGraph.new(@func)
|
267
|
+
g_down.fill(*args)
|
268
|
+
|
269
|
+
g_up = UpperFunctionGraph.new(@func)
|
270
|
+
g_up.fill(*args)
|
271
|
+
|
272
|
+
g_down.each_edge do |u,v|
|
273
|
+
self.add_edge(u,v)
|
274
|
+
end
|
275
|
+
g_up.each_edge do |u,v|
|
276
|
+
self.add_edge(u,v)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: codegraph
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 7
|
8
|
+
- 1
|
9
|
+
version: 0.7.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Ralf Mueller
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-11-01 00:00:00 +01:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rgl
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
description: Display functional dependencies in source code (C, Fortran, PHP, Perl).
|
34
|
+
email: stark.dreamdetective@gmail.com
|
35
|
+
executables:
|
36
|
+
- codegraph
|
37
|
+
extensions: []
|
38
|
+
|
39
|
+
extra_rdoc_files: []
|
40
|
+
|
41
|
+
files:
|
42
|
+
- lib/codegraph.rb
|
43
|
+
- bin/codegraph
|
44
|
+
- gemspec
|
45
|
+
- LICENSE
|
46
|
+
has_rdoc: true
|
47
|
+
homepage: http://codegraph.rubyforge.org
|
48
|
+
licenses: []
|
49
|
+
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 0
|
70
|
+
version: "0"
|
71
|
+
requirements: []
|
72
|
+
|
73
|
+
rubyforge_project: codegraph
|
74
|
+
rubygems_version: 1.3.7
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: Display functional dependencies in source code (C, Fortran, PHP, Perl)
|
78
|
+
test_files: []
|
79
|
+
|