ruby-graphviz_c 1.1.0

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 (184) hide show
  1. checksums.yaml +7 -0
  2. data/.gemrc +0 -0
  3. data/.gitignore +9 -0
  4. data/.travis.yml +7 -0
  5. data/AUTHORS.rdoc +33 -0
  6. data/CHANGELOG.rdoc +287 -0
  7. data/COPYING.rdoc +133 -0
  8. data/Gemfile +4 -0
  9. data/README.rdoc +206 -0
  10. data/Rakefile +71 -0
  11. data/bin/dot2ruby +91 -0
  12. data/bin/gem2gv +165 -0
  13. data/bin/git2gv +167 -0
  14. data/bin/ruby2gv +234 -0
  15. data/bin/xml2gv +96 -0
  16. data/examples/dot/JSP.dot +52 -0
  17. data/examples/dot/balanced.dot +36 -0
  18. data/examples/dot/cluster.dot +30 -0
  19. data/examples/dot/dotgraph.dot +28 -0
  20. data/examples/dot/fsm.dot +20 -0
  21. data/examples/dot/genetic.dot +118 -0
  22. data/examples/dot/hello.dot +1 -0
  23. data/examples/dot/hello_test.rb +33 -0
  24. data/examples/dot/lion_share.dot +103 -0
  25. data/examples/dot/prof.dot +150 -0
  26. data/examples/dot/psg.dot +28 -0
  27. data/examples/dot/rank.dot +6 -0
  28. data/examples/dot/sdh.dot +284 -0
  29. data/examples/dot/siblings.dot +492 -0
  30. data/examples/dot/so-sample001.gv +30 -0
  31. data/examples/dot/so-sample002.gv +33 -0
  32. data/examples/dot/so-sample003.gv +45 -0
  33. data/examples/dot/test.dot +17 -0
  34. data/examples/dot/test_parse.rb +13 -0
  35. data/examples/dot/this_crach_with_dot_2.20.dot +24 -0
  36. data/examples/dot/unix.dot +104 -0
  37. data/examples/graphml/attributes.ext.graphml +12 -0
  38. data/examples/graphml/attributes.graphml +40 -0
  39. data/examples/graphml/cluster.graphml +75 -0
  40. data/examples/graphml/failed_graph.graphml +461 -0
  41. data/examples/graphml/hyper.graphml +29 -0
  42. data/examples/graphml/nested.graphml +54 -0
  43. data/examples/graphml/port.graphml +32 -0
  44. data/examples/graphml/simple.graphml +30 -0
  45. data/examples/hello.png +0 -0
  46. data/examples/rgv/rgv.ps +125 -0
  47. data/examples/rgv/test_rgv.rb +12 -0
  48. data/examples/sample01.rb +32 -0
  49. data/examples/sample02.rb +42 -0
  50. data/examples/sample03.rb +31 -0
  51. data/examples/sample04.rb +22 -0
  52. data/examples/sample05.rb +32 -0
  53. data/examples/sample06.rb +46 -0
  54. data/examples/sample07.rb +23 -0
  55. data/examples/sample08.rb +34 -0
  56. data/examples/sample09.rb +50 -0
  57. data/examples/sample10.rb +50 -0
  58. data/examples/sample11.rb +42 -0
  59. data/examples/sample12.rb +55 -0
  60. data/examples/sample13.rb +48 -0
  61. data/examples/sample14.rb +44 -0
  62. data/examples/sample15.rb +25 -0
  63. data/examples/sample16.rb +8 -0
  64. data/examples/sample17.rb +92 -0
  65. data/examples/sample18.rb +24 -0
  66. data/examples/sample19.rb +59 -0
  67. data/examples/sample20.rb +47 -0
  68. data/examples/sample21.rb +12 -0
  69. data/examples/sample22.rb +10 -0
  70. data/examples/sample23.rb +11 -0
  71. data/examples/sample24.rb +11 -0
  72. data/examples/sample25.rb +11 -0
  73. data/examples/sample26.rb +8 -0
  74. data/examples/sample27.rb +8 -0
  75. data/examples/sample28.rb +12 -0
  76. data/examples/sample29.rb +8 -0
  77. data/examples/sample30.rb +12 -0
  78. data/examples/sample31.rb +10 -0
  79. data/examples/sample32.rb +14 -0
  80. data/examples/sample33.rb +43 -0
  81. data/examples/sample34.rb +29 -0
  82. data/examples/sample35.rb +43 -0
  83. data/examples/sample36.rb +35 -0
  84. data/examples/sample37.rb +87 -0
  85. data/examples/sample38.rb +12 -0
  86. data/examples/sample39.rb +11 -0
  87. data/examples/sample40.rb +17 -0
  88. data/examples/sample41.rb +8 -0
  89. data/examples/sample42.rb +35 -0
  90. data/examples/sample43.rb +26 -0
  91. data/examples/sample44.rb +97 -0
  92. data/examples/sample45.rb +24 -0
  93. data/examples/sample46.rb +43 -0
  94. data/examples/sample47.rb +7 -0
  95. data/examples/sample48.rb +62 -0
  96. data/examples/sample49.rb +10 -0
  97. data/examples/sample50.rb +215 -0
  98. data/examples/sample51.rb +37 -0
  99. data/examples/sample52.rb +62 -0
  100. data/examples/sample53.rb +26 -0
  101. data/examples/sample54.rb +26 -0
  102. data/examples/sample55.rb +9 -0
  103. data/examples/sample56.rb +10 -0
  104. data/examples/sample57.rb +8 -0
  105. data/examples/sample58.rb +33 -0
  106. data/examples/sample59.rb +14 -0
  107. data/examples/sample60.rb +12 -0
  108. data/examples/sample61.rb +12 -0
  109. data/examples/sample62.rb +24 -0
  110. data/examples/sample63.rb +32 -0
  111. data/examples/sample64.rb +31 -0
  112. data/examples/sample65.rb +9 -0
  113. data/examples/sample66.rb +4 -0
  114. data/examples/sample67.rb +10 -0
  115. data/examples/sample68.rb +27 -0
  116. data/examples/sample69.rb +23 -0
  117. data/examples/sample70.rb +9 -0
  118. data/examples/sample99.rb +70 -0
  119. data/examples/sdlshapes/README +2 -0
  120. data/examples/sdlshapes/sdl.ps +655 -0
  121. data/examples/sdlshapes/sdlshapes.dot +78 -0
  122. data/examples/test.xml +26 -0
  123. data/examples/theory/pert.rb +47 -0
  124. data/examples/theory/tests.rb +87 -0
  125. data/lib/ext/gvpr/dot2ruby.g +185 -0
  126. data/lib/graphviz/attrs.rb +73 -0
  127. data/lib/graphviz/constants.rb +294 -0
  128. data/lib/graphviz/core_ext.rb +64 -0
  129. data/lib/graphviz/dot2ruby.rb +59 -0
  130. data/lib/graphviz/dot_script.rb +109 -0
  131. data/lib/graphviz/dsl.rb +67 -0
  132. data/lib/graphviz/edge.rb +197 -0
  133. data/lib/graphviz/elements.rb +39 -0
  134. data/lib/graphviz/ext.rb +17 -0
  135. data/lib/graphviz/family_tree/couple.rb +63 -0
  136. data/lib/graphviz/family_tree/generation.rb +39 -0
  137. data/lib/graphviz/family_tree/person.rb +120 -0
  138. data/lib/graphviz/family_tree/sibling.rb +13 -0
  139. data/lib/graphviz/family_tree.rb +118 -0
  140. data/lib/graphviz/graphml.rb +268 -0
  141. data/lib/graphviz/math/matrix.rb +221 -0
  142. data/lib/graphviz/node.rb +160 -0
  143. data/lib/graphviz/nothugly/nothugly.xsl +321 -0
  144. data/lib/graphviz/nothugly.rb +63 -0
  145. data/lib/graphviz/theory.rb +321 -0
  146. data/lib/graphviz/types/arrow_type.rb +32 -0
  147. data/lib/graphviz/types/color.rb +58 -0
  148. data/lib/graphviz/types/color_list.rb +24 -0
  149. data/lib/graphviz/types/esc_string.rb +20 -0
  150. data/lib/graphviz/types/gv_bool.rb +49 -0
  151. data/lib/graphviz/types/gv_double.rb +32 -0
  152. data/lib/graphviz/types/html_string.rb +18 -0
  153. data/lib/graphviz/types/lbl_string.rb +22 -0
  154. data/lib/graphviz/types/rect.rb +35 -0
  155. data/lib/graphviz/types/spline_type.rb +77 -0
  156. data/lib/graphviz/types.rb +22 -0
  157. data/lib/graphviz/utils/colors.rb +1018 -0
  158. data/lib/graphviz/utils.rb +70 -0
  159. data/lib/graphviz/xml.rb +119 -0
  160. data/lib/graphviz.rb +967 -0
  161. data/lib/ruby-graphviz.rb +1 -0
  162. data/man/dot2ruby.1 +66 -0
  163. data/man/dot2ruby.1.ronn +55 -0
  164. data/man/gem2gv.1 +60 -0
  165. data/man/gem2gv.1.ronn +47 -0
  166. data/man/git2gv.1 +48 -0
  167. data/man/git2gv.1.ronn +40 -0
  168. data/man/ruby2gv.1 +60 -0
  169. data/man/ruby2gv.1.ronn +47 -0
  170. data/man/xml2gv.1 +48 -0
  171. data/man/xml2gv.1.ronn +39 -0
  172. data/ruby-graphviz.gemspec +47 -0
  173. data/setup.rb +1585 -0
  174. data/test/helper.rb +13 -0
  175. data/test/support.rb +95 -0
  176. data/test/test_dot_script.rb +47 -0
  177. data/test/test_examples.rb +151 -0
  178. data/test/test_graph.rb +115 -0
  179. data/test/test_search.rb +29 -0
  180. data/test/test_subgraph.rb +27 -0
  181. data/test/test_theory.rb +98 -0
  182. data/test/test_types.rb +65 -0
  183. data/test/test_utils_colors.rb +52 -0
  184. metadata +301 -0
