luquet-ruby-graphviz 0.9.5

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.
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
+