codegraph 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|