graph 1.2.0 → 2.0.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.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
|