GraphvizR 0.3.2 → 0.4.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.
- data/History.txt +6 -0
- data/README.txt +0 -2
- data/lib/graphviz_r.rb +134 -60
- data/test/test_graphviz_r.rb +68 -2
- metadata +5 -5
data/History.txt
CHANGED
data/README.txt
CHANGED
data/lib/graphviz_r.rb
CHANGED
@@ -33,7 +33,7 @@
|
|
33
33
|
# gvr = GraphvizR.new 'sample'
|
34
34
|
# gvr.alpha >> gvr.beta
|
35
35
|
# generates
|
36
|
-
#
|
36
|
+
# digraph sample {
|
37
37
|
# alpla -> beta
|
38
38
|
# }
|
39
39
|
# while
|
@@ -44,6 +44,28 @@
|
|
44
44
|
# alpla -- beta
|
45
45
|
# }
|
46
46
|
#
|
47
|
+
# == Grouping Nodes
|
48
|
+
#
|
49
|
+
# When one node is the root of some nodes, you can aggregate the children by using an array.
|
50
|
+
# For example,
|
51
|
+
# gvr = GraphvizR.new 'sample'
|
52
|
+
# gvr.alpha >> [gvr.beta, gvr.gamma, gvr.delta]
|
53
|
+
# generates
|
54
|
+
# digraph sample {
|
55
|
+
# alpha -> {beta; gamma; delta;}
|
56
|
+
# }
|
57
|
+
#
|
58
|
+
# == Consective Edges
|
59
|
+
#
|
60
|
+
# You can write:
|
61
|
+
# gvr = GraphvizR.new 'sample'
|
62
|
+
# gvr.alpha >> gvr.beta >> gvr.gamma >> gvr.delta
|
63
|
+
# instead of doing:
|
64
|
+
# gvr = GraphvizR.new 'sample'
|
65
|
+
# gvr.alpha >> gvr.beta
|
66
|
+
# gvr.beta >> gvr.gamma
|
67
|
+
# gvr.gamma >> gvr.delta
|
68
|
+
#
|
47
69
|
# == Graph Attributes
|
48
70
|
#
|
49
71
|
# Attributes are specified by Hash in []. Thus, to set the fillcolor of a node abc, one would use
|
@@ -74,10 +96,17 @@
|
|
74
96
|
# (gvr.node2 >> gvr.node1(:p_right)) [:label => 'record']
|
75
97
|
# gvr.to_dot
|
76
98
|
#
|
77
|
-
# ==
|
99
|
+
# == Rank
|
100
|
+
#
|
101
|
+
# Ranks of nodes can be set as the same value for other nodes.
|
102
|
+
# gvr.rank :same, [gvr.a, gvr.b, gvr.c]
|
103
|
+
# means node a, b, and c has same rank value and generages:
|
104
|
+
# {rank = same; a; b; c;};
|
78
105
|
#
|
79
|
-
#
|
80
|
-
#
|
106
|
+
# == Clusters
|
107
|
+
#
|
108
|
+
# Cluster is a way to construct hierarchical graph in graphviz. GraphvizR allows you to use
|
109
|
+
# clusters by means of method calling with a block which has one argument. For example,
|
81
110
|
# gvr = GraphvizR.new 'sample'
|
82
111
|
# gvr.cluster0 do |c0|
|
83
112
|
# c0.graph [:color => :blue, :label => 'area 0', :style => :bold]
|
@@ -112,7 +141,7 @@
|
|
112
141
|
# c -> f [lhead = cluster1];
|
113
142
|
#
|
114
143
|
class GraphvizR
|
115
|
-
VERSION = '0.
|
144
|
+
VERSION = '0.4.0'
|
116
145
|
INDENT_UNIT = ' '
|
117
146
|
|
118
147
|
# This represents graphviz attributes.
|
@@ -122,20 +151,20 @@ class GraphvizR
|
|
122
151
|
@dot = dot
|
123
152
|
end
|
124
153
|
|
125
|
-
def [](
|
126
|
-
@dot.send :"#{@name}=",
|
154
|
+
def [](attr)
|
155
|
+
@dot.send :"#{@name}=", attr
|
127
156
|
end
|
128
157
|
end
|
129
158
|
|
130
159
|
# This represents graphviz node.
|
131
160
|
class Node
|
132
|
-
attr_reader :
|
161
|
+
attr_reader :attr, :name
|
133
162
|
|
134
163
|
def initialize(name, port, dot)
|
135
164
|
@name = name
|
136
165
|
@port = port || []
|
137
166
|
@dot = dot
|
138
|
-
@
|
167
|
+
@attr = {}
|
139
168
|
|
140
169
|
if !@port.empty? and @port[0].is_a? Array and @port[0][0].is_a? Hash
|
141
170
|
@dot[@name] = @port[0][0]
|
@@ -155,15 +184,21 @@ class GraphvizR
|
|
155
184
|
end
|
156
185
|
|
157
186
|
def add_edge_on_dot(node)
|
158
|
-
|
159
|
-
|
187
|
+
attr = nil
|
188
|
+
if node.is_a? Array
|
189
|
+
node = NodeGroup.new node
|
190
|
+
attr = @attr
|
191
|
+
else
|
192
|
+
attr = @attr.merge node.attr
|
193
|
+
end
|
194
|
+
edge = Edge.new([self, node], @dot, attr)
|
160
195
|
@dot.add_edge edge
|
161
196
|
edge
|
162
197
|
end
|
163
198
|
|
164
|
-
def [](
|
165
|
-
@dot[@name] =
|
166
|
-
@
|
199
|
+
def [](attr)
|
200
|
+
@dot[@name] = attr
|
201
|
+
@attr.merge! attr
|
167
202
|
self
|
168
203
|
end
|
169
204
|
|
@@ -181,18 +216,43 @@ class GraphvizR
|
|
181
216
|
name.map{|e| e.to_dot}.join(':')
|
182
217
|
end
|
183
218
|
end
|
219
|
+
|
220
|
+
# Aggregate some nodes.
|
221
|
+
class NodeGroup
|
222
|
+
def initialize(nodes, attr={})
|
223
|
+
@nodes = nodes
|
224
|
+
@attributes = attr
|
225
|
+
end
|
226
|
+
|
227
|
+
def to_sym
|
228
|
+
to_dot.to_sym
|
229
|
+
end
|
230
|
+
|
231
|
+
def to_dot
|
232
|
+
dot = "{"
|
233
|
+
dot += @attributes.to_a.map{|e| "#{e[0]} = #{e[1]};"}.join(' ') unless @attributes.empty?
|
234
|
+
dot += ' ' unless @attributes.empty?
|
235
|
+
dot += @nodes.map{|e| "#{e.to_dot};"}.join(' ')
|
236
|
+
dot += "}"
|
237
|
+
end
|
238
|
+
end
|
184
239
|
|
185
240
|
# This represents a graphviz edge.
|
186
241
|
class Edge
|
187
|
-
def initialize(
|
188
|
-
@
|
189
|
-
@to = to
|
242
|
+
def initialize(nodes, dot, attr={})
|
243
|
+
@nodes = nodes
|
190
244
|
@dot = dot
|
191
|
-
@
|
245
|
+
@attribute = attr
|
192
246
|
end
|
193
|
-
|
194
|
-
def [](
|
195
|
-
@
|
247
|
+
|
248
|
+
def [](attr)
|
249
|
+
@attribute.merge! attr
|
250
|
+
end
|
251
|
+
|
252
|
+
def >>(node, attr={})
|
253
|
+
@nodes << node
|
254
|
+
self[attr]
|
255
|
+
self
|
196
256
|
end
|
197
257
|
|
198
258
|
def node_to_dot(node)
|
@@ -200,8 +260,8 @@ class GraphvizR
|
|
200
260
|
end
|
201
261
|
|
202
262
|
def to_dot
|
203
|
-
dot =
|
204
|
-
dot += " #{@
|
263
|
+
dot = @nodes.map{|e| node_to_dot e}.join " #{@dot.arrow} "
|
264
|
+
dot += " #{@attribute.to_dot}" unless @attribute.empty?
|
205
265
|
dot
|
206
266
|
end
|
207
267
|
|
@@ -210,20 +270,20 @@ class GraphvizR
|
|
210
270
|
end
|
211
271
|
end
|
212
272
|
|
213
|
-
# This returns dot formatted string from given
|
273
|
+
# This returns dot formatted string from given attributes. To know more about <tt>attr</tt>,
|
214
274
|
# please see GraphvizR.new .
|
215
|
-
def self.dot(name,
|
216
|
-
GraphvizR.new(name,
|
275
|
+
def self.dot(name, attr)
|
276
|
+
GraphvizR.new(name, attr).to_dot
|
217
277
|
end
|
218
278
|
|
219
279
|
# This initialzes a GraphvizR instance.
|
220
280
|
# +name+:: the name of the graph
|
221
|
-
# +
|
281
|
+
# +attr+:: <b>!deprecated!</b> all attributes for a graph can be given as a hash instance.
|
222
282
|
# Please guess the contents of the hash from the test or examples below:
|
223
283
|
# gvr = GraphvizR.dot(:sample,
|
224
284
|
# :graph => {:size => "1.5, 2.5"},
|
225
285
|
# :label => 'example',
|
226
|
-
# :
|
286
|
+
# :node_attributes => {
|
227
287
|
# :beta => {:shape => :box},
|
228
288
|
# },
|
229
289
|
# :alpha => :beta,
|
@@ -235,7 +295,7 @@ class GraphvizR
|
|
235
295
|
# gvr = GraphvizR.dot(:sample,
|
236
296
|
# :graph => {:size => "1.5, 2.5"},
|
237
297
|
# :node => {:shape => :record},
|
238
|
-
# :
|
298
|
+
# :node_attributes => {
|
239
299
|
# :node1 => {:label => "<p_left> left|<p_center>center|<p_right> right"},
|
240
300
|
# :node2 => {:label => "left|center|right"}
|
241
301
|
# },
|
@@ -269,34 +329,38 @@ class GraphvizR
|
|
269
329
|
# )
|
270
330
|
# +parent+:: a parent graph is given when this graph is a subgraph.
|
271
331
|
# +indent+:: indent level when this instance is converted to rdot.
|
272
|
-
def initialize(name,
|
332
|
+
def initialize(name, attr={}, parent=nil, indent=0)
|
273
333
|
if name.is_a? Array
|
274
334
|
initialize(*name)
|
275
335
|
else
|
276
336
|
@name = name
|
337
|
+
@default_graph_attributes = {}
|
338
|
+
@default_node_attributes = {}
|
339
|
+
@default_edge_attributes = {}
|
340
|
+
@node_attributes = {}
|
277
341
|
@edges = []
|
278
|
-
@default_node_properties = {}
|
279
|
-
@node_properties = {}
|
280
|
-
@graph_properties = {}
|
281
342
|
@subgraphs = []
|
343
|
+
@node_groups = []
|
282
344
|
@indent = indent + 1
|
283
345
|
@parent = parent
|
284
346
|
@directed = true
|
285
|
-
interprete
|
347
|
+
interprete attr
|
286
348
|
end
|
287
349
|
end
|
288
350
|
|
289
|
-
def interprete(
|
290
|
-
|
351
|
+
def interprete(attr) #:nodoc:
|
352
|
+
attr.each do |k, v|
|
291
353
|
case k
|
292
|
-
when :
|
293
|
-
|
354
|
+
when :node_attribute, :node_attributes
|
355
|
+
add_node_attributes v
|
294
356
|
when :graph
|
295
|
-
@
|
357
|
+
@default_graph_attributes.merge! v
|
296
358
|
when :label, :size, :color, :fillcolor, :style
|
297
|
-
@
|
359
|
+
@default_graph_attributes[k] = v
|
298
360
|
when :node
|
299
|
-
@
|
361
|
+
@default_node_attributes[k] = v
|
362
|
+
when :edge
|
363
|
+
@default_edge_attributes[k] = v
|
300
364
|
when :subgraphs
|
301
365
|
add_subgraph(v)
|
302
366
|
else
|
@@ -305,9 +369,9 @@ class GraphvizR
|
|
305
369
|
end
|
306
370
|
end
|
307
371
|
|
308
|
-
# add
|
309
|
-
def
|
310
|
-
@
|
372
|
+
# add attributes for nodes
|
373
|
+
def add_node_attributes(attrs)
|
374
|
+
@node_attributes = attrs
|
311
375
|
end
|
312
376
|
|
313
377
|
# add an edge to the graph
|
@@ -316,19 +380,19 @@ class GraphvizR
|
|
316
380
|
f = from.keys[0]
|
317
381
|
t = from[f]
|
318
382
|
p = to
|
319
|
-
@edges << Edge.new(f, t, self, p)
|
383
|
+
@edges << Edge.new([f, t], self, p)
|
320
384
|
elsif to.nil?
|
321
385
|
# from is Edge instance
|
322
386
|
@edges << from
|
323
387
|
else
|
324
|
-
@edges << Edge.new(from, to, self)
|
388
|
+
@edges << Edge.new([from, to], self)
|
325
389
|
end
|
326
390
|
end
|
327
391
|
|
328
392
|
# add subgraph
|
329
393
|
def add_subgraph(graphs)
|
330
|
-
graphs.to_a.sort.each do |
|
331
|
-
@subgraphs << self.class.new(
|
394
|
+
graphs.to_a.sort.each do |key_attr|
|
395
|
+
@subgraphs << self.class.new(key_attr[0], key_attr[1], self, @indent)
|
332
396
|
end
|
333
397
|
end
|
334
398
|
|
@@ -373,6 +437,10 @@ class GraphvizR
|
|
373
437
|
end
|
374
438
|
end
|
375
439
|
|
440
|
+
def arrow
|
441
|
+
directed? ? '->' : '--'
|
442
|
+
end
|
443
|
+
|
376
444
|
# When block is given, create new subgraph. Otherwise, create new node.
|
377
445
|
def [](key, *args, &block)
|
378
446
|
if block
|
@@ -384,18 +452,18 @@ class GraphvizR
|
|
384
452
|
end
|
385
453
|
end
|
386
454
|
|
387
|
-
# set
|
455
|
+
# set attributes for a node
|
388
456
|
def []=(key, *args, &block)
|
389
|
-
@
|
457
|
+
@node_attributes[key] = args[0]
|
390
458
|
end
|
391
459
|
|
392
460
|
[:label, :size, :color, :fillcolor, :style].each do |method|
|
393
461
|
define_method :"#{method}=" do |v|
|
394
|
-
@
|
462
|
+
@default_graph_attributes[method] = v
|
395
463
|
end
|
396
464
|
end
|
397
465
|
|
398
|
-
# set graph
|
466
|
+
# set graph attributes
|
399
467
|
def graph(*args)
|
400
468
|
if args.empty?
|
401
469
|
Attributes.new :graph, self
|
@@ -404,20 +472,26 @@ class GraphvizR
|
|
404
472
|
end
|
405
473
|
end
|
406
474
|
|
407
|
-
# set graph
|
408
|
-
def graph=(
|
409
|
-
@
|
475
|
+
# set graph attributes
|
476
|
+
def graph=(attr)
|
477
|
+
@default_graph_attributes.merge! attr
|
478
|
+
end
|
479
|
+
|
480
|
+
def rank(same, nodes)
|
481
|
+
@node_groups << (NodeGroup.new nodes, {:rank => same})
|
410
482
|
end
|
411
483
|
|
412
484
|
# convert this instance to dot
|
413
485
|
def to_dot
|
414
486
|
graph_type = if subgraph?; 'subgraph'elsif directed?; 'digraph' else 'graph' end
|
415
487
|
dot = indent_enter("#{graph_type} #{@name} {", true)
|
416
|
-
dot += indent_enter("graph #{@
|
488
|
+
dot += indent_enter("graph #{@default_graph_attributes.to_dot};") unless @default_graph_attributes.empty?
|
417
489
|
dot += @subgraphs.map{|e| e.to_dot}.join('') unless @subgraphs.empty?
|
418
|
-
dot +=
|
419
|
-
dot +=
|
490
|
+
dot += attributes_to_dot(@default_node_attributes) unless @default_node_attributes.empty?
|
491
|
+
dot += attributes_to_dot(@default_edge_attributes) unless @default_edge_attributes.empty?
|
492
|
+
dot += attributes_to_dot(@node_attributes) unless @node_attributes.empty?
|
420
493
|
dot += @edges.sort.map{|e| indent_enter("#{e.to_dot};")}.join("")
|
494
|
+
dot += @node_groups.map{|e| indent_enter("#{e.to_dot};")}.join("")
|
421
495
|
dot += indent_enter("}", true)
|
422
496
|
dot
|
423
497
|
end
|
@@ -466,12 +540,12 @@ class GraphvizR
|
|
466
540
|
|
467
541
|
protected
|
468
542
|
|
469
|
-
def
|
543
|
+
def attributes_to_dot(hash) #:nodoc:
|
470
544
|
hash.to_a.sort.map{|e| indent_enter "#{e[0]} #{e[1].to_dot};"}.join()
|
471
545
|
end
|
472
546
|
end
|
473
547
|
|
474
|
-
class
|
548
|
+
class Numeric #:nodoc:
|
475
549
|
def to_dot
|
476
550
|
to_s
|
477
551
|
end
|
data/test/test_graphviz_r.rb
CHANGED
@@ -20,7 +20,7 @@ class TestGraphvizR < Test::Unit::TestCase
|
|
20
20
|
gvr = GraphvizR.dot(:sample,
|
21
21
|
:graph => {:size => "1.5, 2.5"},
|
22
22
|
:label => 'example',
|
23
|
-
:
|
23
|
+
:node_attributes => {
|
24
24
|
:beta => {:shape => :box},
|
25
25
|
},
|
26
26
|
:alpha => :beta,
|
@@ -70,7 +70,8 @@ digraph sample {
|
|
70
70
|
gvr = GraphvizR.dot(:sample,
|
71
71
|
:graph => {:size => "1.5, 2.5"},
|
72
72
|
:node => {:shape => :record},
|
73
|
-
:
|
73
|
+
:edge => {:fontsize => 24},
|
74
|
+
:node_attributes => {
|
74
75
|
:node1 => {:label => "<p_left> left|<p_center>center|<p_right> right"},
|
75
76
|
:node2 => {:label => "left|center|right"}
|
76
77
|
},
|
@@ -84,6 +85,7 @@ digraph sample {
|
|
84
85
|
digraph sample {
|
85
86
|
graph [size = "1.5, 2.5"];
|
86
87
|
node [shape = record];
|
88
|
+
edge [fontsize = 24];
|
87
89
|
node1 [label = "<p_left> left|<p_center>center|<p_right> right"];
|
88
90
|
node2 [label = "left|center|right"];
|
89
91
|
node1 -> node2;
|
@@ -296,6 +298,70 @@ digraph sample {
|
|
296
298
|
assert_equal <<-end_of_string, gvr.data(:dot)
|
297
299
|
digraph sample {
|
298
300
|
"alpha" -> "beta" [label = "label1"];
|
301
|
+
}
|
302
|
+
end_of_string
|
303
|
+
end
|
304
|
+
|
305
|
+
def test_consective_edges
|
306
|
+
gvr = GraphvizR.new 'sample'
|
307
|
+
gvr.alpha >> gvr.beta
|
308
|
+
gvr.alpha >> gvr.beta >> gvr.gamma
|
309
|
+
gvr.alpha >> gvr.beta >> gvr.gamma >> gvr.delta
|
310
|
+
|
311
|
+
assert_equal <<-end_of_string, gvr.to_dot
|
312
|
+
digraph sample {
|
313
|
+
alpha -> beta;
|
314
|
+
alpha -> beta -> gamma;
|
315
|
+
alpha -> beta -> gamma -> delta;
|
316
|
+
}
|
317
|
+
end_of_string
|
318
|
+
end
|
319
|
+
|
320
|
+
def test_node_group
|
321
|
+
gvr = GraphvizR.new 'sample'
|
322
|
+
# gvr.a >> gvr.grouping(){gvr.b, gvr.c, gvr.d}
|
323
|
+
# gvr.aa >> gvr.grouping(gvr.bb, gvr.cc, gvr.dd)
|
324
|
+
# a -> {b c d};
|
325
|
+
# aa -> {bb cc dd};
|
326
|
+
gvr.aaa >> [gvr.bbb, gvr.ccc, gvr.ddd]
|
327
|
+
|
328
|
+
assert_equal <<-end_of_string, gvr.to_dot
|
329
|
+
digraph sample {
|
330
|
+
aaa -> {bbb; ccc; ddd;};
|
331
|
+
}
|
332
|
+
end_of_string
|
333
|
+
end
|
334
|
+
|
335
|
+
def test_rank
|
336
|
+
gvr = GraphvizR.new 'sample'
|
337
|
+
gvr.graph [:size => "3, 3"]
|
338
|
+
gvr.Level_1 >> gvr.Level_2 >> gvr.Level_3
|
339
|
+
gvr.a >> gvr.b
|
340
|
+
gvr.a >> gvr.c
|
341
|
+
gvr.a >> gvr.d
|
342
|
+
gvr.b >> gvr.c
|
343
|
+
gvr.b >> gvr.e
|
344
|
+
gvr.d >> gvr.e
|
345
|
+
gvr.d >> gvr.f
|
346
|
+
#gvr.grouping(:rank => :same) {gvr.Level_1; gvr.a}
|
347
|
+
gvr.rank :same, [gvr.Level_1, gvr.a]
|
348
|
+
gvr.rank :same, [gvr.Level_2, gvr.c, gvr.b, gvr.d]
|
349
|
+
gvr.rank :same, [gvr.Level_3, gvr.e, gvr.f]
|
350
|
+
|
351
|
+
assert_equal <<-end_of_string, gvr.to_dot
|
352
|
+
digraph sample {
|
353
|
+
graph [size = "3, 3"];
|
354
|
+
Level_1 -> Level_2 -> Level_3;
|
355
|
+
a -> b;
|
356
|
+
a -> c;
|
357
|
+
a -> d;
|
358
|
+
b -> c;
|
359
|
+
b -> e;
|
360
|
+
d -> e;
|
361
|
+
d -> f;
|
362
|
+
{rank = same; Level_1; a;};
|
363
|
+
{rank = same; Level_2; c; b; d;};
|
364
|
+
{rank = same; Level_3; e; f;};
|
299
365
|
}
|
300
366
|
end_of_string
|
301
367
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: GraphvizR
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-02-
|
6
|
+
version: 0.4.0
|
7
|
+
date: 2007-02-26 00:00:00 +09:00
|
8
8
|
summary: Graphviz wrapper for Ruby and Rails
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -35,8 +35,8 @@ description: "Graphviz wrapper for Ruby. This can be used as a common library, a
|
|
35
35
|
node1 [:label => @label1] node2 [:label => @label2] node1 >> node2
|
36
36
|
node1(:p_left) >> node2 node2 >> node1(:p_center) (node2 >> node1(:p_right))
|
37
37
|
[:label => 'record'] == DEPENDENCIES: * Graphviz (http://www.graphviz.org) ==
|
38
|
-
TODO:
|
39
|
-
|
38
|
+
TODO: == INSTALL: * sudo gem install graphviz_r * if you want to use this in
|
39
|
+
ruby on rails * script/plugin install
|
40
40
|
http://technohippy.net/svn/repos/graphviz_r/trunk/vendor/plugins/rdot ==
|
41
41
|
LICENSE: (The MIT License)"
|
42
42
|
autorequire:
|
@@ -92,5 +92,5 @@ dependencies:
|
|
92
92
|
-
|
93
93
|
- ">="
|
94
94
|
- !ruby/object:Gem::Version
|
95
|
-
version: 1.
|
95
|
+
version: 1.2.0
|
96
96
|
version:
|