graph 1.2.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/History.txt +36 -0
- data/Manifest.txt +6 -0
- data/README.txt +21 -18
- data/Rakefile +18 -0
- data/bin/graph +6 -1
- data/gallery/cluster.rb +66 -0
- data/gallery/fsm.rb +49 -0
- data/gallery/ruby_exceptions.rb +20 -0
- data/gallery/simple_example.rb +19 -0
- data/gallery/unix.rb +115 -0
- data/lib/dep_analyzer.rb +36 -6
- data/lib/graph.rb +328 -108
- data/lib/homebrew_analyzer.rb +19 -0
- data/lib/rake_analyzer.rb +19 -22
- data/lib/rubygems_analyzer.rb +25 -4
- data/test/test_graph.rb +227 -90
- metadata +41 -27
- metadata.gz.sig +1 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'dep_analyzer'
|
2
|
+
|
3
|
+
class HomebrewAnalyzer < DepAnalyzer
|
4
|
+
def installed
|
5
|
+
# don't cache so it updates every delete
|
6
|
+
puts "scanning installed ports"
|
7
|
+
`brew list`.scan(/\S+/).map { |s| s.split.first }
|
8
|
+
end
|
9
|
+
|
10
|
+
def outdated
|
11
|
+
# don't cache so it updates every delete
|
12
|
+
puts "scanning outdated ports"
|
13
|
+
`brew outdated`.split(/\n/).map { |s| s.split.first }
|
14
|
+
end
|
15
|
+
|
16
|
+
def deps port
|
17
|
+
`brew deps #{port}`.scan(/\S+/)
|
18
|
+
end
|
19
|
+
end
|
data/lib/rake_analyzer.rb
CHANGED
@@ -2,30 +2,27 @@ require 'dep_analyzer'
|
|
2
2
|
|
3
3
|
class RakeAnalyzer < DepAnalyzer
|
4
4
|
def run
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
digraph do
|
6
|
+
rotate
|
7
|
+
boxes
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
9
|
+
current = nil
|
10
|
+
`rake -P -s`.each_line do |line|
|
11
|
+
case line
|
12
|
+
when /^rake (.+)/
|
13
|
+
name = $1
|
14
|
+
current = name
|
15
|
+
node current if current
|
16
|
+
when /^\s+(.+)/
|
17
|
+
dep = $1
|
18
|
+
next if current =~ /pkg/ and File.file? dep
|
19
|
+
edge current, dep if current
|
20
|
+
else
|
21
|
+
warn "unparsed: #{line.chomp}"
|
22
|
+
end
|
23
23
|
end
|
24
|
-
end
|
25
|
-
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
system "open #{self.class}.png"
|
25
|
+
save "RakeAnalyzer", "png"
|
26
|
+
end
|
30
27
|
end
|
31
28
|
end
|
data/lib/rubygems_analyzer.rb
CHANGED
@@ -1,10 +1,15 @@
|
|
1
1
|
require 'dep_analyzer'
|
2
2
|
|
3
|
+
$a ||= false
|
4
|
+
|
3
5
|
class RubygemsAnalyzer < DepAnalyzer
|
4
|
-
def
|
5
|
-
require
|
6
|
+
def setup
|
7
|
+
require "rubygems"
|
6
8
|
ENV['GEM_PATH'] = `gem env home`
|
7
9
|
Gem.clear_paths
|
10
|
+
end
|
11
|
+
|
12
|
+
def installed
|
8
13
|
# don't cache so it updates every delete
|
9
14
|
puts "scanning installed rubygems"
|
10
15
|
Gem.source_index.gems.values.map { |gem| gem.name }.sort
|
@@ -16,7 +21,23 @@ class RubygemsAnalyzer < DepAnalyzer
|
|
16
21
|
Gem.source_index.outdated.sort
|
17
22
|
end
|
18
23
|
|
19
|
-
def deps
|
20
|
-
Gem.source_index.find_name(
|
24
|
+
def deps gem
|
25
|
+
Gem.source_index.find_name(gem).first.dependencies.map { |dep| dep.name }
|
26
|
+
end
|
27
|
+
|
28
|
+
def decorate
|
29
|
+
developer_dependency = g.gray
|
30
|
+
|
31
|
+
installed = self.installed
|
32
|
+
|
33
|
+
installed.each do |gem|
|
34
|
+
deps = Gem.source_index.find_name(gem).first.dependencies
|
35
|
+
|
36
|
+
deps.each do |dep|
|
37
|
+
next if dep.type == :runtime
|
38
|
+
name = dep.name
|
39
|
+
developer_dependency << g[gem][name] if $a or installed.include? name
|
40
|
+
end
|
41
|
+
end
|
21
42
|
end
|
22
43
|
end
|
data/test/test_graph.rb
CHANGED
@@ -2,123 +2,121 @@ require "minitest/autorun"
|
|
2
2
|
require "tmpdir"
|
3
3
|
require "graph"
|
4
4
|
|
5
|
+
class String
|
6
|
+
def clean
|
7
|
+
gsub(/\s+(\[|\])/, ' \1')
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
5
11
|
class TestGraph < MiniTest::Unit::TestCase
|
12
|
+
attr_accessor :graph
|
13
|
+
|
14
|
+
def assert_attribute k, v, a
|
15
|
+
assert_kind_of Graph::Attribute, a
|
16
|
+
assert_equal "#{k} = #{v}", a.attr
|
17
|
+
end
|
18
|
+
|
19
|
+
def assert_graph graph, *lines
|
20
|
+
lines = lines.map { |l| " #{l};" }.join("\n")
|
21
|
+
expected = "digraph \n {\n#{lines}\n }".sub(/\n\n/, "\n")
|
22
|
+
assert_equal expected, graph.to_s.clean
|
23
|
+
end
|
24
|
+
|
6
25
|
def setup
|
7
26
|
@graph = Graph.new
|
8
|
-
@graph["a"]
|
27
|
+
@graph["a"] >> "b"
|
9
28
|
end
|
10
29
|
|
11
30
|
def test_boxes
|
12
|
-
|
13
|
-
assert_equal expected, @graph.to_s
|
31
|
+
assert_graph graph, '"a" -> "b"'
|
14
32
|
|
15
|
-
|
33
|
+
graph.boxes
|
16
34
|
|
17
|
-
|
18
|
-
'"a" -> "b"')
|
19
|
-
assert_equal expected, @graph.to_s
|
35
|
+
assert_graph graph, 'node [ shape = box ]', '"a" -> "b"'
|
20
36
|
end
|
21
37
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
assert_empty @graph.prefix, "prefix"
|
26
|
-
assert_empty @graph.order, "order"
|
27
|
-
assert_empty @graph.attribs, "attribs"
|
28
|
-
assert_empty @graph.edge, "edge"
|
38
|
+
def test_colorscheme
|
39
|
+
assert_attribute "colorscheme", "blah", graph.colorscheme("blah")
|
29
40
|
end
|
30
41
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
@graph["a"] << "b"
|
36
|
-
@graph["a"] << "c"
|
37
|
-
@graph["b"] << "c"
|
42
|
+
def test_fillcolor
|
43
|
+
assert_attribute "fillcolor", "blah", graph.fillcolor("blah")
|
44
|
+
end
|
38
45
|
|
39
|
-
|
40
|
-
|
46
|
+
def test_font
|
47
|
+
assert_attribute "fontname", '"blah"', graph.font("blah")
|
41
48
|
end
|
42
49
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
50
|
+
def test_font_size
|
51
|
+
# cheating... but I didn't want to write a more complex assertion
|
52
|
+
assert_attribute "fontname", '"blah", fontsize = 12', graph.font("blah", 12)
|
46
53
|
end
|
47
54
|
|
48
|
-
def
|
49
|
-
|
50
|
-
|
55
|
+
def test_digraph
|
56
|
+
g = digraph do
|
57
|
+
edge "a", "b", "c"
|
58
|
+
end
|
59
|
+
|
60
|
+
assert_kind_of Graph, g
|
61
|
+
assert_equal %w(a b c), g.nodes.keys.sort
|
51
62
|
end
|
52
63
|
|
53
|
-
def
|
54
|
-
|
55
|
-
assert_equal expected, @graph.to_s
|
64
|
+
def test_edge
|
65
|
+
@graph = Graph.new
|
56
66
|
|
57
|
-
|
67
|
+
graph.edge "a", "b", "c"
|
58
68
|
|
59
|
-
|
60
|
-
'"b" [ color = blue ]',
|
61
|
-
'"a" -> "b"')
|
62
|
-
assert_equal expected, @graph.to_s
|
69
|
+
assert_graph graph, '"a" -> "b"', '"b" -> "c"'
|
63
70
|
end
|
64
71
|
|
65
72
|
def test_invert
|
66
|
-
|
67
|
-
invert =
|
68
|
-
assert_equal %w(a), invert["b"]
|
69
|
-
assert_equal %w(a), invert["c"]
|
73
|
+
graph["a"] >> "c"
|
74
|
+
invert = graph.invert
|
75
|
+
assert_equal %w(a), invert.edges["b"].keys
|
76
|
+
assert_equal %w(a), invert.edges["c"].keys
|
70
77
|
end
|
71
78
|
|
72
|
-
def
|
73
|
-
|
74
|
-
@graph["d"] << "e" << "f" << "g"
|
75
|
-
assert_equal %w(d a), @graph.keys_by_count
|
76
|
-
end
|
79
|
+
def test_label
|
80
|
+
graph.label "blah"
|
77
81
|
|
78
|
-
|
79
|
-
assert_equal %w(a), @graph.keys.sort
|
80
|
-
assert_equal %w(a b), @graph.nodes.sort
|
82
|
+
assert_graph graph, 'label = "blah"', '"a" -> "b"'
|
81
83
|
end
|
82
84
|
|
83
|
-
def
|
84
|
-
|
85
|
-
@graph["a"] << "b" << "b" << "b" # 3 edges from a to b
|
85
|
+
def test_left_shift
|
86
|
+
subgraph = Graph.new "blah"
|
86
87
|
|
87
|
-
|
88
|
-
assert_equal expect, @graph
|
88
|
+
graph << subgraph
|
89
89
|
|
90
|
-
|
90
|
+
assert_equal graph, subgraph.graph
|
91
|
+
assert_includes graph.subgraphs, subgraph
|
92
|
+
end
|
91
93
|
|
92
|
-
|
93
|
-
assert_equal
|
94
|
+
def test_nodes
|
95
|
+
assert_equal %w(a b), graph.nodes.keys.sort
|
94
96
|
end
|
95
97
|
|
96
98
|
def test_orient
|
97
|
-
|
99
|
+
graph.orient "blah"
|
98
100
|
|
99
|
-
assert_equal ["rankdir = blah"],
|
101
|
+
assert_equal ["rankdir = blah"], graph.graph_attribs
|
100
102
|
end
|
101
103
|
|
102
104
|
def test_orient_default
|
103
|
-
|
104
|
-
|
105
|
-
assert_equal ["rankdir = TB"], @graph.prefix
|
106
|
-
end
|
105
|
+
graph.orient
|
107
106
|
|
108
|
-
|
109
|
-
assert_equal %w(a), @graph.order
|
107
|
+
assert_equal ["rankdir = TB"], graph.graph_attribs
|
110
108
|
end
|
111
109
|
|
112
110
|
def test_rotate
|
113
|
-
|
111
|
+
graph.rotate "blah"
|
114
112
|
|
115
|
-
assert_equal ["rankdir = blah"],
|
113
|
+
assert_equal ["rankdir = blah"], graph.graph_attribs
|
116
114
|
end
|
117
115
|
|
118
116
|
def test_rotate_default
|
119
|
-
|
117
|
+
graph.rotate
|
120
118
|
|
121
|
-
assert_equal ["rankdir = LR"],
|
119
|
+
assert_equal ["rankdir = LR"], graph.graph_attribs
|
122
120
|
end
|
123
121
|
|
124
122
|
def test_save
|
@@ -129,39 +127,72 @@ class TestGraph < MiniTest::Unit::TestCase
|
|
129
127
|
util_save nil
|
130
128
|
end
|
131
129
|
|
130
|
+
def test_shape
|
131
|
+
assert_attribute "shape", "blah", graph.shape("blah")
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_style
|
135
|
+
assert_attribute "style", "blah", graph.style("blah")
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_subgraph
|
139
|
+
n = nil
|
140
|
+
s = graph.subgraph "blah" do
|
141
|
+
n = 42
|
142
|
+
end
|
143
|
+
|
144
|
+
assert_equal graph, s.graph
|
145
|
+
assert_equal "blah", s.name
|
146
|
+
assert_equal 42, n
|
147
|
+
end
|
148
|
+
|
132
149
|
def test_to_s
|
133
|
-
|
134
|
-
assert_equal expected, @graph.to_s
|
150
|
+
assert_graph graph, '"a" -> "b"'
|
135
151
|
|
136
|
-
|
152
|
+
graph["a"] >> "c"
|
137
153
|
|
138
|
-
|
139
|
-
assert_equal expected, @graph.to_s
|
154
|
+
assert_graph graph, '"a" -> "b"', '"a" -> "c"'
|
140
155
|
end
|
141
156
|
|
142
157
|
def test_to_s_attrib
|
143
|
-
|
144
|
-
@graph["a"] << "c"
|
158
|
+
graph.color("blue") << graph["a"]
|
145
159
|
|
146
|
-
|
147
|
-
|
160
|
+
assert_graph graph, '"a" [ color = blue ]', '"a" -> "b"'
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_to_s_edge_attribs
|
164
|
+
graph.edge_attribs << "blah" << "halb"
|
165
|
+
|
166
|
+
assert_graph graph, 'edge [ blah, halb ]', '"a" -> "b"'
|
148
167
|
end
|
149
168
|
|
150
169
|
def test_to_s_empty
|
151
|
-
|
170
|
+
assert_graph Graph.new
|
152
171
|
end
|
153
172
|
|
154
|
-
def
|
155
|
-
|
156
|
-
@graph["a"] << "c"
|
173
|
+
def test_to_s_node_attribs
|
174
|
+
graph.node_attribs << "blah" << "halb"
|
157
175
|
|
158
|
-
|
159
|
-
assert_equal expected, @graph.to_s
|
176
|
+
assert_graph graph, 'node [ blah, halb ]', '"a" -> "b"'
|
160
177
|
end
|
161
178
|
|
162
|
-
def
|
163
|
-
|
164
|
-
|
179
|
+
def test_to_s_subgraph
|
180
|
+
g = Graph.new "subgraph" do
|
181
|
+
edge "a", "c"
|
182
|
+
end
|
183
|
+
|
184
|
+
graph << g
|
185
|
+
|
186
|
+
g_s = "subgraph subgraph
|
187
|
+
{
|
188
|
+
\"a\";
|
189
|
+
\"c\";
|
190
|
+
\"a\" -> \"c\";
|
191
|
+
}"
|
192
|
+
|
193
|
+
assert_graph(graph,
|
194
|
+
g_s, # HACK: indentation is really messy right now
|
195
|
+
'"a" -> "b"')
|
165
196
|
end
|
166
197
|
|
167
198
|
def util_save type
|
@@ -169,16 +200,122 @@ class TestGraph < MiniTest::Unit::TestCase
|
|
169
200
|
|
170
201
|
$x = nil
|
171
202
|
|
172
|
-
def
|
203
|
+
def graph.system(*args)
|
173
204
|
$x = args
|
174
205
|
end
|
175
206
|
|
176
|
-
|
207
|
+
graph.save(path, type)
|
177
208
|
|
178
|
-
assert_equal
|
209
|
+
assert_equal graph.to_s, File.read("#{path}.dot")
|
179
210
|
expected = ["dot -T#{type} #{path}.dot > #{path}.png"] if type
|
180
211
|
assert_equal expected, $x
|
181
212
|
ensure
|
182
213
|
File.unlink path rescue nil
|
183
214
|
end
|
184
215
|
end
|
216
|
+
|
217
|
+
class TestAttribute < MiniTest::Unit::TestCase
|
218
|
+
attr_accessor :a
|
219
|
+
|
220
|
+
def setup
|
221
|
+
self.a = Graph::Attribute.new "blah"
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_lshift
|
225
|
+
n = Graph::Node.new nil, nil
|
226
|
+
|
227
|
+
a << n
|
228
|
+
|
229
|
+
assert_equal [a], n.attributes
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_plus
|
233
|
+
b = Graph::Attribute.new "halb"
|
234
|
+
|
235
|
+
c = a + b
|
236
|
+
|
237
|
+
assert_equal "blah, halb", c.attr
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_to_s
|
241
|
+
assert_equal "blah", a.to_s
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
class TestNode < MiniTest::Unit::TestCase
|
246
|
+
attr_accessor :n
|
247
|
+
|
248
|
+
def setup
|
249
|
+
self.n = Graph::Node.new :graph, "n"
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_rshift
|
253
|
+
graph = Graph.new
|
254
|
+
self.n = graph.node "blah"
|
255
|
+
|
256
|
+
n2 = n >> "halb"
|
257
|
+
to = graph["halb"]
|
258
|
+
e = graph.edges["blah"]["halb"]
|
259
|
+
|
260
|
+
assert_equal n, n2
|
261
|
+
assert_kind_of Graph::Edge, e
|
262
|
+
assert_kind_of Graph::Node, to
|
263
|
+
assert_equal n, e.from
|
264
|
+
assert_equal to, e.to
|
265
|
+
end
|
266
|
+
|
267
|
+
def test_index
|
268
|
+
graph = Graph.new
|
269
|
+
self.n = graph.node "blah"
|
270
|
+
|
271
|
+
e = n["halb"]
|
272
|
+
to = graph["halb"]
|
273
|
+
|
274
|
+
assert_kind_of Graph::Edge, e
|
275
|
+
assert_kind_of Graph::Node, to
|
276
|
+
assert_equal n, e.from
|
277
|
+
assert_equal to, e.to
|
278
|
+
end
|
279
|
+
|
280
|
+
def test_label
|
281
|
+
n.label "blah"
|
282
|
+
|
283
|
+
assert_equal ["label = \"blah\""], n.attributes
|
284
|
+
end
|
285
|
+
|
286
|
+
def test_to_s
|
287
|
+
assert_equal '"n"', n.to_s
|
288
|
+
end
|
289
|
+
|
290
|
+
def test_to_s_attribs
|
291
|
+
n.attributes << "blah"
|
292
|
+
|
293
|
+
assert_equal '"n" [ blah ]', n.to_s.clean
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
class TestEdge < MiniTest::Unit::TestCase
|
298
|
+
attr_accessor :e
|
299
|
+
|
300
|
+
def setup
|
301
|
+
a = Graph::Node.new :graph, "a"
|
302
|
+
b = Graph::Node.new :graph, "b"
|
303
|
+
self.e = Graph::Edge.new :graph, a, b
|
304
|
+
end
|
305
|
+
|
306
|
+
def test_label
|
307
|
+
e.label "blah"
|
308
|
+
|
309
|
+
assert_equal ["label = \"blah\""], e.attributes
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_to_s
|
313
|
+
assert_equal '"a" -> "b"', e.to_s
|
314
|
+
end
|
315
|
+
|
316
|
+
def test_to_s_attribs
|
317
|
+
e.attributes << "blah"
|
318
|
+
|
319
|
+
assert_equal '"a" -> "b" [ blah ]', e.to_s.clean
|
320
|
+
end
|
321
|
+
end
|