rgl 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +74 -0
- data/Makefile +72 -0
- data/README +240 -0
- data/Rakefile +210 -0
- data/TAGS +209 -0
- data/examples/canvas.rb +103 -0
- data/examples/codegraph +238 -0
- data/examples/example.jpg +0 -0
- data/examples/examples.rb +112 -0
- data/examples/graph.dot +54 -0
- data/examples/graph.png +0 -0
- data/examples/module_graph.jpg +0 -0
- data/examples/north.rb +12 -0
- data/examples/north/Graph.log +128 -0
- data/examples/north/g.10.0.graphml +28 -0
- data/examples/north/g.10.1.graphml +28 -0
- data/examples/north/g.10.11.graphml +31 -0
- data/examples/north/g.10.12.graphml +27 -0
- data/examples/north/g.10.13.graphml +27 -0
- data/examples/north/g.10.14.graphml +27 -0
- data/examples/north/g.10.15.graphml +26 -0
- data/examples/north/g.10.16.graphml +26 -0
- data/examples/north/g.10.17.graphml +26 -0
- data/examples/north/g.10.19.graphml +37 -0
- data/examples/north/g.10.2.graphml +28 -0
- data/examples/north/g.10.20.graphml +38 -0
- data/examples/north/g.10.22.graphml +43 -0
- data/examples/north/g.10.24.graphml +30 -0
- data/examples/north/g.10.25.graphml +45 -0
- data/examples/north/g.10.27.graphml +38 -0
- data/examples/north/g.10.28.graphml +30 -0
- data/examples/north/g.10.29.graphml +38 -0
- data/examples/north/g.10.3.graphml +26 -0
- data/examples/north/g.10.30.graphml +34 -0
- data/examples/north/g.10.31.graphml +42 -0
- data/examples/north/g.10.34.graphml +42 -0
- data/examples/north/g.10.37.graphml +28 -0
- data/examples/north/g.10.38.graphml +38 -0
- data/examples/north/g.10.39.graphml +36 -0
- data/examples/north/g.10.4.graphml +26 -0
- data/examples/north/g.10.40.graphml +37 -0
- data/examples/north/g.10.41.graphml +37 -0
- data/examples/north/g.10.42.graphml +26 -0
- data/examples/north/g.10.45.graphml +28 -0
- data/examples/north/g.10.46.graphml +32 -0
- data/examples/north/g.10.5.graphml +31 -0
- data/examples/north/g.10.50.graphml +30 -0
- data/examples/north/g.10.56.graphml +29 -0
- data/examples/north/g.10.57.graphml +32 -0
- data/examples/north/g.10.58.graphml +32 -0
- data/examples/north/g.10.6.graphml +26 -0
- data/examples/north/g.10.60.graphml +32 -0
- data/examples/north/g.10.61.graphml +34 -0
- data/examples/north/g.10.62.graphml +34 -0
- data/examples/north/g.10.68.graphml +30 -0
- data/examples/north/g.10.69.graphml +32 -0
- data/examples/north/g.10.7.graphml +29 -0
- data/examples/north/g.10.70.graphml +26 -0
- data/examples/north/g.10.71.graphml +27 -0
- data/examples/north/g.10.72.graphml +28 -0
- data/examples/north/g.10.74.graphml +29 -0
- data/examples/north/g.10.75.graphml +29 -0
- data/examples/north/g.10.78.graphml +27 -0
- data/examples/north/g.10.79.graphml +34 -0
- data/examples/north/g.10.8.graphml +29 -0
- data/examples/north/g.10.80.graphml +34 -0
- data/examples/north/g.10.82.graphml +35 -0
- data/examples/north/g.10.83.graphml +32 -0
- data/examples/north/g.10.85.graphml +34 -0
- data/examples/north/g.10.86.graphml +34 -0
- data/examples/north/g.10.88.graphml +37 -0
- data/examples/north/g.10.89.graphml +29 -0
- data/examples/north/g.10.9.graphml +26 -0
- data/examples/north/g.10.90.graphml +32 -0
- data/examples/north/g.10.91.graphml +31 -0
- data/examples/north/g.10.92.graphml +26 -0
- data/examples/north/g.10.93.graphml +32 -0
- data/examples/north/g.10.94.graphml +34 -0
- data/examples/north/g.12.8.graphml +40 -0
- data/examples/north/g.14.9.graphml +36 -0
- data/examples/north2.rb +21 -0
- data/examples/rdep-rgl.rb +395 -0
- data/install.rb +49 -0
- data/lib/rgl/adjacency.rb +151 -0
- data/lib/rgl/base.rb +299 -0
- data/lib/rgl/connected_components.rb +125 -0
- data/lib/rgl/dot.rb +63 -0
- data/lib/rgl/graphxml.rb +52 -0
- data/lib/rgl/implicit.rb +151 -0
- data/lib/rgl/mutable.rb +54 -0
- data/lib/rgl/rdot.rb +264 -0
- data/lib/rgl/topsort.rb +61 -0
- data/lib/rgl/transitiv_closure.rb +34 -0
- data/lib/rgl/traversal.rb +296 -0
- data/tests/TestComponents.rb +67 -0
- data/tests/TestDirectedGraph.rb +100 -0
- data/tests/TestEdge.rb +33 -0
- data/tests/TestGraphXML.rb +57 -0
- data/tests/TestImplicit.rb +52 -0
- data/tests/TestTransitiveClosure.rb +29 -0
- data/tests/TestTraversal.rb +222 -0
- data/tests/TestUnDirectedGraph.rb +98 -0
- metadata +163 -0
data/TAGS
ADDED
@@ -0,0 +1,209 @@
|
|
1
|
+
|
2
|
+
lib/rgl/adjacency.rb,956
|
3
|
+
module RGLRGL16,586
|
4
|
+
class DirectedAdjacencyGraphDirectedAdjacencyGraph17,597
|
5
|
+
def initialize(edgelist_class=Set)initialize33,1091
|
6
|
+
def each_vertex(&b)each_vertex39,1248
|
7
|
+
def each_adjacent(v, &b) # :nodoc:each_adjacent43,1305
|
8
|
+
def directed?; true; enddirected?49,1470
|
9
|
+
def has_vertex?(v); @vertice_dict.has_key?(v); endhas_vertex?53,1619
|
10
|
+
def has_edge? (u, v)has_edge?60,1799
|
11
|
+
def add_vertex(v)add_vertex67,1981
|
12
|
+
def add_edge (u,v)add_edge72,2080
|
13
|
+
def remove_vertex(v)remove_vertex79,2230
|
14
|
+
def remove_edge (u,v)remove_edge87,2422
|
15
|
+
def basic_add_edge(u,v)basic_add_edge93,2522
|
16
|
+
class AdjacencyGraph < DirectedAdjacencyGraphAdjacencyGraph101,2812
|
17
|
+
def directed?; false; enddirected?103,2885
|
18
|
+
def remove_edge (u,v)remove_edge106,2936
|
19
|
+
def basic_add_edge(u,v)basic_add_edge112,3044
|
20
|
+
module GraphGraph119,3143
|
21
|
+
def to_adjacencyto_adjacency122,3291
|
22
|
+
def reversereverse132,3639
|
23
|
+
def to_undirectedto_undirected144,4009
|
24
|
+
|
25
|
+
lib/rgl/base.rb,1907
|
26
|
+
module EnumerableEnumerable12,301
|
27
|
+
def inject(*argv)inject13,321
|
28
|
+
module EnumerableEnumerable41,700
|
29
|
+
def lengthlength48,892
|
30
|
+
module RGLRGL55,954
|
31
|
+
class NotDirectedError < RuntimeError; endNotDirectedError56,965
|
32
|
+
class NotUndirectedError < RuntimeError; endNotUndirectedError57,1010
|
33
|
+
class NoVertexError < IndexError; endNoVertexError59,1058
|
34
|
+
class NoEdgeError < IndexError; endNoEdgeError60,1098
|
35
|
+
module EdgeEdge65,1327
|
36
|
+
class DirectedEdgeDirectedEdge71,1651
|
37
|
+
def initialize (a,b)initialize80,1874
|
38
|
+
def eql?(edge)eql?86,2086
|
39
|
+
def reversereverse92,2216
|
40
|
+
def to_sto_s101,2504
|
41
|
+
def to_a; [source,target]; endto_a105,2589
|
42
|
+
class UnDirectedEdge < DirectedEdgeUnDirectedEdge115,2894
|
43
|
+
def eql?(edge)eql?116,2931
|
44
|
+
def hashhash120,3021
|
45
|
+
def to_s; "(#{source}=#{target})"; endto_s125,3113
|
46
|
+
module GraphGraph144,3938
|
47
|
+
def each_vertexeach_vertex151,4151
|
48
|
+
def each_adjacent (v)each_adjacent159,4401
|
49
|
+
def each_edge (&block)each_edge171,4882
|
50
|
+
def each(&block); each_vertex(&block); endeach184,5165
|
51
|
+
def directed?; false; enddirected?187,5264
|
52
|
+
def has_vertex?(v); include?(v); end # inherited from enumerablehas_vertex?192,5490
|
53
|
+
def empty?; num_vertices.zero?; endempty?197,5668
|
54
|
+
def vertices; to_a; endvertices200,5781
|
55
|
+
def edge_class; directed? ? DirectedEdge : UnDirectedEdge; endedge_class203,5871
|
56
|
+
def edgesedges207,6079
|
57
|
+
def adjacent_vertices (v)adjacent_vertices215,6239
|
58
|
+
def out_degree (v)out_degree223,6451
|
59
|
+
def size # Why not in Enumerable?size230,6560
|
60
|
+
def num_vertices; size; endnum_vertices236,6732
|
61
|
+
def num_edges; r = 0; each_edge {|u,v| r +=1}; r; endnum_edges239,6794
|
62
|
+
def to_sto_s242,6927
|
63
|
+
def each_edge_auxeach_edge_aux248,6973
|
64
|
+
module BidirectionalGraphBidirectionalGraph272,7816
|
65
|
+
def each_in_neighbor (v)each_in_neighbor279,8156
|
66
|
+
def in_degree (v)in_degree286,8359
|
67
|
+
def degree (v)degree294,8582
|
68
|
+
|
69
|
+
lib/rgl/connected_components.rb,497
|
70
|
+
module RGLRGL7,233
|
71
|
+
module GraphGraph8,244
|
72
|
+
def each_connected_componenteach_connected_component17,641
|
73
|
+
class TarjanSccVisitor < DFSVisitorTarjanSccVisitor34,1174
|
74
|
+
def initialize(g)initialize38,1314
|
75
|
+
def handle_examine_vertex(v)handle_examine_vertex48,1458
|
76
|
+
def handle_finish_vertex(v)handle_finish_vertex56,1606
|
77
|
+
def num_compnum_comp75,2151
|
78
|
+
def min_discover_time(u,v)min_discover_time81,2198
|
79
|
+
def strongly_connected_componentsstrongly_connected_components118,3687
|
80
|
+
|
81
|
+
lib/rgl/dot.rb,298
|
82
|
+
module RGLRGL10,239
|
83
|
+
module GraphGraph11,250
|
84
|
+
def to_dot_graph( params = {} )to_dot_graph15,428
|
85
|
+
def print_dotted_on (params = {}, s=$stdout)print_dotted_on35,1076
|
86
|
+
def dotty( params = {} )dotty41,1270
|
87
|
+
def write_to_graphic_file(fmt='png', dotfile="graph")write_to_graphic_file51,1530
|
88
|
+
|
89
|
+
lib/rgl/graphxml.rb,340
|
90
|
+
module RGLRGL15,594
|
91
|
+
module GraphXMLGraphXML22,893
|
92
|
+
class MutableGraphParserMutableGraphParser23,911
|
93
|
+
def initialize(graph)initialize26,992
|
94
|
+
def tag_start(name, attrs)tag_start30,1042
|
95
|
+
def MutableGraph.append_features(includingClass)append_features41,1229
|
96
|
+
def includingClass.from_graphxml (source)from_graphxml45,1350
|
97
|
+
|
98
|
+
lib/rgl/implicit.rb,681
|
99
|
+
module RGLRGL19,702
|
100
|
+
class ImplicitGraphImplicitGraph20,713
|
101
|
+
def initializeinitialize32,1102
|
102
|
+
def directed?; @directed; enddirected?40,1337
|
103
|
+
def each_vertex (&block) # :nodoc:each_vertex42,1370
|
104
|
+
def each_adjacent (v, &block) # :nodoc:each_adjacent46,1444
|
105
|
+
def each_edge (&block) # :nodoc:each_edge50,1527
|
106
|
+
def vertex_iterator (&block)vertex_iterator60,1811
|
107
|
+
def adjacent_iterator (&block)adjacent_iterator69,2127
|
108
|
+
def edge_iterator (&block)edge_iterator76,2367
|
109
|
+
module GraphGraph81,2433
|
110
|
+
def vertices_filtered_by (&filter)vertices_filtered_by105,3129
|
111
|
+
def edges_filtered_by (&filter)edges_filtered_by124,3675
|
112
|
+
def implicit_graphimplicit_graph141,4120
|
113
|
+
|
114
|
+
lib/rgl/mutable.rb,484
|
115
|
+
module RGLRGL3,20
|
116
|
+
module MutableGraphMutableGraph6,121
|
117
|
+
def add_vertex(v); raise NotImplementedError; endadd_vertex11,266
|
118
|
+
def add_edge(u, v); raise NotImplementedError; endadd_edge20,692
|
119
|
+
def add_vertices (*a)add_vertices23,790
|
120
|
+
def add_edges (*edges)add_edges30,1010
|
121
|
+
def remove_vertex(v); raise NotImplementedError; endremove_vertex39,1365
|
122
|
+
def remove_edge(u, v); raise NotImplementedError; endremove_edge46,1653
|
123
|
+
def remove_vertices (*a)remove_vertices50,1798
|
124
|
+
|
125
|
+
lib/rgl/rdot.rb,1615
|
126
|
+
module DOTDOT9,242
|
127
|
+
def change_tab( t )change_tab16,420
|
128
|
+
class DOTSimpleElementDOTSimpleElement81,1613
|
129
|
+
def initialize( params = {} )initialize84,1669
|
130
|
+
def to_sto_s88,1778
|
131
|
+
class DOTElement < DOTSimpleElementDOTElement94,1897
|
132
|
+
def initialize( params = {}, option_list = [] )initialize98,2005
|
133
|
+
def each_optioneach_option109,2419
|
134
|
+
def each_option_paireach_option_pair113,2497
|
135
|
+
class DOTPort < DOTSimpleElementDOTPort126,2856
|
136
|
+
def initialize( params = {} )initialize129,2931
|
137
|
+
def to_sto_s133,3068
|
138
|
+
class DOTNode < DOTElementDOTNode139,3200
|
139
|
+
def initialize( params = {}, option_list = NODE_OPTS )initialize142,3247
|
140
|
+
def each_porteach_port147,3424
|
141
|
+
def push ( thing )push155,3564
|
142
|
+
def poppop159,3637
|
143
|
+
def to_s( t = '' )to_s163,3689
|
144
|
+
class DOTSubgraph < DOTElementDOTSubgraph188,4604
|
145
|
+
def initialize( params = {}, option_list = GRAPH_OPTS )initialize192,4675
|
146
|
+
def each_nodeeach_node198,4887
|
147
|
+
def push( thing )push206,5034
|
148
|
+
def poppop210,5106
|
149
|
+
def to_s( t = '' )to_s214,5158
|
150
|
+
class DOTDigraph < DOTSubgraphDOTDigraph231,5663
|
151
|
+
def initialize( params = {}, option_list = GRAPH_OPTS )initialize232,5698
|
152
|
+
class DOTEdge < DOTElementDOTEdge239,5879
|
153
|
+
def initialize( params = {}, option_list = EDGE_OPTS )initialize241,5943
|
154
|
+
def edge_link; '--'; endedge_link247,6177
|
155
|
+
def to_s( t = '' )to_s248,6204
|
156
|
+
class DOTDirectedEdge < DOTEdgeDOTDirectedEdge258,6557
|
157
|
+
def edge_link; '->'; endedge_link259,6590
|
158
|
+
|
159
|
+
lib/rgl/topsort.rb,447
|
160
|
+
module RGLRGL3,25
|
161
|
+
class TopsortIteratorTopsortIterator14,503
|
162
|
+
def initialize(g)initialize16,550
|
163
|
+
def set_to_begin # :nodoc:set_to_begin21,602
|
164
|
+
def basic_forward # :nodoc:basic_forward36,924
|
165
|
+
def at_beginning?; true; end # :nodoc: FIXMEat_beginning?45,1091
|
166
|
+
def at_end?; @waiting.empty?; end # :nodoc:at_end?46,1138
|
167
|
+
module GraphGraph49,1190
|
168
|
+
def topsort_iteratortopsort_iterator51,1235
|
169
|
+
def acyclic?acyclic?57,1425
|
170
|
+
|
171
|
+
lib/rgl/transitiv_closure.rb,127
|
172
|
+
module RGLRGL9,334
|
173
|
+
module GraphGraph10,345
|
174
|
+
def transitive_closure_floyd_warshaltransitive_closure_floyd_warshal16,665
|
175
|
+
|
176
|
+
lib/rgl/traversal.rb,1708
|
177
|
+
module RGLRGL14,546
|
178
|
+
module GraphWrapper # :nodoc:GraphWrapper15,557
|
179
|
+
def initialize(graph); @graph = graph; endinitialize19,658
|
180
|
+
module GraphIteratorGraphIterator24,863
|
181
|
+
module GraphVisitorGraphVisitor59,2225
|
182
|
+
def initialize(graph)initialize64,2335
|
183
|
+
def resetreset70,2432
|
184
|
+
def finished_vertex? vfinished_vertex?75,2546
|
185
|
+
def attach_distance_map(map=Hash.new(0))attach_distance_map87,2937
|
186
|
+
def handle_tree_edge(u,v)handle_tree_edge90,3015
|
187
|
+
def distance_to_root(v)distance_to_root96,3141
|
188
|
+
def follow_edge?(u,v) # :nodoc:follow_edge?103,3261
|
189
|
+
def self.def_event_handler(m)def_event_handler108,3355
|
190
|
+
def handle_#{m}(#{params})handle_111,3446
|
191
|
+
def set_#{m}_event_handler(&b)set_114,3553
|
192
|
+
class BFSIteratorBFSIterator137,4373
|
193
|
+
def initialize(graph, start=graph.detect{|x| true})initialize143,4535
|
194
|
+
def at_beginning?; @color_map.size == 1; end # :nodoc:at_beginning?150,4727
|
195
|
+
def at_end?; @waiting.empty?; endat_end?153,4823
|
196
|
+
def set_to_beginset_to_begin156,4932
|
197
|
+
def basic_forward # :nodoc:basic_forward162,5098
|
198
|
+
def next_vertex () # :nodoc:next_vertex186,5696
|
199
|
+
module GraphGraph192,5804
|
200
|
+
def bfs_iterator (v=self.detect {|x| true})bfs_iterator194,5867
|
201
|
+
def bfs_search_tree_from(v)bfs_search_tree_from201,6151
|
202
|
+
class DFSIterator < BFSIteratorDFSIterator218,6699
|
203
|
+
def next_vertexnext_vertex219,6733
|
204
|
+
class DFSVisitorDFSVisitor235,7372
|
205
|
+
module GraphGraph241,7469
|
206
|
+
def dfs_iterator (v=self.detect {|x| true})dfs_iterator243,7532
|
207
|
+
def depth_first_search (vis = DFSVisitor.new(self),&b)depth_first_search250,7787
|
208
|
+
def depth_first_visit (u, vis = DFSVisitor.new(self), &b)depth_first_visit261,8079
|
209
|
+
def acyclic?acyclic?285,8775
|
data/examples/canvas.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# From c.l.r SNIP IT: bond TkCanvas with RubyGraphLibrary
|
2
|
+
# author: Phlip (see also
|
3
|
+
# http://www.rubygarden.org/ruby?RubyAlgorithmPackage/TkCanvasSample)
|
4
|
+
#
|
5
|
+
# put a GraphViz graph into a TkCanvas, and make nodes
|
6
|
+
# selectable. Illustrates a bug in GraphViz
|
7
|
+
|
8
|
+
require 'rgl/graphxml'
|
9
|
+
require 'rgl/adjacency'
|
10
|
+
require 'rgl/dot'
|
11
|
+
require 'tk'
|
12
|
+
|
13
|
+
include RGL
|
14
|
+
filename = ARGV[0]
|
15
|
+
puts 'Displaying ' + filename
|
16
|
+
|
17
|
+
# ruby canvas.rb north/g.10.8.graphml &
|
18
|
+
# ruby canvas.rb north/g.12.8.graphml &
|
19
|
+
# ruby canvas.rb north/g.14.9.graphml &
|
20
|
+
|
21
|
+
File.open(filename) { |file|
|
22
|
+
graph = DirectedAdjacencyGraph.from_graphxml(file)
|
23
|
+
graph.write_to_graphic_file('gif', filename)
|
24
|
+
graph.write_to_graphic_file('plain', filename)
|
25
|
+
root = TkRoot.new{title "Ex1"}
|
26
|
+
|
27
|
+
canvas = TkCanvas.new(root) {
|
28
|
+
width 400
|
29
|
+
height 600
|
30
|
+
}
|
31
|
+
canvas.pack()
|
32
|
+
ovals = []
|
33
|
+
|
34
|
+
TkcImage.new(canvas, 0, 0) {
|
35
|
+
anchor 'nw'
|
36
|
+
|
37
|
+
image TkPhotoImage.new() {
|
38
|
+
file filename + '.gif'
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
# read the 'plain' file, and for each node put an invisible
|
43
|
+
# oval over its image
|
44
|
+
|
45
|
+
File.open(filename + '.plain') { |f|
|
46
|
+
graphLine = f.readline()
|
47
|
+
graphStats = graphLine.split()
|
48
|
+
graphHeight = graphStats[3].to_f()
|
49
|
+
nodeLine = f.readline()
|
50
|
+
fields = nodeLine.split()
|
51
|
+
|
52
|
+
while fields[0] == 'node'
|
53
|
+
namer = fields[1]
|
54
|
+
|
55
|
+
# the following crud is because GraphViz has no system to
|
56
|
+
# emit a "plain" format in pixels that exactly match the
|
57
|
+
# locations of objects in dot's raster output
|
58
|
+
|
59
|
+
# furtherless, the current GraphViz seems to be centering
|
60
|
+
# the raster output but not the 'plain' output. Hence on
|
61
|
+
# g.10.8.graphml the X fudge factor must be 45. >sigh<
|
62
|
+
|
63
|
+
# YMMV, based on your system's opinion of the size of an inch
|
64
|
+
|
65
|
+
exx = fields[2].to_f * 96 - 20 # 45
|
66
|
+
why = (graphHeight - fields[3].to_f()) * 96 - 20
|
67
|
+
widt = fields[4].to_f() * 90
|
68
|
+
hite = fields[5].to_f() * 90
|
69
|
+
|
70
|
+
ov = TkcOval.new(canvas, exx, why,
|
71
|
+
exx + widt, why + hite) {
|
72
|
+
state 'hidden'
|
73
|
+
width 4
|
74
|
+
outline 'green'
|
75
|
+
tags namer
|
76
|
+
}
|
77
|
+
ovals.push(ov)
|
78
|
+
nodeLine = f.readline()
|
79
|
+
fields = nodeLine.split()
|
80
|
+
end
|
81
|
+
}
|
82
|
+
lastOval = ovals[0]
|
83
|
+
|
84
|
+
# at click time, search for an oval in range and display it
|
85
|
+
|
86
|
+
canvas.bind('Button-1') do |event|
|
87
|
+
x,y = canvas.canvasx(event.x), canvas.canvasy(event.y)
|
88
|
+
|
89
|
+
ovals.each { |r|
|
90
|
+
x1,y1,x2,y2 = r.coords()
|
91
|
+
|
92
|
+
if x >= x1 and x <= x2 and y >= y1 and y <= y2 then
|
93
|
+
lastOval.configure('state' => 'hidden')
|
94
|
+
lastOval = r
|
95
|
+
lastOval.configure('state' => 'normal')
|
96
|
+
break
|
97
|
+
end
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
Tk.mainloop
|
102
|
+
}
|
103
|
+
|
data/examples/codegraph
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'ptools'
|
3
|
+
require 'rgl/adjacency'
|
4
|
+
require 'rgl/dot'
|
5
|
+
require 'rgl/rdot'
|
6
|
+
|
7
|
+
class FunctionGraph < RGL::DirectedAdjacencyGraph
|
8
|
+
attr_accessor :command
|
9
|
+
attr_accessor :funx
|
10
|
+
attr_accessor :lines
|
11
|
+
def initialize
|
12
|
+
super
|
13
|
+
@@lines = nil
|
14
|
+
@@funx = nil
|
15
|
+
end
|
16
|
+
def genFiles(graph, filelist, lang, exclude=[])
|
17
|
+
# test if the 'tobegenerated' files already exist
|
18
|
+
if (File.exist?('all.php') or File.exist?('php-funx'))
|
19
|
+
puts "Die Dateien 'all.php' oder 'php-funx' exitieren bereits."
|
20
|
+
puts "Bitte loeschen Sie sie manuel"
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
# command to generate the necessary files
|
24
|
+
command = 'cat ' + filelist + ' | ruby -ne \' print unless /^#.*$/\' |
|
25
|
+
ruby -pe \'gsub(/#.*/," "); gsub(/".*"/,"")\' > all.php;
|
26
|
+
ctags -x --php-kinds=f all.php | sort -n -k 3 |
|
27
|
+
ruby -pe \'gsub(/ function /,"\t"); gsub(/all.php/,"\t")\' |
|
28
|
+
cut -f 1,2 |ruby -pe \'gsub(/ {2,}/,"")\' > php-funx'
|
29
|
+
system(command)
|
30
|
+
funchash = Hash.new
|
31
|
+
file = open('php-funx')
|
32
|
+
file.read.split(/\n/).each {|f|
|
33
|
+
thisfunc = f.split
|
34
|
+
funchash.store(thisfunc.last.to_i, thisfunc.first)
|
35
|
+
}
|
36
|
+
graph.lines = Array.new
|
37
|
+
graph.funx = Array.new
|
38
|
+
funchash.sort.each {|f|
|
39
|
+
next if exclude.include?(f.last)
|
40
|
+
graph.lines << f.first
|
41
|
+
graph.funx << f.last
|
42
|
+
}
|
43
|
+
$filesize = open('all.php').readlines.size
|
44
|
+
end
|
45
|
+
|
46
|
+
def fill(filelist,lang,exclude=[])
|
47
|
+
# generate the necessary files and return the size (in number of lines)
|
48
|
+
# of the file with all definitions
|
49
|
+
genFiles(self,filelist,lang,exclude)
|
50
|
+
# scan the first function
|
51
|
+
funcbody = File.middle('all.php', lines[0]+1, lines[1]-1).to_s
|
52
|
+
add_vertex(funx.first)
|
53
|
+
funx.each {|func|
|
54
|
+
if funcbody =~ /#{func} *\(/
|
55
|
+
add_func("#{funx.first}","#{func}")
|
56
|
+
end
|
57
|
+
}
|
58
|
+
# scan any other function except the last
|
59
|
+
(1...funx.size-1).each {|index|
|
60
|
+
add_vertex(funx[index])
|
61
|
+
funcbody = File.middle('all.php', lines[index]+1,lines[index+1]-1).to_s
|
62
|
+
funx.each {|func|
|
63
|
+
if funcbody =~ /#{func} *\(/
|
64
|
+
add_func("#{funx[index]}","#{func}")
|
65
|
+
end
|
66
|
+
}
|
67
|
+
}
|
68
|
+
# scan the last function
|
69
|
+
funcbody = File.middle('all.php', lines.last+1 , $filesize).to_s
|
70
|
+
add_vertex(funx.last)
|
71
|
+
funx.each {|func|
|
72
|
+
if funcbody =~ /#{func} *\(/
|
73
|
+
add_func("#{funx.last}","#{func}")
|
74
|
+
end
|
75
|
+
}
|
76
|
+
system('rm all.php php-funx')
|
77
|
+
|
78
|
+
# add fallow function's knodes
|
79
|
+
funx.each {|func|
|
80
|
+
if not has_vertex?(func)
|
81
|
+
add_edge("UNUSED CODE",func)
|
82
|
+
end
|
83
|
+
}
|
84
|
+
end
|
85
|
+
def to_ps(filename)
|
86
|
+
if File.exist?(filename)
|
87
|
+
system("rm #{filename}")
|
88
|
+
end
|
89
|
+
if File.exist?(filename+".dot")
|
90
|
+
system("rm #{filename}.dot")
|
91
|
+
end
|
92
|
+
# create dot file
|
93
|
+
params = Hash['rankdir' => 'LR',
|
94
|
+
'ranksep' => '2.0',
|
95
|
+
'concentrate' => 'TRUE',
|
96
|
+
'fontsize' => '10']
|
97
|
+
File.open("#{filename}.dot","w") {|f|
|
98
|
+
print_dotted_on(params,f)
|
99
|
+
}
|
100
|
+
system("dot -Tps -o #{filename} -Nshape=box #{filename}.dot")
|
101
|
+
end
|
102
|
+
def add_func(f,g)
|
103
|
+
add_edge(f,g)
|
104
|
+
end
|
105
|
+
def display
|
106
|
+
params = Hash['rankdir' => 'LR',
|
107
|
+
'ranksep' => '2.0',
|
108
|
+
'concentrate' => 'TRUE',
|
109
|
+
'label' => 'LCWA',
|
110
|
+
'fontsize' => '12']
|
111
|
+
dotty(params)
|
112
|
+
end
|
113
|
+
private :genFiles
|
114
|
+
end
|
115
|
+
|
116
|
+
class SingleFunctionGraph < FunctionGraph
|
117
|
+
attr_accessor :func
|
118
|
+
def initialize(func)
|
119
|
+
@func = func
|
120
|
+
super()
|
121
|
+
end
|
122
|
+
def fill(filelist,lang,exclude=[])
|
123
|
+
genFiles(self,filelist,lang,exclude)
|
124
|
+
$scannedfunx = Array.new
|
125
|
+
scan(self, func)
|
126
|
+
system('rm all.php php-funx')
|
127
|
+
end
|
128
|
+
def scan(graph, f)
|
129
|
+
if ($scannedfunx.include?(f))
|
130
|
+
else
|
131
|
+
$scannedfunx << f
|
132
|
+
beginbody = graph.lines[graph.funx.index(f)]+1
|
133
|
+
if (graph.lines.size <= graph.funx.index(f)+1)
|
134
|
+
endbody = $filesize
|
135
|
+
else
|
136
|
+
endbody = graph.lines[graph.funx.index(f)+1]-1
|
137
|
+
end
|
138
|
+
fbody = File.middle('all.php', beginbody, endbody).to_s
|
139
|
+
graph.funx.each {|g|
|
140
|
+
if fbody =~ /#{g} *\(/
|
141
|
+
graph.add_func(f,g)
|
142
|
+
scan(graph,g)
|
143
|
+
end
|
144
|
+
}
|
145
|
+
end
|
146
|
+
end
|
147
|
+
private :scan
|
148
|
+
end
|
149
|
+
|
150
|
+
# main script #################################################################
|
151
|
+
require 'getoptlong'
|
152
|
+
|
153
|
+
def show_usage
|
154
|
+
puts <<-END
|
155
|
+
Usage: #{__FILE__}: --help guess what
|
156
|
+
|
157
|
+
--source, -s take every $IMPSRC/lcwa/web_interface/*inc.php file
|
158
|
+
to search in
|
159
|
+
--local, -l take every $(pwd)/*.inc.php file for scanning
|
160
|
+
|
161
|
+
--file-list, -F "<list>"
|
162
|
+
fill the graph with every function,
|
163
|
+
that has a definiton inside the given files
|
164
|
+
|
165
|
+
--function, -f <funcname>
|
166
|
+
take the given func as the root knode
|
167
|
+
--exclude, -x "<list>"
|
168
|
+
exclude a list of functions from the graph
|
169
|
+
--to-ps, -p <filename>
|
170
|
+
create a postscript file from the graph
|
171
|
+
END
|
172
|
+
end
|
173
|
+
# option setting ---------------------------------------------------------------
|
174
|
+
options = GetoptLong.new(
|
175
|
+
['--help', '-h', GetoptLong::NO_ARGUMENT],
|
176
|
+
['--local', '-l', GetoptLong::NO_ARGUMENT],
|
177
|
+
['--source', '-s', GetoptLong::NO_ARGUMENT],
|
178
|
+
['--function', '-f', GetoptLong::REQUIRED_ARGUMENT],
|
179
|
+
['--file-list', '-F', GetoptLong::REQUIRED_ARGUMENT],
|
180
|
+
['--to-ps', '-p', GetoptLong::REQUIRED_ARGUMENT],
|
181
|
+
['--exclude', '-x', GetoptLong::REQUIRED_ARGUMENT]
|
182
|
+
)
|
183
|
+
options.ordering = GetoptLong::RETURN_IN_ORDER
|
184
|
+
# the default options ----------------------------------------------------------
|
185
|
+
filelist = ''
|
186
|
+
mode = 'multiple'
|
187
|
+
createPS = false
|
188
|
+
filename = ''
|
189
|
+
function = ''
|
190
|
+
exclude = Array.new
|
191
|
+
spaces = Array.new
|
192
|
+
# option parsing ---------------------------------------------------------------
|
193
|
+
options.each do |opt, arg|
|
194
|
+
case opt
|
195
|
+
when '--local'
|
196
|
+
filelist = './*inc.php'
|
197
|
+
spaces << filelist
|
198
|
+
when '--source'
|
199
|
+
filelist = '$IMPSRC/lcwa/web_interface/*inc.php'
|
200
|
+
spaces << filelist
|
201
|
+
when '--file-list'
|
202
|
+
filelist = arg
|
203
|
+
spaces << filelist
|
204
|
+
when '--function'
|
205
|
+
mode = 'single'
|
206
|
+
function = arg
|
207
|
+
when '--to-ps'
|
208
|
+
createPS = true
|
209
|
+
filename = arg
|
210
|
+
when '--exclude'
|
211
|
+
exclude = arg.split(/ /)
|
212
|
+
else
|
213
|
+
show_usage
|
214
|
+
exit
|
215
|
+
end
|
216
|
+
end
|
217
|
+
options.terminate
|
218
|
+
# script controlling ###########################################################
|
219
|
+
case mode
|
220
|
+
when 'single'
|
221
|
+
g = SingleFunctionGraph.new(function)
|
222
|
+
else
|
223
|
+
g = FunctionGraph.new
|
224
|
+
end
|
225
|
+
case spaces.size
|
226
|
+
when 1
|
227
|
+
g.fill(filelist,'php',exclude)
|
228
|
+
else
|
229
|
+
puts "Benutzen Sie entweder --local, --source oder --file-list <list>"
|
230
|
+
show_usage
|
231
|
+
exit
|
232
|
+
end
|
233
|
+
case createPS
|
234
|
+
when true
|
235
|
+
g.to_ps(filename)
|
236
|
+
else
|
237
|
+
g.display
|
238
|
+
end
|