ruby-graphviz 1.0.9 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -2
- data/AUTHORS.rdoc +5 -1
- data/CHANGELOG.rdoc +10 -0
- data/README.rdoc +2 -1
- data/Rakefile +32 -24
- data/examples/sample70.rb +9 -0
- data/examples/sample71.rb +21 -0
- data/examples/sample72.rb +22 -0
- data/lib/ext/gvpr/dot2ruby.g +80 -62
- data/lib/graphviz.rb +51 -40
- data/lib/graphviz/attrs.rb +1 -1
- data/lib/graphviz/constants.rb +1 -1
- data/lib/graphviz/dot2ruby.rb +5 -2
- data/lib/graphviz/edge.rb +181 -176
- data/lib/graphviz/node.rb +6 -1
- data/lib/graphviz/theory.rb +7 -7
- data/lib/graphviz/utils.rb +6 -22
- data/ruby-graphviz.gemspec +1 -5
- data/test/helper.rb +13 -0
- data/test/test_dot_script.rb +45 -41
- data/test/test_examples.rb +20 -30
- data/test/test_graph.rb +14 -3
- data/test/test_search.rb +1 -4
- data/test/test_subgraph.rb +14 -3
- data/test/test_theory.rb +15 -5
- data/test/test_types.rb +1 -3
- data/test/test_utils_colors.rb +1 -3
- metadata +26 -53
- data/test/support.rb +0 -105
data/lib/graphviz/attrs.rb
CHANGED
@@ -59,7 +59,7 @@ class GraphViz
|
|
59
59
|
end
|
60
60
|
|
61
61
|
begin
|
62
|
-
value = GraphViz::Types.const_get(@attributes[key.to_s]).new(
|
62
|
+
value = GraphViz::Types.const_get(@attributes[key.to_s]).new(value)
|
63
63
|
rescue => e
|
64
64
|
raise AttributeException, "Invalid value `#{value}` for attribute `#{key}` : #{e}"
|
65
65
|
end
|
data/lib/graphviz/constants.rb
CHANGED
data/lib/graphviz/dot2ruby.rb
CHANGED
@@ -24,13 +24,16 @@ class Dot2Ruby #:nodoc:
|
|
24
24
|
def initialize( xGVPath, xOutFile, xOutFormat = nil ) #:nodoc:
|
25
25
|
paths = (xGVPath.nil?) ? [] : [xGVPath]
|
26
26
|
@xGvprPath = find_executable( 'gvpr', paths )
|
27
|
+
if (@xGvprPath.blank?)
|
28
|
+
raise Exception, "GraphViz is not installed. Please be sure that 'gvpr' is on the search path'"
|
29
|
+
end
|
27
30
|
@xOutFile = xOutFile
|
28
31
|
@xOutFormat = xOutFormat || "_"
|
29
32
|
@gvprScript = GraphViz::Ext.find( "dot2ruby.g" )
|
30
33
|
end
|
31
34
|
|
32
35
|
def run( xFile ) #:nodoc:
|
33
|
-
xCmd =
|
36
|
+
xCmd = [@xGvprPath, '-f', @gvprScript, '-a', @xOutFormat, xFile]
|
34
37
|
xOutput = output_from_command( xCmd )
|
35
38
|
if @xOutFile.nil?
|
36
39
|
puts xOutput
|
@@ -42,7 +45,7 @@ class Dot2Ruby #:nodoc:
|
|
42
45
|
end
|
43
46
|
|
44
47
|
def eval( xFile ) #:nodoc:
|
45
|
-
xCmd =
|
48
|
+
xCmd = [@xGvprPath, '-f', @gvprScript, '-a', '-', xFile]
|
46
49
|
xOutput = output_from_command( xCmd )
|
47
50
|
instance_eval(xOutput)
|
48
51
|
return @_graph_eval
|
data/lib/graphviz/edge.rb
CHANGED
@@ -18,180 +18,185 @@ require 'graphviz/attrs'
|
|
18
18
|
require 'graphviz/constants'
|
19
19
|
|
20
20
|
class GraphViz
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
21
|
+
class Edge
|
22
|
+
include GraphViz::Constants
|
23
|
+
|
24
|
+
# Create a new edge
|
25
|
+
#
|
26
|
+
# In:
|
27
|
+
# * vNodeOne : First node (can be a GraphViz::Node or a node ID)
|
28
|
+
# * vNodeTwo : Second node (can be a GraphViz::Node or a node ID)
|
29
|
+
# * parent_graph : Graph
|
30
|
+
def initialize( vNodeOne, vNodeTwo, parent_graph )
|
31
|
+
@node_one_id, @node_one_port = getNodeNameAndPort( vNodeOne )
|
32
|
+
@node_two_id, @node_two_port = getNodeNameAndPort( vNodeTwo )
|
33
|
+
|
34
|
+
@parent_graph = parent_graph
|
35
|
+
@edge_attributes = GraphViz::Attrs::new( nil, "edge", EDGESATTRS )
|
36
|
+
@index = nil
|
37
|
+
|
38
|
+
unless @parent_graph.directed?
|
39
|
+
(@parent_graph.find_node(@node_one_id) || @parent_graph.add_nodes(@node_one_id)).incidents << (@parent_graph.find_node(@node_two_id) || @parent_graph.add_nodes(@node_two_id))
|
40
|
+
(@parent_graph.find_node(@node_two_id) || @parent_graph.add_nodes(@node_two_id)).neighbors << (@parent_graph.find_node(@node_one_id) || @parent_graph.add_nodes(@node_one_id))
|
41
|
+
end
|
42
|
+
(@parent_graph.find_node(@node_one_id) || @parent_graph.add_nodes(@node_one_id)).neighbors << (@parent_graph.find_node(@node_two_id) || @parent_graph.add_nodes(@node_two_id))
|
43
|
+
(@parent_graph.find_node(@node_two_id) || @parent_graph.add_nodes(@node_two_id)).incidents << (@parent_graph.find_node(@node_one_id) || @parent_graph.add_nodes(@node_one_id))
|
44
|
+
end
|
45
|
+
|
46
|
+
# Return the node one as string (so with port if any)
|
47
|
+
def node_one(with_port = true, escaped = true)
|
48
|
+
if not(@node_one_port and with_port)
|
49
|
+
escaped ? GraphViz.escape(@node_one_id) : @node_one_id
|
50
|
+
else
|
51
|
+
escaped ? GraphViz.escape(@node_one_id, :force => true) + ":#{@node_one_port}" : "#{@node_one_id}:#{@node_one_port}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
alias :tail_node :node_one
|
55
|
+
|
56
|
+
# Return the node two as string (so with port if any)
|
57
|
+
def node_two(with_port = true, escaped = true)
|
58
|
+
if not(@node_two_port and with_port)
|
59
|
+
escaped ? GraphViz.escape(@node_two_id) : @node_two_id
|
60
|
+
else
|
61
|
+
escaped ? GraphViz.escape(@node_two_id, :force => true) + ":#{@node_two_port}" : "#{@node_two_id}:#{@node_two_port}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
alias :head_node :node_two
|
65
|
+
|
66
|
+
# Return the index of the edge
|
67
|
+
def index
|
68
|
+
@index
|
69
|
+
end
|
70
|
+
def index=(i) #:nodoc:
|
71
|
+
@index = i if @index == nil
|
72
|
+
end
|
73
|
+
|
74
|
+
# Set value +attribute_value+ to the edge attribute +attribute_name+
|
75
|
+
def []=( attribute_name, attribute_value )
|
76
|
+
attribute_value = attribute_value.to_s if attribute_value.class == Symbol
|
77
|
+
@edge_attributes[attribute_name.to_s] = attribute_value
|
78
|
+
end
|
79
|
+
|
80
|
+
# Set values for edge attributes or
|
81
|
+
# get the value of the given edge attribute +attribute_name+
|
82
|
+
def []( attribute_name )
|
83
|
+
# Modification by axgle (http://github.com/axgle)
|
84
|
+
if Hash === attribute_name
|
85
|
+
attribute_name.each do |key, value|
|
86
|
+
self[key] = value
|
87
|
+
end
|
88
|
+
else
|
89
|
+
if @edge_attributes[attribute_name.to_s]
|
90
|
+
@edge_attributes[attribute_name.to_s].clone
|
91
|
+
else
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# Calls block once for each attribute of the edge, passing the name and value to the
|
99
|
+
# block as a two-element array.
|
100
|
+
#
|
101
|
+
# If global is set to false, the block does not receive the attributes set globally
|
102
|
+
#
|
103
|
+
def each_attribute(global = true, &b)
|
104
|
+
attrs = @edge_attributes.to_h
|
105
|
+
if global
|
106
|
+
attrs = pg.edge.to_h.merge attrs
|
107
|
+
end
|
108
|
+
attrs.each do |k,v|
|
109
|
+
yield(k,v)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
def each_attribut(global = true, &b)
|
113
|
+
warn "`GraphViz::Edge#each_attribut` is deprecated, please use `GraphViz::Edge#each_attribute`"
|
114
|
+
each_attribute(global, &b)
|
115
|
+
end
|
116
|
+
|
117
|
+
def <<( node ) #:nodoc:
|
118
|
+
n = @parent_graph.get_node(@node_two_id)
|
119
|
+
|
120
|
+
GraphViz::commonGraph( node, n ).add_edges( n, node )
|
121
|
+
end
|
122
|
+
alias :> :<< #:nodoc:
|
123
|
+
alias :- :<< #:nodoc:
|
124
|
+
alias :>> :<< #:nodoc:
|
125
|
+
|
126
|
+
#
|
127
|
+
# Return the root graph
|
128
|
+
#
|
129
|
+
def root_graph
|
130
|
+
return( (self.pg.nil?) ? nil : self.pg.root_graph )
|
131
|
+
end
|
132
|
+
|
133
|
+
def pg #:nodoc:
|
134
|
+
@parent_graph
|
135
|
+
end
|
136
|
+
|
137
|
+
# Set edge attributes
|
138
|
+
#
|
139
|
+
# Example :
|
140
|
+
# e = graph.add_edges( ... )
|
141
|
+
# ...
|
142
|
+
# e.set { |_e|
|
143
|
+
# _e.color = "blue"
|
144
|
+
# _e.fontcolor = "red"
|
145
|
+
# }
|
146
|
+
def set( &b )
|
147
|
+
yield( self )
|
148
|
+
end
|
149
|
+
|
150
|
+
# Add edge options
|
151
|
+
# use edge.<option>=<value> or edge.<option>( <value> )
|
152
|
+
def method_missing( idName, *args, &block ) #:nodoc:
|
153
|
+
return if idName == :to_ary # ruby 1.9.2 fix
|
154
|
+
xName = idName.id2name
|
155
|
+
|
156
|
+
self[xName.gsub( /=$/, "" )]=args[0]
|
157
|
+
end
|
158
|
+
|
159
|
+
def output( oGraphType ) #:nodoc:
|
160
|
+
xLink = " -> "
|
161
|
+
if oGraphType == "graph"
|
162
|
+
xLink = " -- "
|
163
|
+
end
|
164
|
+
|
165
|
+
# reserved words, they aren't accepted in dot as node name
|
166
|
+
reserved_names = ["node", "edge","graph", "digraph", "subgraph", "strict"]
|
167
|
+
|
168
|
+
xOut = reserved_names.include?(self.node_one) ? "" << "_" + self.node_one : "" << self.node_one
|
169
|
+
xOut = xOut << xLink
|
170
|
+
xOut = reserved_names.include?(self.node_two) ? xOut << "_" + self.node_two : xOut << self.node_two
|
171
|
+
xAttr = ""
|
172
|
+
xSeparator = ""
|
173
|
+
@edge_attributes.data.each do |k, v|
|
174
|
+
xAttr << xSeparator + k + " = " + v.to_gv
|
175
|
+
xSeparator = ", "
|
176
|
+
end
|
177
|
+
if xAttr.length > 0
|
178
|
+
xOut << " [" + xAttr + "]"
|
179
|
+
end
|
180
|
+
xOut << ";"
|
181
|
+
|
182
|
+
return( xOut )
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
def getNodeNameAndPort( node )
|
187
|
+
name, port = nil, nil
|
188
|
+
if node.class == Hash
|
189
|
+
node.each do |k, v|
|
190
|
+
name, port = getNodeNameAndPort(k)
|
191
|
+
port = v
|
192
|
+
end
|
193
|
+
elsif node.class == String
|
194
|
+
name = node
|
195
|
+
else
|
196
|
+
name = node.id
|
197
|
+
end
|
198
|
+
|
199
|
+
return name, port
|
200
|
+
end
|
201
|
+
end
|
197
202
|
end
|
data/lib/graphviz/node.rb
CHANGED
@@ -134,11 +134,16 @@ class GraphViz
|
|
134
134
|
end
|
135
135
|
|
136
136
|
def output #:nodoc:
|
137
|
+
# reserved words, they aren't accepted in dot as node name
|
138
|
+
reserved_names = ["node", "edge","graph", "digraph", "subgraph", "strict"]
|
137
139
|
#node_id = @node_id.clone
|
138
140
|
#node_id = '"' << node_id << '"' if node_id.match( /^[a-zA-Z_]+[a-zA-Z0-9_\.]*$/ ).nil?
|
139
141
|
node_id = GraphViz.escape(@node_id)
|
140
142
|
|
141
|
-
|
143
|
+
# add a check to see if the node names are valid
|
144
|
+
# if they aren't is added an _ before
|
145
|
+
# and the print staies the same, because of the label
|
146
|
+
xOut = reserved_names.include?(node_id) ? "" << "_" + node_id : "" << node_id
|
142
147
|
xAttr = ""
|
143
148
|
xSeparator = ""
|
144
149
|
|
data/lib/graphviz/theory.rb
CHANGED
@@ -11,8 +11,8 @@ class GraphViz
|
|
11
11
|
matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.node_count )
|
12
12
|
|
13
13
|
@graph.each_edge { |e|
|
14
|
-
x = @graph.get_node(e.node_one( false
|
15
|
-
y = @graph.get_node(e.node_two( false
|
14
|
+
x = @graph.get_node(e.node_one(false, false)).index
|
15
|
+
y = @graph.get_node(e.node_two(false, false)).index
|
16
16
|
matrix[x+1, y+1] = 1
|
17
17
|
matrix[y+1, x+1] = 1 if @graph.type == "graph"
|
18
18
|
}
|
@@ -28,8 +28,8 @@ class GraphViz
|
|
28
28
|
@graph.each_edge { |e|
|
29
29
|
x = e.index
|
30
30
|
|
31
|
-
nstart = @graph.get_node(e.node_one( false
|
32
|
-
nend = @graph.get_node(e.node_two( false
|
31
|
+
nstart = @graph.get_node(e.node_one(false, false)).index
|
32
|
+
nend = @graph.get_node(e.node_two(false, false)).index
|
33
33
|
|
34
34
|
matrix[nstart+1, x+1] = 1
|
35
35
|
matrix[nend+1, x+1] = tail
|
@@ -48,7 +48,7 @@ class GraphViz
|
|
48
48
|
end
|
49
49
|
|
50
50
|
@graph.each_edge do |e|
|
51
|
-
degree += 1 if e.node_one(false) == name or e.node_two(false) == name
|
51
|
+
degree += 1 if e.node_one(false, false) == name or e.node_two(false, false) == name
|
52
52
|
end
|
53
53
|
|
54
54
|
return degree
|
@@ -246,8 +246,8 @@ class GraphViz
|
|
246
246
|
matrix = GraphViz::Math::Matrix.new( @graph.node_count, @graph.node_count, (1.0/0.0) )
|
247
247
|
|
248
248
|
@graph.each_edge { |e|
|
249
|
-
x = @graph.get_node(e.node_one( false
|
250
|
-
y = @graph.get_node(e.node_two( false
|
249
|
+
x = @graph.get_node(e.node_one(false, false)).index
|
250
|
+
y = @graph.get_node(e.node_two(false, false)).index
|
251
251
|
unless x == y
|
252
252
|
weight = ((e[:weight].nil?) ? 1 : e[:weight].to_f)
|
253
253
|
matrix[x+1, y+1] = weight
|