luquet-ruby-graphviz 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/AUTHORS +7 -0
  2. data/COPYING +340 -0
  3. data/ChangeLog +66 -0
  4. data/README.rdoc +69 -0
  5. data/bin/ruby2gv +194 -0
  6. data/examples/HTML-Labels.rb +20 -0
  7. data/examples/arrowhead.rb +97 -0
  8. data/examples/dot/cluster.dot +31 -0
  9. data/examples/dot/fsm.dot +20 -0
  10. data/examples/dot/genetic.dot +118 -0
  11. data/examples/dot/hello.dot +1 -0
  12. data/examples/dot/hello_test.rb +14 -0
  13. data/examples/dot/lion_share.dot +103 -0
  14. data/examples/dot/prof.dot +150 -0
  15. data/examples/dot/psg.dot +28 -0
  16. data/examples/dot/sdh.dot +284 -0
  17. data/examples/dot/siblings.dot +492 -0
  18. data/examples/dot/test.dot +17 -0
  19. data/examples/dot/unix.dot +104 -0
  20. data/examples/graphviz.org/TrafficLights.rb +62 -0
  21. data/examples/graphviz.org/cluster.rb +62 -0
  22. data/examples/graphviz.org/hello_world.rb +10 -0
  23. data/examples/graphviz.org/lion_share.rb +215 -0
  24. data/examples/graphviz.org/process.rb +37 -0
  25. data/examples/maketest.sh +85 -0
  26. data/examples/p2p.rb +35 -0
  27. data/examples/sample01.rb +32 -0
  28. data/examples/sample02.rb +42 -0
  29. data/examples/sample03.rb +31 -0
  30. data/examples/sample04.rb +22 -0
  31. data/examples/sample05.rb +32 -0
  32. data/examples/sample06.rb +46 -0
  33. data/examples/sample07.rb +23 -0
  34. data/examples/sample08.rb +34 -0
  35. data/examples/sample09.rb +50 -0
  36. data/examples/sample10.rb +50 -0
  37. data/examples/sample11.rb +42 -0
  38. data/examples/sample12.rb +55 -0
  39. data/examples/sample13.rb +48 -0
  40. data/examples/sample14.rb +44 -0
  41. data/examples/sample15.rb +23 -0
  42. data/examples/sample16.rb +8 -0
  43. data/examples/sample17.rb +92 -0
  44. data/examples/sample18.rb +24 -0
  45. data/examples/sample19.rb +59 -0
  46. data/examples/sample20.rb +47 -0
  47. data/examples/sample21.rb +12 -0
  48. data/examples/sample22.rb +10 -0
  49. data/examples/sample23.rb +11 -0
  50. data/examples/sample24.rb +11 -0
  51. data/examples/sample25.rb +11 -0
  52. data/examples/shapes.rb +24 -0
  53. data/examples/test.xml +26 -0
  54. data/examples/testorder.rb +43 -0
  55. data/examples/testxml.rb +7 -0
  56. data/lib/graphviz.rb +655 -0
  57. data/lib/graphviz/attrs.rb +51 -0
  58. data/lib/graphviz/constants.rb +246 -0
  59. data/lib/graphviz/dot.treetop +97 -0
  60. data/lib/graphviz/edge.rb +130 -0
  61. data/lib/graphviz/node.rb +129 -0
  62. data/lib/graphviz/parser.rb +249 -0
  63. data/lib/graphviz/xml.rb +131 -0
  64. data/setup.rb +1585 -0
  65. metadata +176 -0
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift( "../lib" );
4
+ require "graphviz"
5
+
6
+ GraphViz::options( :use => "dot" )
7
+
8
+ if ARGV[0]
9
+ GraphViz::options( :path => ARGV[0] )
10
+ end
11
+
12
+ GraphViz::new( "g", :rankdir => "LR", :type => "digraph" ) { |g|
13
+ g.node[:fontsize] = "16"
14
+ g.node[:shape] = "record"
15
+
16
+ g.node0( :label => "<f0> 0x10ba8| <f1>" )
17
+ g.node1( :label => "<f0> 0xf7fc4380| <f1> | <f2> |-1" )
18
+ g.node2( :label => "<f0> 0xf7fc44b8| | |2" )
19
+ g.node3( :label => "<f0> 3.43322790286038071e-06|44.79998779296875|0" )
20
+ g.node4( :label => "<f0> 0xf7fc4380| <f1> | <f2> |2" )
21
+ g.node5( :label => "<f0> (nil)| | |-1" )
22
+ g.node6( :label => "<f0> 0xf7fc4380| <f1> | <f2> |1" )
23
+ g.node7( :label => "<f0> 0xf7fc4380| <f1> | <f2> |2" )
24
+ g.node8( :label => "<f0> (nil)| | |-1" )
25
+ g.node9( :label => "<f0> (nil)| | |-1" )
26
+ g.node10( :label => "<f0> (nil)| <f1> | <f2> |-1" )
27
+ g.node11( :label => "<f0> (nil)| <f1> | <f2> |-1" )
28
+ g.node12( :label => "<f0> 0xf7fc43e0| | |1" )
29
+
30
+ g.add_edge( g.node0(:f0), g.node1(:f0) )
31
+ g.add_edge( g.node0(:f1), g.node2(:f0) )
32
+ g.add_edge( g.node1(:f0), g.node3(:f0) )
33
+ g.add_edge( g.node1(:f1), g.node4(:f0) )
34
+ g.add_edge( g.node1(:f2), g.node5(:f0) )
35
+ g.add_edge( g.node4(:f0), g.node3(:f0) )
36
+ g.add_edge( g.node4(:f1), g.node6(:f0) )
37
+ g.add_edge( g.node4(:f2), g.node10(:f0) )
38
+ g.add_edge( g.node6(:f0), g.node3(:f0) )
39
+ g.add_edge( g.node6(:f1), g.node7(:f0) )
40
+ g.add_edge( g.node6(:f2), g.node9(:f0) )
41
+ g.add_edge( g.node7(:f0), g.node3(:f0) )
42
+ g.add_edge( g.node7(:f1), g.node1(:f0) )
43
+ g.add_edge( g.node7(:f2), g.node8(:f0) )
44
+ g.add_edge( g.node10(:f1), g.node11(:f0) )
45
+ g.add_edge( g.node10(:f2), g.node12(:f0) )
46
+ g.add_edge( g.node11(:f2), g.node1(:f0) )
47
+ }.output( :png => "#{$0}.png" )
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift( "../lib" );
4
+ require "graphviz"
5
+
6
+ {"png" => "#{$0}.png", "imap" => "#{$0}.html"}.each do |format, file|
7
+ GraphViz::new( "G" ) { |g|
8
+ g.command(:URL => "http://www.research.att.com/base.html")
9
+ g._output(:label => "output", :URL => "colors.html")
10
+ g.command << g._output
11
+ }.output( format => file )
12
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift( "../lib" );
4
+ require "graphviz"
5
+
6
+ GraphViz::new( "mainmap" ) { |graph|
7
+ graph[:URL] = "http://www.research.att.com/base.html"
8
+ graph.command( :URL => "http://www.research.att.com/command.html" )
9
+ (graph.command << graph._output( :label => "output" ))[:URL] = "colors.html"
10
+ }.output( :canon => nil, :cmapx => "#{$0}.html", :png => "#{$0}.png" )
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift( "../lib" );
4
+ require "graphviz"
5
+
6
+ r = GraphViz::new( "mainmap" ) { |graph|
7
+ graph[:URL] = "http://www.research.att.com/base.html"
8
+ graph.command( :URL => "http://www.research.att.com/command.html" )
9
+ (graph.command << graph._output( :label => "output" ))[:URL] = "colors.html"
10
+ }
11
+ puts r.output( :cmapx => String, :png => "#{$0}.png" )
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift( "../lib" );
4
+ require "graphviz"
5
+
6
+ GraphViz::new( "G" ) { |g|
7
+ g.hello << g.world
8
+ g.bonjour - g.monde
9
+ g.hola > g.mundo
10
+ g.holla >> g.welt
11
+ }.output( :path => "/usr/local/bin", :png => "#{$0}.png" )
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift( "../lib" );
4
+ require "graphviz"
5
+
6
+ GraphViz::new( "G" ) { |g|
7
+ g.hello << g.world
8
+ g.bonjour( :label => '"Bonjour"' ) - g.monde( :label => "Le\nmonde")
9
+ g.hola > g.mundo
10
+ g.holla >> g.welt
11
+ }.output( :path => "/usr/local/bin", :png => "#{$0}.png" )
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift( "../lib" );
4
+ require "graphviz"
5
+
6
+ g = nil
7
+ if ARGV[0]
8
+ g = GraphViz::new( "G", "path" => ARGV[0] )
9
+ else
10
+ g = GraphViz::new( "G" )
11
+ end
12
+
13
+ g.node["shape"] = "ellipse"
14
+
15
+ [ "box", "polygon", "ellipse", "circle", "point",
16
+ "egg", "triangle", "plaintext", "diamond", "trapezium",
17
+ "parallelogram", "house", "pentagon", "hexagon", "septagon", "octagon", "doublecircle",
18
+ "doubleoctagon", "tripleoctagon", "invtriangle", "invtrapezium", "invhouse",
19
+ "Mdiamond", "Msquare", "Mcircle", "rect", "rectangle", "none", "note", "tab", "folder",
20
+ "box3d", "component" ].each { |s|
21
+ g.add_node( s, "shape" => s )
22
+ }
23
+
24
+ g.output( :png => "shapes.png")
@@ -0,0 +1,26 @@
1
+ <inventory title="OmniCorp Store #45x10^3">
2
+ <section name="health">
3
+ <item upc="123456789" stock="12">
4
+ <name>Invisibility Cream</name>
5
+ <price>14.50</price>
6
+ <description>Makes you invisible</description>
7
+ </item>
8
+ <item upc="445322344" stock="18">
9
+ <name>Levitation Salve</name>
10
+ <price>23.99</price>
11
+ <description>Levitate yourself for up to 3 hours per application</description>
12
+ </item>
13
+ </section>
14
+ <section name="food">
15
+ <item upc="485672034" stock="653">
16
+ <name>Blork and Freen Instameal</name>
17
+ <price>4.95</price>
18
+ <description>A tasty meal in a tablet; just add water</description>
19
+ </item>
20
+ <item upc="132957764" stock="44">
21
+ <name>Grob winglets</name>
22
+ <price>3.56</price>
23
+ <description>Tender winglets of Grob. Just add water</description>
24
+ </item>
25
+ </section>
26
+ </inventory>
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift( "../lib" );
4
+ require "graphviz"
5
+
6
+ g = nil
7
+ if ARGV[0]
8
+ g = GraphViz::new( "G", "path" => ARGV[0] )
9
+ else
10
+ g = GraphViz::new( "G" )
11
+ end
12
+
13
+ g.node["color"] = "black"
14
+
15
+ g.edge["color"] = "black"
16
+ g.edge["weight"] = "1"
17
+ g.edge["style"] = "filled"
18
+ g.edge["label"] = ""
19
+
20
+ g["size"] = "4,4"
21
+
22
+ g.node["shape"] = "box"
23
+ main = g.add_node( "main" )
24
+ g.node["shape"] = "ellipse"
25
+ parse = g.add_node( "parse" )
26
+ execute = g.add_node( "execute" )
27
+ init = g.add_node( "init" )
28
+ cleanup = g.add_node( "cleanup" )
29
+ make_string = g.add_node( "make_string", "label" => 'make a\nstring' )
30
+ printf = g.add_node( "printf" )
31
+ compare = g.add_node( "compare", "shape" => "box", "style" => "filled", "color" => ".7 .3 1.0" )
32
+
33
+ g.add_edge( main, parse, "weight" => "8" )
34
+ g.add_edge( parse, execute )
35
+ g.add_edge( main, init, "style" => "dotted" )
36
+ g.add_edge( main, cleanup )
37
+ g.add_edge( execute, make_string )
38
+ g.add_edge( execute, printf )
39
+ g.add_edge( init, make_string )
40
+ g.add_edge( main, printf, "color" => "red", "style" => "bold", "label" => "100 times" )
41
+ g.add_edge( execute, compare, "color" => "red" )
42
+
43
+ g.output( :png => "#{$0}.png" )
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift( "../lib" )
4
+ require 'graphviz/xml'
5
+
6
+ gvxml = GraphViz::XML::new( "test.xml", :text => true, :attrs => true )
7
+ gvxml.output( :png => "#{$0}.png", :use => "dot", :path => ARGV[0] )
@@ -0,0 +1,655 @@
1
+ # Copyright (C) 2003, 2004, 2005, 2006, 2007 Gregoire Lejeune <gregoire.lejeune@free.fr>
2
+ #
3
+ # This program is free software; you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation; either version 2 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program; if not, write to the Free Software
15
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
+
17
+ require 'tempfile'
18
+ #require 'mkmf'
19
+
20
+ require 'graphviz/node'
21
+ require 'graphviz/edge'
22
+ require 'graphviz/attrs'
23
+ require 'graphviz/constants'
24
+ require 'graphviz/parser'
25
+
26
+ class GraphViz
27
+ include Constants
28
+
29
+ public
30
+
31
+ ## Var: Output format (dot, png, jpeg, ...)
32
+ @@format = nil #"canon"
33
+ @format
34
+ ## Var: Output file name
35
+ @filename
36
+ ## Var: Output format and file
37
+ @output
38
+ ## Var: program to use (dot|twopi)
39
+ @@prog = "dot"
40
+ @prog
41
+ ## Var: program path
42
+ @@path = nil
43
+ @path
44
+ ## Var: Error level
45
+ @@errors = 1
46
+ @errors
47
+
48
+ ## Var: Graph name
49
+ @name
50
+
51
+ ## Var: defined attributs
52
+ @graph
53
+ @node
54
+ @edge
55
+
56
+ # This accessor allow you to set global nodes attributs
57
+ attr_accessor :node
58
+
59
+ # This accessor allow you to set global edges attributs
60
+ attr_accessor :edge
61
+
62
+ @elements_order
63
+
64
+ ##
65
+ # Create a new node
66
+ #
67
+ # In:
68
+ # * xNodeName : Name of the new node
69
+ # * *hOpt : Node attributs
70
+ #
71
+ # Return the GraphViz::Node object created
72
+ #
73
+ def add_node( xNodeName, *hOpt )
74
+ @hoNodes[xNodeName] = GraphViz::Node::new( xNodeName, self )
75
+
76
+ if hOpt.nil? == false and hOpt[0].nil? == false
77
+ hOpt[0].each do |xKey, xValue|
78
+ @hoNodes[xNodeName][xKey.to_s] = xValue
79
+ end
80
+ end
81
+
82
+ @elements_order.push( {
83
+ "type" => "node",
84
+ "name" => xNodeName,
85
+ "value" => @hoNodes[xNodeName]
86
+ } )
87
+
88
+ return( @hoNodes[xNodeName] )
89
+ end
90
+
91
+ #
92
+ # Return the node object for the given name (or nil)
93
+ #
94
+ def get_node( xNodeName, &block )
95
+ node = @hoNodes[xNodeName] || nil
96
+
97
+ yield( node ) if( block and node.nil? == false )
98
+
99
+ return node
100
+ end
101
+
102
+ ##
103
+ # Create a new edge
104
+ #
105
+ # In:
106
+ # * oNodeOne : First node (or node list)
107
+ # * oNodeTwo : Second Node (or node list)
108
+ # * *hOpt : Edge attributs
109
+ #
110
+ def add_edge( oNodeOne, oNodeTwo, *hOpt )
111
+
112
+ if( oNodeOne.class == Array )
113
+ oNodeOne.each do |no|
114
+ add_edge( no, oNodeTwo, *hOpt )
115
+ end
116
+ else
117
+ if( oNodeTwo.class == Array )
118
+ oNodeTwo.each do |nt|
119
+ add_edge( oNodeOne, nt, *hOpt )
120
+ end
121
+ else
122
+
123
+ oEdge = GraphViz::Edge::new( oNodeOne, oNodeTwo, self )
124
+
125
+ if hOpt.nil? == false and hOpt[0].nil? == false
126
+ hOpt[0].each do |xKey, xValue|
127
+ oEdge[xKey.to_s] = xValue
128
+ end
129
+ end
130
+
131
+ @elements_order.push( {
132
+ "type" => "edge",
133
+ "value" => oEdge
134
+ } )
135
+ @loEdges.push( oEdge )
136
+
137
+ return( oEdge )
138
+ end
139
+ end
140
+ end
141
+
142
+ #
143
+ # Create a new graph
144
+ #
145
+ # In:
146
+ # * xGraphName : Graph name
147
+ # * *hOpt : Graph attributs
148
+ #
149
+ def add_graph( xGraphName, *hOpt )
150
+ @hoGraphs[xGraphName] = GraphViz::new( xGraphName, :parent => self, :type => @oGraphType )
151
+
152
+ if hOpt.nil? == false and hOpt[0].nil? == false
153
+ hOpt[0].each do |xKey, xValue|
154
+ @hoGraphs[xGraphName][xKey.to_s] = xValue
155
+ end
156
+ end
157
+
158
+ @elements_order.push( {
159
+ "type" => "graph",
160
+ "name" => xGraphName,
161
+ "value" => @hoGraphs[xGraphName]
162
+ } )
163
+
164
+ return( @hoGraphs[xGraphName] )
165
+ end
166
+
167
+ #
168
+ # Return the graph object for the given name (or nil)
169
+ #
170
+ def get_graph( xGraphName, &block )
171
+ graph = @hoGraphs[xGraphName] || nil
172
+
173
+ yield( graph ) if( block and graph.nil? == false )
174
+
175
+ return graph
176
+ end
177
+
178
+ #
179
+ # Get the number of nodes
180
+ #
181
+ def node_count
182
+ @hoNodes.size
183
+ end
184
+
185
+ #
186
+ # Get the number of edges
187
+ #
188
+ def edge_count
189
+ @loEdges.size
190
+ end
191
+
192
+ def method_missing( idName, *args, &block ) #:nodoc:
193
+ xName = idName.id2name
194
+
195
+ rCod = nil
196
+
197
+ if block
198
+ # Creating a cluster named '#{xName}'
199
+ rCod = add_graph( xName, args[0] )
200
+ yield( rCod )
201
+ else
202
+ # Create a node named '#{xName}' or search for a node, edge or cluster
203
+ if @hoNodes.keys.include?( xName )
204
+ if( args[0] )
205
+ return "#{xName}:#{args[0].to_s}"
206
+ else
207
+ return( @hoNodes[xName] )
208
+ end
209
+ end
210
+ return( @hoGraphs[xName] ) if @hoGraphs.keys.include?( xName )
211
+
212
+ rCod = add_node( xName, args[0] )
213
+ end
214
+
215
+ return rCod
216
+ end
217
+
218
+ #
219
+ # Set value +xValue+ to the graph attribut +xAttrName+
220
+ #
221
+ def []=( xAttrName, xValue )
222
+ xValue = xValue.to_s if xValue.class == Symbol
223
+ @graph[xAttrName] = xValue
224
+ end
225
+
226
+ #
227
+ # Get the value of the graph attribut +xAttrName+
228
+ #
229
+ def []( xAttrName )
230
+ return( @graph[xAttrName].clone )
231
+ end
232
+
233
+ #
234
+ # Generate the graph
235
+ #
236
+ # Options :
237
+ # * :output : Output format (Constants::FORMATS)
238
+ # * :file : Output file name
239
+ # * :use : Program to use (Constants::PROGRAMS)
240
+ # * :path : Program PATH
241
+ # * :<format> => <file> : <file> can be
242
+ # * a file name
243
+ # * nil, then the output will be printed to STDOUT
244
+ # * String, then the output will be returned as a String
245
+ # * :errors : DOT error level (default 1)
246
+ # * 0 = Error + Warning
247
+ # * 1 = Error
248
+ # * 2 = none
249
+ #
250
+ def output( *hOpt )
251
+ xDOTScript = ""
252
+ xLastType = nil
253
+ xSeparator = ""
254
+ xData = ""
255
+
256
+ @elements_order.each { |kElement|
257
+ if xLastType.nil? == true or xLastType != kElement["type"]
258
+
259
+ if xData.length > 0
260
+ case xLastType
261
+ when "graph_attr"
262
+ xDOTScript << " " + xData + ";\n"
263
+
264
+ when "node_attr"
265
+ xDOTScript << " node [" + xData + "];\n"
266
+
267
+ when "edge_attr"
268
+ xDOTScript << " edge [" + xData + "];\n"
269
+ end
270
+ end
271
+
272
+ xSeparator = ""
273
+ xData = ""
274
+ end
275
+
276
+ xLastType = kElement["type"]
277
+
278
+ #Modified by
279
+ #Brandon Coleman
280
+ #verify value is NOT NULL
281
+ if kElement["value"] == nil then
282
+ raise ArgumentError, "#{kElement["name"]} has a nil value!"
283
+ end
284
+
285
+ case kElement["type"]
286
+ when "graph_attr"
287
+ xData << xSeparator + kElement["name"] + " = \"" + kElement["value"] + "\""
288
+ xSeparator = "; "
289
+
290
+ when "node_attr"
291
+ xData << xSeparator + kElement["name"] + " = \"" + kElement["value"] + "\""
292
+ xSeparator = ", "
293
+
294
+ when "edge_attr"
295
+ xData << xSeparator + kElement["name"] + " = \"" + kElement["value"] + "\""
296
+ xSeparator = ", "
297
+
298
+ when "node"
299
+ xDOTScript << " " + kElement["value"].output() + "\n"
300
+
301
+ when "edge"
302
+ xDOTScript << " " + kElement["value"].output( @oGraphType ) + "\n"
303
+
304
+ when "graph"
305
+ xDOTScript << kElement["value"].output() + "\n"
306
+
307
+ else
308
+ raise ArgumentError, "Don't know what to do with element type '#{kElement['type']}'"
309
+ end
310
+ }
311
+
312
+ if xData.length > 0
313
+ case xLastType
314
+ when "graph_attr"
315
+ xDOTScript << " " + xData + ";\n"
316
+
317
+ when "node_attr"
318
+ xDOTScript << " node [" + xData + "];\n"
319
+
320
+ when "edge_attr"
321
+ xDOTScript << " edge [" + xData + "];\n"
322
+ end
323
+ end
324
+ xDOTScript << "}"
325
+
326
+ if @oParentGraph.nil? == false
327
+ xDOTScript = "subgraph #{@name} {\n" << xDOTScript
328
+
329
+ return( xDOTScript )
330
+ else
331
+ if hOpt.nil? == false and hOpt[0].nil? == false
332
+ hOpt[0].each do |xKey, xValue|
333
+ xValue = xValue.to_s unless xValue.nil? or [Class, TrueClass, FalseClass].include?(xValue.class)
334
+ case xKey.to_s
335
+ when "output"
336
+ warn ":output option is deprecated, please use :<format> => :<file>"
337
+ if FORMATS.index( xValue ).nil? == true
338
+ raise ArgumentError, "output format '#{xValue}' invalid"
339
+ end
340
+ @format = xValue
341
+ when "file"
342
+ warn ":file option is deprecated, please use :<format> => :<file>"
343
+ @filename = xValue
344
+ when "use"
345
+ if PROGRAMS.index( xValue ).nil? == true
346
+ raise ArgumentError, "can't use '#{xValue}'"
347
+ end
348
+ @prog = xValue
349
+ when "path"
350
+ @path = xValue
351
+ when "errors"
352
+ @errors = xValue
353
+ else
354
+ if FORMATS.index( xKey.to_s ).nil? == true
355
+ raise ArgumentError, "output format '#{xValue}' invalid"
356
+ end
357
+ @output[xKey.to_s] = xValue
358
+ end
359
+ end
360
+ end
361
+
362
+ xDOTScript = "#{@oGraphType} #{@name} {\n" << xDOTScript
363
+
364
+ xOutputString = false
365
+ xOutput = if @format != "none"
366
+ ## Act: Save script and send it to dot
367
+ t = if /Windows/.match( ENV['OS'] )
368
+ Tempfile::open( File.basename($0), "." )
369
+ else
370
+ Tempfile::open( File.basename($0) )
371
+ end
372
+ t.print( xDOTScript )
373
+ t.close
374
+
375
+ cmd = find_executable( )
376
+ if cmd == nil
377
+ raise StandardError, "GraphViz not installed or #{@prog} not in PATH. Install GraphViz or use the 'path' option"
378
+ end
379
+
380
+ xOutputWithFile = ""
381
+ xOutputWithoutFile = ""
382
+ unless @format.nil?
383
+ if @filename.nil?
384
+ xOutputWithoutFile = "-T#{@format} "
385
+ elsif @filename == String
386
+ xOutputWithoutFile = "-T#{@format} "
387
+ xOutputString = true
388
+ else
389
+ xOutputWithFile = "-T#{@format} -o#{@filename} "
390
+ end
391
+ end
392
+ @output.each do |format, file|
393
+ if file.nil?
394
+ xOutputWithoutFile << "-T#{format} "
395
+ elsif file == String
396
+ xOutputWithoutFile << "-T#{format} "
397
+ xOutputString = true
398
+ else
399
+ xOutputWithFile << "-T#{format} -o#{file} "
400
+ end
401
+ end
402
+
403
+ #xCmd = "#{cmd} #{xOutputWithFile} #{xOutputWithoutFile} #{t.path}"
404
+ #if /Windows/.match( ENV['OS'] )
405
+ xCmd = "\"#{cmd}\" -q#{@errors} #{xOutputWithFile} #{xOutputWithoutFile} #{t.path}"
406
+ #end
407
+
408
+ output_from_command( xCmd )
409
+ else
410
+ xDOTScript
411
+ end
412
+
413
+ if xOutputString
414
+ xOutput
415
+ else
416
+ print xOutput
417
+ end
418
+ end
419
+ end
420
+
421
+ alias :save :output
422
+
423
+ def output_and_errors_from_command(cmd) #:nodoc:
424
+ unless defined? Open3
425
+ begin
426
+ require 'open3'
427
+ require 'win32/open3'
428
+ rescue LoadError
429
+ end
430
+ end
431
+ begin
432
+ Open3.popen3( cmd ) do |stdin, stdout, stderr|
433
+ stdin.close
434
+ [stdout.read, stderr.read]
435
+ end
436
+ rescue NotImplementedError, NoMethodError
437
+ IO.popen( cmd ) do |stdout|
438
+ [stdout.read, nil]
439
+ end
440
+ end
441
+ end
442
+
443
+ def output_from_command(cmd) #:nodoc:
444
+ output, errors = output_and_errors_from_command(cmd)
445
+ if errors.nil? || errors.strip.empty?
446
+ output
447
+ else
448
+ raise "Error from #{cmd}:\n#{errors}"
449
+ end
450
+ end
451
+
452
+ #
453
+ # Get the graph name
454
+ #
455
+ def name
456
+ @name.clone
457
+ end
458
+
459
+ #
460
+ # Create an edge between the current cluster and the node or cluster +oNode+
461
+ #
462
+ def <<( oNode )
463
+ raise( ArgumentError, "Edge between root graph and node or cluster not allowed!" ) if self.pg.nil?
464
+
465
+ if( oNode.class == Array )
466
+ oNode.each do |no|
467
+ self << no
468
+ end
469
+ else
470
+ return GraphViz::commonGraph( oNode, self ).add_edge( self, oNode )
471
+ end
472
+ end
473
+ alias :> :<<
474
+ alias :- :<<
475
+ alias :>> :<<
476
+
477
+ def pg #:nodoc:
478
+ @oParentGraph
479
+ end
480
+
481
+ def self.commonGraph( o1, o2 ) #:nodoc:
482
+ g1 = o1.pg
483
+ g2 = o2.pg
484
+
485
+ return o1 if g1.nil?
486
+ return o2 if g2.nil?
487
+
488
+ return g1 if g1.object_id == g2.object_id
489
+
490
+ return GraphViz::commonGraph( g1, g2 )
491
+ end
492
+
493
+ def set_position( xType, xKey, xValue ) #:nodoc:
494
+ @elements_order.push( {
495
+ "type" => "#{xType}_attr",
496
+ "name" => xKey,
497
+ "value" => xValue
498
+ } )
499
+ end
500
+
501
+ ## ----------------------------------------------------------------------------
502
+
503
+ #
504
+ # Change default options (:use, :path, :errors and :output)
505
+ #
506
+ def self.default( hOpts )
507
+ hOpts.each do |k, v|
508
+ case k.to_s
509
+ when "use"
510
+ @@prog = v
511
+ when "path"
512
+ @@path = v
513
+ when "errors"
514
+ @@errors = v
515
+ when "output"
516
+ warn ":output option is deprecated!"
517
+ @@format = v
518
+ else
519
+ warn "Invalide option #{k}!"
520
+ end
521
+ end
522
+ end
523
+
524
+ def self.options( hOpts )
525
+ GraphViz::default( hOpts )
526
+ end
527
+
528
+ ## ----------------------------------------------------------------------------
529
+
530
+ #
531
+ # Create a new graph from a GraphViz File
532
+ #
533
+ # Options :
534
+ # * :output : Output format (Constants::FORMATS) (default : dot)
535
+ # * :file : Output file name (default : none)
536
+ # * :use : Program to use (Constants::PROGRAMS) (default : dot)
537
+ # * :path : Program PATH
538
+ # * :parent : Parent graph (default : none)
539
+ # * :type : Graph type (Constants::GRAPHTYPE) (default : digraph)
540
+ #
541
+ def self.parse( xFile, *hOpts, &block )
542
+ g = GraphViz::Parser.parse( xFile, hOpts[0], &block )
543
+ return g
544
+ end
545
+
546
+ ## ----------------------------------------------------------------------------
547
+
548
+ private
549
+
550
+ ## Var: Nodes, Edges and Graphs tables
551
+ @hoNodes
552
+ @loEdges
553
+ @hoGraphs
554
+
555
+ ## Var: Parent graph
556
+ @oParentGraph
557
+
558
+ ## Var: Type de graphe (orienté ou non)
559
+ @oGraphType
560
+
561
+ #
562
+ # Create a new graph object
563
+ #
564
+ # Options :
565
+ # * :output : Output format (Constants::FORMATS) (default : dot)
566
+ # * :file : Output file name (default : none)
567
+ # * :use : Program to use (Constants::PROGRAMS) (default : dot)
568
+ # * :path : Program PATH
569
+ # * :parent : Parent graph (default : none)
570
+ # * :type : Graph type (Constants::GRAPHTYPE) (default : digraph)
571
+ # * :errors : DOT error level (default 1)
572
+ # * 0 = Error + Warning
573
+ # * 1 = Error
574
+ # * 2 = none
575
+ #
576
+ def initialize( xGraphName, *hOpt, &block )
577
+ @filename = nil
578
+ @name = xGraphName.to_s
579
+ @format = @@format
580
+ @prog = @@prog
581
+ @path = @@path
582
+ @errors = @@errors
583
+ @output = {}
584
+
585
+ @elements_order = Array::new()
586
+
587
+ @oParentGraph = nil
588
+ @oGraphType = "digraph"
589
+
590
+ @hoNodes = Hash::new()
591
+ @loEdges = Array::new()
592
+ @hoGraphs = Hash::new()
593
+
594
+ @node = GraphViz::Attrs::new( self, "node", NODESATTRS )
595
+ @edge = GraphViz::Attrs::new( self, "edge", EDGESATTRS )
596
+ @graph = GraphViz::Attrs::new( self, "graph", GRAPHSATTRS )
597
+
598
+ if hOpt.nil? == false and hOpt[0].nil? == false
599
+ hOpt[0].each do |xKey, xValue|
600
+ case xKey.to_s
601
+ when "output"
602
+ warn ":output option is deprecated, please use :<format> => :<file>"
603
+ if FORMATS.index( xValue.to_s ).nil? == true
604
+ raise ArgumentError, "output format '#{xValue}' invalid"
605
+ end
606
+ @format = xValue.to_s
607
+ when "use"
608
+ if PROGRAMS.index( xValue.to_s ).nil? == true
609
+ raise ArgumentError, "can't use '#{xValue}'"
610
+ end
611
+ @prog = xValue.to_s
612
+ when "file"
613
+ warn ":file option is deprecated, please use :<format> => :<file>"
614
+ @filename = xValue.to_s
615
+ when "parent"
616
+ @oParentGraph = xValue
617
+ when "type"
618
+ if GRAPHTYPE.index( xValue.to_s ).nil? == true
619
+ raise ArgumentError, "graph type '#{xValue}' unknow"
620
+ end
621
+ @oGraphType = xValue.to_s
622
+ when "path"
623
+ @path = xValue.to_s
624
+ when "errors"
625
+ @errors = xValue
626
+ else
627
+ self[xKey.to_s] = xValue.to_s
628
+ end
629
+ end
630
+ end
631
+
632
+ yield( self ) if( block )
633
+ end
634
+
635
+ #
636
+ # Escape a string to be acceptable as a node name in a graphviz input file
637
+ #
638
+ def self.escape(str, force = false) #:nodoc:
639
+ if force or str.match( /\A[a-zA-Z_]+[a-zA-Z0-9_:\.]*\Z/ ).nil?
640
+ '"' + str.gsub('"', '\\"').gsub("\n", '\\\\n') + '"'
641
+ else
642
+ str
643
+ end
644
+ end
645
+
646
+ def find_executable( ) #:nodoc:
647
+ cmd = find_executable0( @prog )
648
+ if cmd == nil and @path != nil
649
+ __cmd = File.join( @path, @prog )
650
+ cmd = __cmd if File.executable?( __cmd )
651
+ end
652
+ return cmd
653
+ end
654
+ end
655
+