@@ -0,0 +1,63 @@
1
+ # This file use notugly.xsl: An XSL transform to pretty up the SVG output from Graphviz
2
+ #
3
+ # See: http://www.hokstad.com/making-graphviz-output-pretty-with-xsl.html
4
+ # And: http://www.hokstad.com/making-graphviz-output-pretty-with-xsl-updated.html
5
+ #
6
+ # By Vidar Hokstad and Ryan Shea; Contributions by Jonas Tingborn,
7
+ # Earl Cummings, Michael Kennedy (Graphviz 2.20.2 compatibility, bug fixes,
8
+ # testing, lots of gradients)
9
+
10
+ require 'rubygems'
11
+ begin
12
+ require 'xml/xslt'
13
+ XSLT_METHOD = :xml_xslt_transform
14
+ rescue LoadError => e
15
+ require 'libxml'
16
+ require 'libxslt'
17
+ XSLT_METHOD = :libxslt_transform
18
+ end
19
+
20
+ class GraphViz
21
+ # Transform to pretty up the SVG output
22
+ #
23
+ # For more information, see http://www.hokstad.com/making-graphviz-output-pretty-with-xsl.html
24
+ # and http://www.hokstad.com/making-graphviz-output-pretty-with-xsl-updated.html
25
+ #
26
+ # You can use the :nothugly option to GraphViz#output :
27
+ #
28
+ # graph.output( :svg => "myGraph.svg", :nothugly => true )
29
+ #
30
+ # Or directly on an SVG output graph :
31
+ #
32
+ # GraphViz.nothugly( "myGraph.svg" )
33
+ def self.nothugly( file, save = true )
34
+ xsl = File.join( File.dirname(File.expand_path(__FILE__)), "nothugly", "nothugly.xsl" )
35
+ out = self.send(XSLT_METHOD, file, xsl)
36
+
37
+ if save
38
+ fname = File.join( File.dirname(File.expand_path(file)), File.basename(file))
39
+ File.open( fname, "w" ) { |io|
40
+ io.print out
41
+ }
42
+ else
43
+ return out
44
+ end
45
+ end
46
+
47
+ def self.xml_xslt_transform(xml, xsl)
48
+ xslt = XML::XSLT.new()
49
+ xslt.xml = xml
50
+ xslt.xsl = xsl
51
+ xslt.serve()
52
+ end
53
+
54
+ def self.libxslt_transform(xml, xsl)
55
+ LibXML::XML.default_load_external_dtd = false
56
+ LibXML::XML.default_substitute_entities = false
57
+
58
+ stylesheet_doc = LibXML::XML::Document.file(xsl)
59
+ stylesheet = LibXSLT::XSLT::Stylesheet.new(stylesheet_doc)
60
+ xml_doc = LibXML::XML::Document.file(xml)
61
+ stylesheet.apply(xml_doc).to_s
62
+ end
63
+ end
@@ -0,0 +1,321 @@
1
+ require 'graphviz/math/matrix'
2
+
3
+ class GraphViz
4
+ class Theory
5
+ def initialize( graph )
6
+ @graph = graph
7
+ end
8
+
9
+ # Return the adjancy matrix of the graph
10
+ def adjancy_matrix
11
+ matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.node_count )
12
+
13
+ @graph.each_edge { |e|
14
+ x = @graph.get_node(e.node_one( false )).index
15
+ y = @graph.get_node(e.node_two( false )).index
16
+ matrix[x+1, y+1] = 1
17
+ matrix[y+1, x+1] = 1 if @graph.type == "graph"
18
+ }
19
+
20
+ return matrix
21
+ end
22
+
23
+ # Return the incidence matrix of the graph
24
+ def incidence_matrix
25
+ tail = (@graph.type == "digraph") ? -1 : 1
26
+ matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.edge_count )
27
+
28
+ @graph.each_edge { |e|
29
+ x = e.index
30
+
31
+ nstart = @graph.get_node(e.node_one( false )).index
32
+ nend = @graph.get_node(e.node_two( false )).index
33
+
34
+ matrix[nstart+1, x+1] = 1
35
+ matrix[nend+1, x+1] = tail
36
+ matrix[nend+1, x+1] = 2 if nstart == nend
37
+ }
38
+
39
+ return matrix
40
+ end
41
+
42
+ # Return the degree of the given node
43
+ def degree( node )
44
+ degree = 0
45
+ name = node
46
+ if node.kind_of?(GraphViz::Node)
47
+ name = node.id
48
+ end
49
+
50
+ @graph.each_edge do |e|
51
+ degree += 1 if e.node_one(false) == name or e.node_two(false) == name
52
+ end
53
+
54
+ return degree
55
+ end
56
+
57
+ # Return the laplacian matrix of the graph
58
+ def laplacian_matrix
59
+ return degree_matrix - adjancy_matrix
60
+ end
61
+
62
+ # Return <tt>true</tt> if the graph if symmetric, <tt>false</tt> otherwise
63
+ def symmetric?
64
+ adjancy_matrix == adjancy_matrix.transpose
65
+ end
66
+
67
+ # moore_dijkstra(source, destination)
68
+ def moore_dijkstra( dep, arv )
69
+ dep = @graph.get_node(dep) unless dep.kind_of?(GraphViz::Node)
70
+ arv = @graph.get_node(arv) unless arv.kind_of?(GraphViz::Node)
71
+
72
+ m = distance_matrix
73
+ n = @graph.node_count
74
+ # Table des sommets à choisir
75
+ c = [dep.index]
76
+ # Table des distances
77
+ d = []
78
+ d[dep.index] = 0
79
+
80
+ # Table des predecesseurs
81
+ pred = []
82
+
83
+ @graph.each_node do |name, k|
84
+ if k != dep
85
+ d[k.index] = m[dep.index+1,k.index+1]
86
+ pred[k.index] = dep
87
+ end
88
+ end
89
+
90
+ while c.size < n
91
+ # trouver y tel que d[y] = min{d[k]; k sommet tel que k n'appartient pas à c}
92
+ mini = 1.0/0.0
93
+ y = nil
94
+ @graph.each_node do |name, k|
95
+ next if c.include?(k.index)
96
+ if d[k.index] < mini
97
+ mini = d[k.index]
98
+ y = k
99
+ end
100
+ end
101
+
102
+ # si ce minimum est ∞ alors sortir de la boucle fin si
103
+ break unless mini.to_f.infinite?.nil?
104
+
105
+ c << y.index
106
+ @graph.each_node do |name, k|
107
+ next if c.include?(k.index)
108
+ if d[k.index] > d[y.index] + m[y.index+1,k.index+1]
109
+ d[k.index] = d[y.index] + m[y.index+1,k.index+1]
110
+ pred[k.index] = y
111
+ end
112
+ end
113
+ end
114
+
115
+ # Construction du chemin le plus court
116
+ ch = []
117
+ k = arv
118
+ while k.index != dep.index
119
+ ch.unshift(k)
120
+ k = pred[k.index]
121
+ end
122
+ ch.unshift(dep)
123
+
124
+ if d[arv.index].to_f.infinite?
125
+ return nil
126
+ else
127
+ return( {
128
+ :path => ch,
129
+ :distance => d[arv.index]
130
+ } )
131
+ end
132
+ end
133
+
134
+ # Return a liste of range
135
+ #
136
+ # If the returned array include nil values, there is one or more circuits in the graph
137
+ def range
138
+ matrix = adjancy_matrix
139
+ unseen = (1..matrix.columns).to_a
140
+ result = Array.new(matrix.columns)
141
+ r = 0
142
+
143
+ range_recursion( matrix, unseen, result, r )
144
+ end
145
+
146
+ # Return the critical path for a PERT network
147
+ #
148
+ # If the given graph is not a PERT network, return nul
149
+ def critical_path
150
+ return nil if range.include?(nil) or @graph.type != "digraph"
151
+ r = [ [0, [1]] ]
152
+
153
+ critical_path_recursion( distance_matrix, adjancy_matrix, r, [], 0 ).inject( {:distance => 0, :path => []} ) { |_r, item|
154
+ (_r[:distance] < item[0]) ? { :distance => item[0], :path => item[1] } : _r
155
+ }
156
+ end
157
+
158
+ # Return the PageRank in an directed graph.
159
+ #
160
+ # * damping_factor: PageRank dumping factor.
161
+ # * max_iterations: Maximum number of iterations.
162
+ # * min_delta: Smallest variation required to have a new iteration.
163
+ def pagerank(damping_factor = 0.85, max_iterations = 100, min_delta = 0.00001)
164
+ return nil unless @graph.directed?
165
+
166
+ min_value = (1.0-damping_factor)/@graph.node_count
167
+
168
+ pagerank = {}
169
+ @graph.each_node { |_, node|
170
+ pagerank[node] = 1.0/@graph.node_count
171
+ }
172
+
173
+ max_iterations.times { |_|
174
+ diff = 0
175
+ @graph.each_node { |_, node|
176
+ rank = min_value
177
+ incidents(node).each { |referent|
178
+ rank += damping_factor * pagerank[referent] / neighbors(referent).size
179
+ }
180
+
181
+ diff += (pagerank[node] - rank).abs
182
+ pagerank[node] = rank
183
+ }
184
+ break if diff < min_delta
185
+ }
186
+
187
+ return pagerank
188
+ end
189
+
190
+ # Return the list of nodes that are directly accessible from given node
191
+ def neighbors(node)
192
+ if node.class == String
193
+ @graph.get_node(node).neighbors
194
+ else
195
+ node.neighbors
196
+ end
197
+ end
198
+
199
+ # Return the list of nodes that are incident to the given node (in a directed graph neighbors == incidents)
200
+ def incidents(node)
201
+ if node.class == String
202
+ @graph.get_node(node).incidents
203
+ else
204
+ node.incidents
205
+ end
206
+ end
207
+
208
+ # Breadth First Search
209
+ def bfs(node, &b)
210
+ queue = []
211
+ visited_nodes = []
212
+ node = @graph.get_node(node) if node.kind_of? String
213
+ queue << node
214
+ visited_nodes << node
215
+
216
+ while not queue.empty?
217
+ node = queue.shift
218
+ b.call(node)
219
+ neighbors(node).each do |n|
220
+ unless visited_nodes.include?(n)
221
+ visited_nodes << n
222
+ queue << n
223
+ end
224
+ end
225
+ end
226
+ end
227
+
228
+ # Depth First Search
229
+ def dfs(node, &b)
230
+ visited_nodes = []
231
+ recursive_dfs(node, visited_nodes, &b)
232
+ end
233
+
234
+ private
235
+ def recursive_dfs(node, visited_nodes, &b)
236
+ node = @graph.get_node(node) if node.kind_of? String
237
+ b.call(node)
238
+ visited_nodes << node
239
+ neighbors(node).each do |n|
240
+ recursive_dfs(n, visited_nodes, &b) unless visited_nodes.include?(n)
241
+ end
242
+ end
243
+
244
+ def distance_matrix
245
+ type = @graph.type
246
+ matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.node_count, (1.0/0.0) )
247
+
248
+ @graph.each_edge { |e|
249
+ x = @graph.get_node(e.node_one( false )).index
250
+ y = @graph.get_node(e.node_two( false )).index
251
+ unless x == y
252
+ weight = ((e[:weight].nil?) ? 1 : e[:weight].to_f)
253
+ matrix[x+1, y+1] = weight
254
+ matrix[y+1, x+1] = weight if type == "graph"
255
+ end
256
+ }
257
+
258
+ return matrix
259
+ end
260
+
261
+ def degree_matrix
262
+ matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.node_count )
263
+ @graph.each_node do |name, node|
264
+ i = node.index
265
+ matrix[i+1, i+1] = degree(node)
266
+ end
267
+ return matrix
268
+ end
269
+
270
+ def range_recursion(matrix, unseen, result, r)
271
+ remove = []
272
+ matrix.columns.times do |c|
273
+ if matrix.sum_of_column(c+1) == 0
274
+ result[unseen[c]-1] = r
275
+ remove.unshift( c + 1 )
276
+ end
277
+ end
278
+
279
+ remove.each do |rem|
280
+ matrix = matrix.remove_line(rem).remove_column(rem)
281
+ unseen.delete_at(rem-1)
282
+ end
283
+
284
+ if matrix.columns == 1 and matrix.lines == 1
285
+ if matrix.sum_of_column(1) == 0
286
+ result[unseen[0]-1] = r+1
287
+ end
288
+ elsif remove.size > 0
289
+ range_recursion( matrix, unseen, result, r+1 )
290
+ end
291
+
292
+ return result
293
+ end
294
+
295
+ def index_of_item( array, item )
296
+ array.inject( [0,[]] ){|a,i|
297
+ a[1] << a[0] if i == item
298
+ a[0] += 1
299
+ a
300
+ }[1]
301
+ end
302
+
303
+ def critical_path_recursion( d, a, r, result, level )
304
+ r.each do |p|
305
+ node = p[1][-1]
306
+ index_of_item( a.line(node), 1 ).each do |c|
307
+ succ = c+1
308
+
309
+ cpath = [ (p[0] + d[node,succ]), (p[1].clone << succ) ]
310
+
311
+ if index_of_item( a.line(succ), 1 ).size > 0
312
+ critical_path_recursion( d, a, [cpath], result, level+1 )
313
+ else
314
+ result << cpath
315
+ end
316
+ end
317
+ end
318
+ return result
319
+ end
320
+ end
321
+ end
@@ -0,0 +1,32 @@
1
+ # >> x = "hello\n\t\\l\"world\""
2
+ # => "hello\n\t\\l\"world\""
3
+ # >> puts x.inspect.gsub( "\\\\", "\\" )
4
+ # "hello\n\t\l\"world\""
5
+ #
6
+ # OR
7
+ #
8
+ # >> x = 'hello\n\t\l"world"'
9
+ # => "hello\\n\\t\\l\"world\""
10
+ # >> puts x.inspect.gsub( "\\\\", "\\" )
11
+ # "hello\n\t\l\"world\""
12
+
13
+ class GraphViz
14
+ class Types
15
+ class ArrowType < Common
16
+ def check(data)
17
+ return data
18
+ end
19
+
20
+ def output
21
+ return @data.to_s.inspect.gsub( "\\\\", "\\" )
22
+ end
23
+
24
+ alias :to_gv :output
25
+ alias :to_s :output
26
+
27
+ def to_ruby
28
+ @data
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,58 @@
1
+ require 'graphviz/utils/colors'
2
+
3
+ class ColorException < RuntimeError
4
+ end
5
+
6
+ class GraphViz
7
+ class Types
8
+ class Color < Common
9
+ HEX_FOR_COLOR = /[0-9a-fA-F]{2}/
10
+ RGBA = /^#(#{HEX_FOR_COLOR})(#{HEX_FOR_COLOR})(#{HEX_FOR_COLOR})(#{HEX_FOR_COLOR})?$/
11
+
12
+ def check(data)
13
+ data = data.to_s if data.is_a?(Symbol)
14
+ return nil if data.empty?
15
+
16
+ if data[0].chr == "#"
17
+ m = RGBA.match(data)
18
+ if m.nil?
19
+ raise ColorException, "Wrong color definition RGBA #{data}"
20
+ end
21
+ @to_ruby = GraphViz::Utils::Colors.rgb(m[1], m[2], m[3], m[4])
22
+ return data
23
+ elsif data.include?(",") or data.include?(" ")
24
+ m = data.split(/(?:\s*,\s*|\s+)/).map { |x| x.to_f }
25
+ if m.size != 3
26
+ raise ColorException, "Wrong color definition HSV #{data}"
27
+ end
28
+ @to_ruby = GraphViz::Utils::Colors.hsv(m[0], m[1], m[2])
29
+ return data
30
+ elsif data.is_a?(Array)
31
+ if data.all? { |x| x.is_a?(String) and x =~ /^#{HEX_FOR_COLOR}$/ } and [3,4].include?(data.size)
32
+ @to_ruby = GraphViz::Utils::Colors.rgb(data[0], data[1], data[2], data[3])
33
+ return data
34
+ elsif data.all? { |x| x.kind_of?(Numeric) } and data.size == 3
35
+ @to_ruby = GraphViz::Utils::Colors.hsv(data[0], data[1], data[2])
36
+ return data
37
+ end
38
+
39
+ raise ColorException, "Wrong color definition Array #{data}"
40
+ else
41
+ @to_ruby = GraphViz::Utils::Colors.name(data)
42
+ return data
43
+ end
44
+ end
45
+
46
+ def output
47
+ return @data.to_s.inspect.gsub( "\\\\", "\\" )
48
+ end
49
+
50
+ alias :to_gv :output
51
+ alias :to_s :output
52
+
53
+ def to_ruby
54
+ @to_ruby
55
+ end
56
+ end
57
+ end
58
+ end