ruby-graphviz 0.9.16 → 0.9.17
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +1 -0
- data/README.rdoc +64 -0
- data/examples/graphml/attributes.ext.graphml +12 -0
- data/examples/graphml/attributes.graphml +40 -0
- data/examples/graphml/cluster.graphml +75 -0
- data/examples/graphml/hyper.graphml +29 -0
- data/examples/graphml/nested.graphml +54 -0
- data/examples/graphml/port.graphml +32 -0
- data/examples/graphml/simple.graphml +30 -0
- data/examples/sample57.rb +6 -0
- data/examples/theory/PERT.png +0 -0
- data/examples/theory/matrix.png +0 -0
- data/examples/theory/pert.rb +47 -0
- data/examples/theory/tests.rb +81 -0
- data/lib/graphviz.rb +45 -8
- data/lib/graphviz/constants.rb +43 -40
- data/lib/graphviz/edge.rb +22 -5
- data/lib/graphviz/elements.rb +39 -0
- data/lib/graphviz/graphml.rb +218 -0
- data/lib/graphviz/math/matrix.rb +221 -0
- data/lib/graphviz/node.rb +11 -0
- data/lib/graphviz/theory.rb +252 -0
- data/lib/graphviz/types.rb +4 -0
- data/lib/graphviz/types/gv_double.rb +20 -0
- metadata +24 -4
data/lib/graphviz.rb
CHANGED
@@ -25,6 +25,7 @@ require 'graphviz/node'
|
|
25
25
|
require 'graphviz/edge'
|
26
26
|
require 'graphviz/attrs'
|
27
27
|
require 'graphviz/constants'
|
28
|
+
require 'graphviz/elements'
|
28
29
|
|
29
30
|
require 'graphviz/dot2ruby'
|
30
31
|
require 'graphviz/types'
|
@@ -93,7 +94,8 @@ class GraphViz
|
|
93
94
|
#
|
94
95
|
def add_node( xNodeName, hOpts = {} )
|
95
96
|
@hoNodes[xNodeName] = GraphViz::Node::new( xNodeName, self )
|
96
|
-
|
97
|
+
@hoNodes[xNodeName].index = @elements_order.size_of( "node" )
|
98
|
+
|
97
99
|
unless hOpts.keys.include?(:label) or hOpts.keys.include?("label")
|
98
100
|
hOpts[:label] = xNodeName
|
99
101
|
end
|
@@ -122,12 +124,24 @@ class GraphViz
|
|
122
124
|
return node
|
123
125
|
end
|
124
126
|
|
127
|
+
#
|
128
|
+
# Return the node object for the given index
|
129
|
+
#
|
130
|
+
def get_node_at_index( index )
|
131
|
+
element = @elements_order[index, "node"]
|
132
|
+
(element.nil?) ? nil : element["value"]
|
133
|
+
end
|
134
|
+
|
125
135
|
#
|
126
136
|
# Allow you to traverse nodes
|
127
137
|
#
|
128
138
|
def each_node( &block )
|
129
|
-
|
130
|
-
|
139
|
+
if block_given?
|
140
|
+
@hoNodes.each do |name, node|
|
141
|
+
yield( name, node )
|
142
|
+
end
|
143
|
+
else
|
144
|
+
return( @hoNodes )
|
131
145
|
end
|
132
146
|
end
|
133
147
|
|
@@ -159,6 +173,7 @@ class GraphViz
|
|
159
173
|
end
|
160
174
|
else
|
161
175
|
oEdge = GraphViz::Edge::new( oNodeOne, oNodeTwo, self )
|
176
|
+
oEdge.index = @elements_order.size_of( "edge" )
|
162
177
|
|
163
178
|
hOpts.each do |xKey, xValue|
|
164
179
|
oEdge[xKey.to_s] = xValue
|
@@ -179,8 +194,12 @@ class GraphViz
|
|
179
194
|
# Allow you to traverse edges
|
180
195
|
#
|
181
196
|
def each_edge( &block )
|
182
|
-
|
183
|
-
|
197
|
+
if block_given?
|
198
|
+
@loEdges.each do |edge|
|
199
|
+
yield(edge)
|
200
|
+
end
|
201
|
+
else
|
202
|
+
return @loEdges
|
184
203
|
end
|
185
204
|
end
|
186
205
|
|
@@ -191,6 +210,14 @@ class GraphViz
|
|
191
210
|
@loEdges.size
|
192
211
|
end
|
193
212
|
|
213
|
+
#
|
214
|
+
# Return the edge object for the given index
|
215
|
+
#
|
216
|
+
def get_edge_at_index( index )
|
217
|
+
element = @elements_order[index, "edge"]
|
218
|
+
(element.nil?) ? nil : element["value"]
|
219
|
+
end
|
220
|
+
|
194
221
|
#
|
195
222
|
# Create a new graph
|
196
223
|
#
|
@@ -241,11 +268,21 @@ class GraphViz
|
|
241
268
|
# Allow you to traverse graphs
|
242
269
|
#
|
243
270
|
def each_graph( &block )
|
244
|
-
|
245
|
-
|
271
|
+
if block_given?
|
272
|
+
@hoGraphs.each do |name, graph|
|
273
|
+
yield( name, graph )
|
274
|
+
end
|
275
|
+
else
|
276
|
+
return @hoGraphs
|
246
277
|
end
|
247
278
|
end
|
248
279
|
|
280
|
+
#
|
281
|
+
# Return the graph type (graph digraph)
|
282
|
+
def type
|
283
|
+
@oGraphType
|
284
|
+
end
|
285
|
+
|
249
286
|
#
|
250
287
|
# Get the number of graphs
|
251
288
|
#
|
@@ -669,7 +706,7 @@ class GraphViz
|
|
669
706
|
@output = {}
|
670
707
|
@nothugly = false
|
671
708
|
|
672
|
-
@elements_order =
|
709
|
+
@elements_order = GraphViz::Elements::new()
|
673
710
|
|
674
711
|
@oParentGraph = nil
|
675
712
|
@oGraphType = "digraph"
|
data/lib/graphviz/constants.rb
CHANGED
@@ -40,7 +40,7 @@
|
|
40
40
|
# C => cluster
|
41
41
|
#
|
42
42
|
module Constants
|
43
|
-
RGV_VERSION = "0.9.
|
43
|
+
RGV_VERSION = "0.9.17"
|
44
44
|
|
45
45
|
## Const: Output formats
|
46
46
|
FORMATS = [
|
@@ -96,7 +96,8 @@ module Constants
|
|
96
96
|
"neato",
|
97
97
|
"twopi",
|
98
98
|
"fdp",
|
99
|
-
"circo"
|
99
|
+
"circo",
|
100
|
+
"sfdp"
|
100
101
|
]
|
101
102
|
|
102
103
|
## Const: graphs type
|
@@ -115,11 +116,11 @@ module Constants
|
|
115
116
|
|
116
117
|
# E, N, G, S and C represent edges, nodes, the root graph, subgraphs and cluster subgraphs, respectively
|
117
118
|
GENCS_ATTRS = {
|
118
|
-
"Damping" => { :usedBy => "G", :type => :
|
119
|
-
"K" => { :usedBy => "GC", :type => :
|
119
|
+
"Damping" => { :usedBy => "G", :type => :GvDouble },
|
120
|
+
"K" => { :usedBy => "GC", :type => :GvDouble },
|
120
121
|
"URL" => { :usedBy => "ENGC", :type => :EscString },
|
121
122
|
"arrowhead" => { :usedBy => "E", :type => :EscString },
|
122
|
-
"arrowsize" => { :usedBy => "E", :type => :
|
123
|
+
"arrowsize" => { :usedBy => "E", :type => :GvDouble },
|
123
124
|
"arrowtail" => { :usedBy => "E", :type => :EscString },
|
124
125
|
"aspect" => { :usedBy => "G", :type => :EscString },
|
125
126
|
"bb" => { :usedBy => "G", :type => :EscString },
|
@@ -134,26 +135,26 @@ module Constants
|
|
134
135
|
"concentrate" => { :usedBy => "G", :type => :EscString },
|
135
136
|
"constraint" => { :usedBy => "E", :type => :EscString },
|
136
137
|
"decorate" => { :usedBy => "E", :type => :EscString },
|
137
|
-
"defaultdist" => { :usedBy => "G", :type => :
|
138
|
+
"defaultdist" => { :usedBy => "G", :type => :GvDouble },
|
138
139
|
"dim" => { :usedBy => "G", :type => :EscString },
|
139
140
|
"dimen" => { :usedBy => "G", :type => :EscString },
|
140
141
|
"dir" => { :usedBy => "E", :type => :EscString },
|
141
142
|
"diredgeconstraints" => { :usedBy => "G", :type => :EscString },
|
142
|
-
"distortion" => { :usedBy => "N", :type => :
|
143
|
-
"dpi" => { :usedBy => "G", :type => :
|
143
|
+
"distortion" => { :usedBy => "N", :type => :GvDouble },
|
144
|
+
"dpi" => { :usedBy => "G", :type => :GvDouble },
|
144
145
|
"edgeURL" => { :usedBy => "E", :type => :EscString },
|
145
146
|
"edgehref" => { :usedBy => "E", :type => :EscString },
|
146
147
|
"edgetarget" => { :usedBy => "E", :type => :EscString },
|
147
148
|
"edgetooltip" => { :usedBy => "E", :type => :EscString },
|
148
|
-
"epsilon" => { :usedBy => "G", :type => :
|
149
|
-
"esep" => { :usedBy => "G", :type => :EscString },
|
149
|
+
"epsilon" => { :usedBy => "G", :type => :GvDouble },
|
150
|
+
"esep" => { :usedBy => "G", :type => :EscString }, # GvDouble , pointf
|
150
151
|
"fillcolor" => { :usedBy => "NC", :type => :EscString },
|
151
152
|
"fixedsize" => { :usedBy => "N", :type => :EscString },
|
152
153
|
"fontcolor" => { :usedBy => "ENGC", :type => :EscString },
|
153
154
|
"fontname" => { :usedBy => "ENGC", :type => :EscString },
|
154
155
|
"fontnames" => { :usedBy => "G", :type => :EscString },
|
155
156
|
"fontpath" => { :usedBy => "G", :type => :EscString },
|
156
|
-
"fontsize" => { :usedBy => "ENGC", :type => :
|
157
|
+
"fontsize" => { :usedBy => "ENGC", :type => :GvDouble },
|
157
158
|
"group" => { :usedBy => "N", :type => :EscString },
|
158
159
|
"headURL" => { :usedBy => "E", :type => :EscString },
|
159
160
|
"headclip" => { :usedBy => "E", :type => :EscString },
|
@@ -162,7 +163,7 @@ module Constants
|
|
162
163
|
"headport" => { :usedBy => "E", :type => :EscString },
|
163
164
|
"headtarget" => { :usedBy => "E", :type => :EscString },
|
164
165
|
"headtooltip" => { :usedBy => "E", :type => :EscString },
|
165
|
-
"height" => { :usedBy => "N", :type => :
|
166
|
+
"height" => { :usedBy => "N", :type => :GvDouble },
|
166
167
|
"href" => { :usedBy => "NE", :type => :EscString },
|
167
168
|
"html" => { :usedBy => "N", :type => :HtmlString }, # API extension -- Deprecated
|
168
169
|
"id" => { :usedBy => "ENG", :type => :EscString },
|
@@ -170,12 +171,12 @@ module Constants
|
|
170
171
|
"imagescale" => { :usedBy => "N", :type => :EscString },
|
171
172
|
"label" => { :usedBy => "ENGC", :type => :LblString },
|
172
173
|
"labelURL" => { :usedBy => "E", :type => :EscString },
|
173
|
-
"labelangle" => { :usedBy => "E", :type => :
|
174
|
-
"labeldistance" => { :usedBy => "E", :type => :
|
174
|
+
"labelangle" => { :usedBy => "E", :type => :GvDouble },
|
175
|
+
"labeldistance" => { :usedBy => "E", :type => :GvDouble },
|
175
176
|
"labelfloat" => { :usedBy => "E", :type => :EscString },
|
176
177
|
"labelfontcolor" => { :usedBy => "E", :type => :EscString },
|
177
178
|
"labelfontname" => { :usedBy => "E", :type => :EscString },
|
178
|
-
"labelfontsize" => { :usedBy => "E", :type => :
|
179
|
+
"labelfontsize" => { :usedBy => "E", :type => :GvDouble },
|
179
180
|
"labelhref" => { :usedBy => "E", :type => :EscString },
|
180
181
|
"labeljust" => { :usedBy => "GC", :type => :EscString },
|
181
182
|
"labelloc" => { :usedBy => "GCN", :type => :EscString },
|
@@ -186,64 +187,66 @@ module Constants
|
|
186
187
|
"layers" => { :usedBy => "G", :type => :EscString },
|
187
188
|
"layersep" => { :usedBy => "G", :type => :EscString },
|
188
189
|
"layout" => { :usedBy => "G", :type => :EscString },
|
189
|
-
"len" => { :usedBy => "E", :type => :
|
190
|
+
"len" => { :usedBy => "E", :type => :GvDouble },
|
190
191
|
"levels" => { :usedBy => "G", :type => :EscString },
|
191
|
-
"levelsgap" => { :usedBy => "G", :type => :
|
192
|
+
"levelsgap" => { :usedBy => "G", :type => :GvDouble },
|
192
193
|
"lhead" => { :usedBy => "E", :type => :EscString },
|
194
|
+
"lheight" => { :usedBy => "GC", :type => :GvDouble },
|
193
195
|
"lp" => { :usedBy => "EGC", :type => :EscString },
|
194
196
|
"ltail" => { :usedBy => "E", :type => :EscString },
|
195
|
-
"
|
197
|
+
"lweight" => { :usedBy => "GC", :type => :GvDouble },
|
198
|
+
"margin" => { :usedBy => "NG", :type => :EscString }, # GvDouble , pointf
|
196
199
|
"maxiter" => { :usedBy => "G", :type => :EscString },
|
197
|
-
"mclimit" => { :usedBy => "G", :type => :
|
198
|
-
"mindist" => { :usedBy => "G", :type => :
|
200
|
+
"mclimit" => { :usedBy => "G", :type => :GvDouble },
|
201
|
+
"mindist" => { :usedBy => "G", :type => :GvDouble },
|
199
202
|
"minlen" => { :usedBy => "E", :type => :EscString },
|
200
203
|
"mode" => { :usedBy => "G", :type => :EscString },
|
201
204
|
"model" => { :usedBy => "G", :type => :EscString },
|
202
205
|
"mosek" => { :usedBy => "G", :type => :EscString },
|
203
|
-
"nodesep" => { :usedBy => "G", :type => :
|
206
|
+
"nodesep" => { :usedBy => "G", :type => :GvDouble },
|
204
207
|
"nojustify" => { :usedBy => "GCNE", :type => :EscString },
|
205
208
|
"normalize" => { :usedBy => "G", :type => :EscString },
|
206
|
-
"nslimit" => { :usedBy => "G", :type => :
|
207
|
-
"nslimit1" => { :usedBy => "G", :type => :
|
209
|
+
"nslimit" => { :usedBy => "G", :type => :GvDouble },
|
210
|
+
"nslimit1" => { :usedBy => "G", :type => :GvDouble },
|
208
211
|
"ordering" => { :usedBy => "G", :type => :EscString },
|
209
|
-
"orientation" => { :usedBy => "NG", :type => :
|
212
|
+
"orientation" => { :usedBy => "NG", :type => :GvDouble },
|
210
213
|
"outputorder" => { :usedBy => "G", :type => :EscString },
|
211
214
|
"overlap" => { :usedBy => "G", :type => :EscString },
|
212
|
-
"overlap_scaling" => { :usedBy => "G", :type => :
|
215
|
+
"overlap_scaling" => { :usedBy => "G", :type => :GvDouble },
|
213
216
|
"pack" => { :usedBy => "G", :type => :EscString },
|
214
217
|
"packmode" => { :usedBy => "G", :type => :EscString },
|
215
|
-
"pad" => { :usedBy => "G", :type => :EscString },
|
216
|
-
"page" => { :usedBy => "G", :type => :EscString },
|
218
|
+
"pad" => { :usedBy => "G", :type => :EscString }, # GvDouble , pointf
|
219
|
+
"page" => { :usedBy => "G", :type => :EscString }, # GvDouble , pointf
|
217
220
|
"pagedir" => { :usedBy => "G", :type => :EscString },
|
218
221
|
"pencolor" => { :usedBy => "C", :type => :EscString },
|
219
|
-
"penwidth" => { :usedBy => "CNE", :type => :
|
222
|
+
"penwidth" => { :usedBy => "CNE", :type => :GvDouble },
|
220
223
|
"peripheries" => { :usedBy => "NC", :type => :EscString },
|
221
224
|
"pin" => { :usedBy => "N", :type => :EscString },
|
222
225
|
"pos" => { :usedBy => "EN", :type => :EscString },
|
223
226
|
"quadtree" => { :usedBy => "G", :type => :EscString },
|
224
|
-
"quantum" => { :usedBy => "G", :type => :
|
227
|
+
"quantum" => { :usedBy => "G", :type => :GvDouble },
|
225
228
|
"rank" => { :usedBy => "S", :type => :EscString },
|
226
229
|
"rankdir" => { :usedBy => "G", :type => :EscString },
|
227
|
-
"ranksep" => { :usedBy => "G", :type => :EscString },
|
228
|
-
"ratio" => { :usedBy => "G", :type => :EscString },
|
230
|
+
"ranksep" => { :usedBy => "G", :type => :EscString }, # GvDouble, doubleList
|
231
|
+
"ratio" => { :usedBy => "G", :type => :EscString }, # GvDouble, String
|
229
232
|
"rects" => { :usedBy => "N", :type => :EscString },
|
230
233
|
"regular" => { :usedBy => "N", :type => :EscString },
|
231
234
|
"remincross" => { :usedBy => "G", :type => :EscString },
|
232
|
-
"repulsiveforce" => { :usedBy => "G", :type => :
|
233
|
-
"resolution" => { :usedBy => "G", :type => :
|
235
|
+
"repulsiveforce" => { :usedBy => "G", :type => :GvDouble },
|
236
|
+
"resolution" => { :usedBy => "G", :type => :GvDouble },
|
234
237
|
"root" => { :usedBy => "GN", :type => :EscString },
|
235
238
|
"rotate" => { :usedBy => "G", :type => :EscString },
|
236
239
|
"samehead" => { :usedBy => "E", :type => :EscString },
|
237
240
|
"sametail" => { :usedBy => "E", :type => :EscString },
|
238
241
|
"samplepoints" => { :usedBy => "G", :type => :EscString },
|
239
242
|
"searchsize" => { :usedBy => "G", :type => :EscString },
|
240
|
-
"sep" => { :usedBy => "G", :type => :EscString },
|
243
|
+
"sep" => { :usedBy => "G", :type => :EscString }, # GvDouble , pointf
|
241
244
|
"shape" => { :usedBy => "N", :type => :EscString },
|
242
245
|
"shapefile" => { :usedBy => "N", :type => :EscString },
|
243
246
|
"showboxes" => { :usedBy => "ENG", :type => :EscString },
|
244
247
|
"sides" => { :usedBy => "N", :type => :EscString },
|
245
|
-
"size" => { :usedBy => "NG", :type => :EscString },
|
246
|
-
"skew" => { :usedBy => "N", :type => :
|
248
|
+
"size" => { :usedBy => "NG", :type => :EscString }, # GvDouble , pointf
|
249
|
+
"skew" => { :usedBy => "N", :type => :GvDouble },
|
247
250
|
"smoothing" => { :usedBy => "G", :type => :EscString },
|
248
251
|
"sortv" => { :usedBy => "GCN", :type => :EscString },
|
249
252
|
"splines" => { :usedBy => "G", :type => :EscString },
|
@@ -262,10 +265,10 @@ module Constants
|
|
262
265
|
"truecolor" => { :usedBy => "G", :type => :EscString },
|
263
266
|
"vertices" => { :usedBy => "N", :type => :EscString },
|
264
267
|
"viewport" => { :usedBy => "G", :type => :EscString },
|
265
|
-
"voro_margin" => { :usedBy => "G", :type => :
|
266
|
-
"weight" => { :usedBy => "E", :type => :
|
267
|
-
"width" => { :usedBy => "N", :type => :
|
268
|
-
"z" => { :usedBy => "N", :type => :
|
268
|
+
"voro_margin" => { :usedBy => "G", :type => :GvDouble },
|
269
|
+
"weight" => { :usedBy => "E", :type => :GvDouble },
|
270
|
+
"width" => { :usedBy => "N", :type => :GvDouble },
|
271
|
+
"z" => { :usedBy => "N", :type => :GvDouble }
|
269
272
|
}
|
270
273
|
|
271
274
|
## Const: Graph attributs
|
data/lib/graphviz/edge.rb
CHANGED
@@ -52,11 +52,13 @@ class GraphViz
|
|
52
52
|
@oGParrent = oGParrent
|
53
53
|
|
54
54
|
@oAttrEdge = GraphViz::Attrs::new( nil, "edge", EDGESATTRS )
|
55
|
+
|
56
|
+
@index = nil
|
55
57
|
end
|
56
58
|
|
57
59
|
# Return the node one as string (so with port if any)
|
58
|
-
def node_one
|
59
|
-
if @xNodeOnePort.nil?
|
60
|
+
def node_one( with_port = true )
|
61
|
+
if @xNodeOnePort.nil? or with_port == false
|
60
62
|
GraphViz.escape(@xNodeOne)
|
61
63
|
else
|
62
64
|
GraphViz.escape(@xNodeOne, true) + ":#{@xNodeOnePort}"
|
@@ -64,14 +66,24 @@ class GraphViz
|
|
64
66
|
end
|
65
67
|
|
66
68
|
# Return the node two as string (so with port if any)
|
67
|
-
def node_two
|
68
|
-
if @xNodeTwoPort.nil?
|
69
|
+
def node_two( with_port = true )
|
70
|
+
if @xNodeTwoPort.nil? or with_port == false
|
69
71
|
GraphViz.escape(@xNodeTwo)
|
70
72
|
else
|
71
73
|
GraphViz.escape(@xNodeTwo, true) + ":#{@xNodeTwoPort}"
|
72
74
|
end
|
73
75
|
end
|
74
76
|
|
77
|
+
#
|
78
|
+
# Return the index of the edge
|
79
|
+
#
|
80
|
+
def index
|
81
|
+
@index
|
82
|
+
end
|
83
|
+
def index=(i) #:nodoc:
|
84
|
+
@index = i if @index == nil
|
85
|
+
end
|
86
|
+
|
75
87
|
#
|
76
88
|
# Set value +xAttrValue+ to the edge attribut +xAttrName+
|
77
89
|
#
|
@@ -91,7 +103,11 @@ class GraphViz
|
|
91
103
|
self[key] = value
|
92
104
|
end
|
93
105
|
else
|
94
|
-
@oAttrEdge[xAttrName.to_s]
|
106
|
+
if @oAttrEdge[xAttrName.to_s]
|
107
|
+
@oAttrEdge[xAttrName.to_s].clone
|
108
|
+
else
|
109
|
+
nil
|
110
|
+
end
|
95
111
|
end
|
96
112
|
end
|
97
113
|
|
@@ -122,6 +138,7 @@ class GraphViz
|
|
122
138
|
# Add edge options
|
123
139
|
# use edge.<option>=<value> or edge.<option>( <value> )
|
124
140
|
def method_missing( idName, *args, &block ) #:nodoc:
|
141
|
+
return if idName == :to_ary # ruby 1.9.2 fix
|
125
142
|
xName = idName.id2name
|
126
143
|
|
127
144
|
self[xName.gsub( /=$/, "" )]=args[0]
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class GraphViz
|
2
|
+
class Elements
|
3
|
+
def initialize
|
4
|
+
@elements = Array.new
|
5
|
+
@elements_hash_by_type = Hash.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def push( obj )
|
9
|
+
@elements.push( obj )
|
10
|
+
if @elements_hash_by_type[obj['type']].nil?
|
11
|
+
@elements_hash_by_type[obj['type']] = Array.new
|
12
|
+
end
|
13
|
+
|
14
|
+
@elements_hash_by_type[obj['type']].push( obj )
|
15
|
+
end
|
16
|
+
|
17
|
+
def each( &b )
|
18
|
+
@elements.each do |e|
|
19
|
+
yield( e )
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def size_of( type )
|
24
|
+
if @elements_hash_by_type[type].nil?
|
25
|
+
return 0
|
26
|
+
else
|
27
|
+
return @elements_hash_by_type[type].size
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def []( index, type = nil )
|
32
|
+
if type.nil?
|
33
|
+
return @elements[index]
|
34
|
+
else
|
35
|
+
return @elements_hash_by_type[type][index]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,218 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Copyright (C) 2010 Gregoire Lejeune <gregoire.lejeune@free.fr>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
|
+
|
18
|
+
require 'graphviz'
|
19
|
+
require 'rexml/document'
|
20
|
+
|
21
|
+
class GraphViz
|
22
|
+
class GraphML
|
23
|
+
attr_reader :attributs
|
24
|
+
attr_accessor :graph
|
25
|
+
|
26
|
+
DEST = {
|
27
|
+
'node' => [:nodes],
|
28
|
+
'edge' => [:edges],
|
29
|
+
'graph' => [:graphs],
|
30
|
+
'all' => [:nodes, :edges, :graphs]
|
31
|
+
}
|
32
|
+
|
33
|
+
GTYPE = {
|
34
|
+
'directed' => :digraph,
|
35
|
+
'undirected' => :graph
|
36
|
+
}
|
37
|
+
|
38
|
+
def initialize( xFile )
|
39
|
+
@xmlDoc = REXML::Document::new( File::new( xFile ) )
|
40
|
+
@attributs = {
|
41
|
+
:nodes => {},
|
42
|
+
:edges => {},
|
43
|
+
:graphs => {}
|
44
|
+
}
|
45
|
+
@graph = nil
|
46
|
+
@current_attr = nil
|
47
|
+
@current_node = nil
|
48
|
+
@current_edge = nil
|
49
|
+
@current_graph = nil
|
50
|
+
|
51
|
+
parse( @xmlDoc.root )
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse( node )
|
55
|
+
#begin
|
56
|
+
send( node.name.to_sym, node )
|
57
|
+
#rescue NoMethodError => e
|
58
|
+
# raise "ERROR node #{node.name} can be root"
|
59
|
+
#end
|
60
|
+
end
|
61
|
+
|
62
|
+
def graphml( node )
|
63
|
+
node.each_element( ) do |child|
|
64
|
+
#begin
|
65
|
+
send( "graphml_#{child.name}".to_sym, child )
|
66
|
+
#rescue NoMethodError => e
|
67
|
+
# raise "ERROR node #{child.name} can be child of graphml"
|
68
|
+
#end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def graphml_key( node )
|
73
|
+
id = node.attributes['id']
|
74
|
+
@current_attr = {
|
75
|
+
:name => node.attributes['attr.name'],
|
76
|
+
:type => node.attributes['attr.type']
|
77
|
+
}
|
78
|
+
DEST[node.attributes['for']].each do |d|
|
79
|
+
@attributs[d][id] = @current_attr
|
80
|
+
end
|
81
|
+
|
82
|
+
node.each_element( ) do |child|
|
83
|
+
begin
|
84
|
+
send( "graphml_key_#{child.name}".to_sym, child )
|
85
|
+
rescue NoMethodError => e
|
86
|
+
raise "ERROR node #{child.name} can be child of graphml"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
@current_attr = nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def graphml_key_default( node )
|
94
|
+
@current_attr[:default] = node.texts().to_s
|
95
|
+
end
|
96
|
+
|
97
|
+
def graphml_graph( node )
|
98
|
+
@current_node = nil
|
99
|
+
|
100
|
+
if @current_graph.nil?
|
101
|
+
@graph = GraphViz.new( node.attributes['id'], :type => GTYPE[node.attributes['edgedefault']] )
|
102
|
+
@current_graph = @graph
|
103
|
+
previous_graph = @graph
|
104
|
+
else
|
105
|
+
previous_graph = @current_graph
|
106
|
+
@current_graph = previous_graph.add_graph( node.attributes['id'] )
|
107
|
+
end
|
108
|
+
|
109
|
+
@attributs[:graphs].each do |id, data|
|
110
|
+
@current_graph.graph[data[:name]] = data[:default] if data.has_key?(:default)
|
111
|
+
end
|
112
|
+
@attributs[:nodes].each do |id, data|
|
113
|
+
@current_graph.node[data[:name]] = data[:default] if data.has_key?(:default)
|
114
|
+
end
|
115
|
+
@attributs[:edges].each do |id, data|
|
116
|
+
@current_graph.edge[data[:name]] = data[:default] if data.has_key?(:default)
|
117
|
+
end
|
118
|
+
|
119
|
+
node.each_element( ) do |child|
|
120
|
+
#begin
|
121
|
+
send( "graphml_graph_#{child.name}".to_sym, child )
|
122
|
+
#rescue NoMethodError => e
|
123
|
+
# raise "ERROR node #{child.name} can be child of graphml"
|
124
|
+
#end
|
125
|
+
end
|
126
|
+
|
127
|
+
@current_graph = previous_graph
|
128
|
+
end
|
129
|
+
|
130
|
+
def graphml_graph_data( node )
|
131
|
+
@current_graph[@attributs[:graphs][node.attributes['key']][:name]] = node.texts().to_s
|
132
|
+
end
|
133
|
+
|
134
|
+
def graphml_graph_node( node )
|
135
|
+
@current_node = {}
|
136
|
+
|
137
|
+
node.each_element( ) do |child|
|
138
|
+
case child.name
|
139
|
+
when "graph"
|
140
|
+
graphml_graph( child )
|
141
|
+
else
|
142
|
+
begin
|
143
|
+
send( "graphml_graph_node_#{child.name}".to_sym, child )
|
144
|
+
rescue NoMethodError => e
|
145
|
+
raise "ERROR node #{child.name} can be child of graphml"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
unless @current_node.nil?
|
151
|
+
node = @current_graph.add_node( node.attributes['id'] )
|
152
|
+
@current_node.each do |k, v|
|
153
|
+
node[k] = v
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
@current_node = nil
|
158
|
+
end
|
159
|
+
|
160
|
+
def graphml_graph_node_data( node )
|
161
|
+
@current_node[@attributs[:nodes][node.attributes['key']][:name]] = node.texts().to_s
|
162
|
+
end
|
163
|
+
|
164
|
+
def graphml_graph_node_port( node )
|
165
|
+
@current_node[:shape] = :record
|
166
|
+
port = node.attributes['name']
|
167
|
+
if @current_node[:label]
|
168
|
+
label = @current_node[:label].gsub( "{", "" ).gsub( "}", "" )
|
169
|
+
@current_node[:label] = "#{label}|<#{port}> #{port}"
|
170
|
+
else
|
171
|
+
@current_node[:label] = "<#{port}> #{port}"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def graphml_graph_edge( node )
|
176
|
+
source = node.attributes['source']
|
177
|
+
source = {source => node.attributes['sourceport']} if node.attributes['sourceport']
|
178
|
+
target = node.attributes['target']
|
179
|
+
target = {target => node.attributes['targetport']} if node.attributes['targetport']
|
180
|
+
|
181
|
+
@current_edge = @current_graph.add_edge( source, target )
|
182
|
+
|
183
|
+
node.each_element( ) do |child|
|
184
|
+
#begin
|
185
|
+
send( "graphml_graph_edge_#{child.name}".to_sym, child )
|
186
|
+
#rescue NoMethodError => e
|
187
|
+
# raise "ERROR node #{child.name} can be child of graphml"
|
188
|
+
#end
|
189
|
+
end
|
190
|
+
|
191
|
+
@current_edge = nil
|
192
|
+
end
|
193
|
+
|
194
|
+
def graphml_graph_edge_data( node )
|
195
|
+
@current_edge[@attributs[:edges][node.attributes['key']][:name]] = node.texts().to_s
|
196
|
+
end
|
197
|
+
|
198
|
+
def graphml_graph_hyperedge( node )
|
199
|
+
list = []
|
200
|
+
|
201
|
+
node.each_element( ) do |child|
|
202
|
+
if child.name == "endpoint"
|
203
|
+
if child.attributes['port']
|
204
|
+
list << { child.attributes['node'] => child.attributes['port'] }
|
205
|
+
else
|
206
|
+
list << child.attributes['node']
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
list.each { |s|
|
212
|
+
list.each { |t|
|
213
|
+
@current_graph.add_edge( s, t ) unless s == t
|
214
|
+
}
|
215
|
+
}
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|