rgl 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/ChangeLog +19 -10
  2. data/Gemfile +3 -0
  3. data/{README → README.rdoc} +70 -98
  4. data/Rakefile +44 -150
  5. data/examples/canvas.rb +63 -64
  6. data/examples/examples.rb +42 -42
  7. data/examples/graph.dot +46 -0
  8. data/examples/images/example.jpg +0 -0
  9. data/examples/images/module_graph.jpg +0 -0
  10. data/examples/images/rgl_modules.png +0 -0
  11. data/examples/{insel-der-tausend-gefahren.rb → insel_der_tausend_gefahren.rb} +18 -19
  12. data/examples/north.rb +2 -2
  13. data/examples/north2.rb +11 -11
  14. data/examples/rdep-rgl.rb +218 -222
  15. data/lib/rgl/adjacency.rb +78 -74
  16. data/lib/rgl/base.rb +160 -78
  17. data/lib/rgl/bellman_ford.rb +115 -0
  18. data/lib/rgl/bidirectional.rb +17 -10
  19. data/lib/rgl/bipartite.rb +87 -0
  20. data/lib/rgl/condensation.rb +13 -4
  21. data/lib/rgl/connected_components.rb +38 -30
  22. data/lib/rgl/dijkstra.rb +158 -0
  23. data/lib/rgl/dijkstra_visitor.rb +42 -0
  24. data/lib/rgl/dot.rb +40 -32
  25. data/lib/rgl/edge_properties_map.rb +55 -0
  26. data/lib/rgl/edmonds_karp.rb +136 -0
  27. data/lib/rgl/enumerable_ext.rb +4 -1
  28. data/lib/rgl/graph_iterator.rb +15 -0
  29. data/lib/rgl/graph_visitor.rb +138 -0
  30. data/lib/rgl/graph_wrapper.rb +15 -0
  31. data/lib/rgl/graphxml.rb +20 -10
  32. data/lib/rgl/implicit.rb +68 -66
  33. data/lib/rgl/mutable.rb +37 -31
  34. data/lib/rgl/path_builder.rb +40 -0
  35. data/lib/rgl/prim.rb +52 -0
  36. data/lib/rgl/rdot.rb +411 -374
  37. data/lib/rgl/topsort.rb +23 -16
  38. data/lib/rgl/transitivity.rb +29 -27
  39. data/lib/rgl/traversal.rb +67 -205
  40. data/rakelib/dep_graph.rake +4 -3
  41. data/test/bellman_ford_test.rb +187 -0
  42. data/test/bipartite_test.rb +47 -0
  43. data/test/components_test.rb +80 -0
  44. data/test/cycles_test.rb +60 -0
  45. data/test/dijkstra_test.rb +148 -0
  46. data/test/directed_graph_test.rb +118 -0
  47. data/test/dot_test.rb +26 -0
  48. data/test/edge_properties_map_test.rb +63 -0
  49. data/test/edge_test.rb +35 -0
  50. data/test/edmonds_karp_test.rb +105 -0
  51. data/{tests/TestGraph.rb → test/graph_test.rb} +6 -6
  52. data/test/graph_xml_test.rb +57 -0
  53. data/test/implicit_test.rb +53 -0
  54. data/test/prim_test.rb +98 -0
  55. data/{tests/TestRdot.rb → test/rdot_test.rb} +309 -308
  56. data/{tests → test}/test_helper.rb +4 -1
  57. data/{tests/TestTransitivity.rb → test/transitivity_test.rb} +43 -43
  58. data/test/traversal_test.rb +221 -0
  59. data/test/undirected_graph_test.rb +103 -0
  60. metadata +226 -145
  61. data/examples/example.jpg +0 -0
  62. data/examples/module_graph.jpg +0 -0
  63. data/install.rb +0 -49
  64. data/tests/TestComponents.rb +0 -65
  65. data/tests/TestCycles.rb +0 -61
  66. data/tests/TestDirectedGraph.rb +0 -125
  67. data/tests/TestDot.rb +0 -18
  68. data/tests/TestEdge.rb +0 -34
  69. data/tests/TestGraphXML.rb +0 -57
  70. data/tests/TestImplicit.rb +0 -52
  71. data/tests/TestTraversal.rb +0 -220
  72. data/tests/TestUnDirectedGraph.rb +0 -102
@@ -6,7 +6,7 @@ include RGL
6
6
 
7
7
  Dir['north/*.graphml'].each do |filename|
8
8
  File.open(filename) { |file|
9
- graph = DirectedAdjacencyGraph.from_graphxml(file)
10
- graph.write_to_graphic_file('jpg',filename)
9
+ graph = DirectedAdjacencyGraph.from_graphxml(file)
10
+ graph.write_to_graphic_file('jpg', filename)
11
11
  }
12
12
  end
@@ -3,19 +3,19 @@ require 'rgl/adjacency'
3
3
  require 'rgl/dot'
4
4
 
5
5
  include RGL
6
- name,nnodes,nedges = '','',''
7
- IO.foreach('north/Graph.log') {
8
- |line|
6
+ name, nnodes, nedges = '', '', ''
7
+
8
+ IO.foreach('north/Graph.log') { |line|
9
9
  if /name:\s*(.*)\sformat: graphml\s+nodes: (\d+)\s+edges: (\d+)/ =~ line
10
- name,nnodes,nedges = $1,$2.to_i,$3.to_i
10
+ name, nnodes, nedges = $1, $2.to_i, $3.to_i
11
11
  end
12
+
12
13
  if name && /directed: (.*)\s+acyclic: (.*)\s+.*connected: (.*)\s+biconnected: (.*)\s+/ =~ line
13
- directed, acyclic, connected, biconnected = $1,$2,$3,$4
14
- puts [name,nnodes,nedges].join('-|-')
15
- File.open('north/' + name + '.graphml') {
16
- |file|
17
- graph = DirectedAdjacencyGraph.from_graphxml(file)
18
- puts "#{graph.num_vertices} = #{nnodes}"
19
- }
14
+ directed, acyclic, connected, biconnected = $1, $2, $3, $4
15
+ puts [name, nnodes, nedges].join('-|-')
16
+ File.open('north/' + name + '.graphml') { |file|
17
+ graph = DirectedAdjacencyGraph.from_graphxml(file)
18
+ puts "#{graph.num_vertices} = #{nnodes}"
19
+ }
20
20
  end
21
21
  }
@@ -1,11 +1,9 @@
1
- #
2
- # $Id: rdep-rgl.rb,v 1.1 2002/11/13 23:30:25 monora Exp $
3
- #
1
+ #
4
2
  # Simple extensions of Hal Fultons tool to show dependencies between ruby
5
3
  # source files (see http://hypermetrics.com/rubyhacker/code/rdep/). The basic
6
4
  # extensions can be found at the end of the function find_files.
7
5
  #
8
- # Source: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/rgl/rgl/examples/rdep-rgl.rb
6
+ # Source: [http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/rgl/rgl/examples/rdep-rgl.rb]
9
7
  #
10
8
  # Additionaly rdep-rgl.rb generates a graphics file named
11
9
  # File.basename(ARGV[0]) + ".png".
@@ -16,7 +14,7 @@
16
14
  # ruby rdep-rgl.rb j:/ruby/lib/ruby/site_ruby/1.6/rdoc/rdoc.rb
17
15
  #
18
16
  # produces the following graph: link:rdoc.rb.png
19
- #
17
+ #
20
18
  require 'rgl/adjacency'
21
19
  require 'rgl/dot'
22
20
 
@@ -31,7 +29,7 @@ Ruby's license
31
29
 
32
30
  Purpose
33
31
 
34
- Determine the library files on which a specified Ruby file is dependent
32
+ Determine the library files on which a specified Ruby file is dependent
35
33
  (and their location and availability).
36
34
 
37
35
  Usage notes
@@ -40,33 +38,33 @@ Usage notes
40
38
 
41
39
  The sourcefile may or may not have a .rb extension.
42
40
 
43
- The directories in the $: array (which includes the RUBYLIB environment
44
- variable) are searched first. File extensions are currently searched for
41
+ The directories in the $: array (which includes the RUBYLIB environment
42
+ variable) are searched first. File extensions are currently searched for
45
43
  in this order: no extension, .rb, .o, .so, .dll (this may not be correct).
46
44
 
47
45
  If there are no detected dependencies, the program will give the
48
46
  message, "No dependencies found."
49
47
 
50
- If the program finds [auto]load and require statements that it can
51
- understand, it searches for the specified files. Any recognized Ruby
52
- source files (*.rb) are processed recursively in the same way. No attempt
48
+ If the program finds [auto]load and require statements that it can
49
+ understand, it searches for the specified files. Any recognized Ruby
50
+ source files (*.rb) are processed recursively in the same way. No attempt
53
51
  is made to open the files that appear to be binary.
54
52
 
55
53
  The program will print up to four lists (any or all may be omitted):
56
54
  1. A list of files it found by going through RUBYLIB.;
57
55
  2. A list of files found under the searchroot (or under '.');
58
- 3. A list of directories under searchroot which should perhaps be
56
+ 3. A list of directories under searchroot which should perhaps be
59
57
  added to RUBYLIB; and
60
58
  4. A list of files (without extensions) which could not be found.
61
59
 
62
- If there were unparseable [auto]load or require statements, a warning
60
+ If there were unparseable [auto]load or require statements, a warning
63
61
  will be issued.
64
62
 
65
63
  Between lists 3 and 4, the program will give an opinion about the overall
66
64
  situation. The worst case is that files were not found; the uncertain
67
- case is when there were unparseable statements; and the best case is
65
+ case is when there were unparseable statements; and the best case is
68
66
  when all files could be found (lists 1 and 2).
69
-
67
+
70
68
  Exit codes
71
69
 
72
70
  0 - Usage or successful execution
@@ -141,241 +139,240 @@ end
141
139
  class Dependency
142
140
  attr_reader :graph
143
141
 
144
- #
145
- # unquote - Find the value of a string. Called from scan.
146
- #
142
+ #
143
+ # unquote - Find the value of a string. Called from scan.
144
+ #
147
145
 
148
- def unquote(str)
149
- # Still more kludgy code.
150
- return nil if str == nil
151
- if [?', ?"].include? str[0] # ' Unconfuse gvim
152
- str = str[1..-2]
153
- else
154
- ""
146
+ def unquote(str)
147
+ # Still more kludgy code.
148
+ return nil if str == nil
149
+ if [?', ?"].include? str[0] # ' Unconfuse gvim
150
+ str = str[1..-2]
151
+ else
152
+ ""
153
+ end
155
154
  end
156
- end
157
155
 
158
- #
159
- # scan - Scans a line and returns the filename from a load or require
160
- # statement. Returns null string if there was a parsing problem.
161
- # Returns nil if this is not a load or require.
162
- #
156
+ #
157
+ # scan - Scans a line and returns the filename from a load or require
158
+ # statement. Returns null string if there was a parsing problem.
159
+ # Returns nil if this is not a load or require.
160
+ #
163
161
 
164
- def scan(line)
165
- line.strip!
166
- if line =~ /^load/ or line =~ /^auto/ or line =~ /^require/
167
- @has_dep = true # At least one dependency found.
168
- # Kludge!!
169
- junk = %w[ require load autoload ( ) , ] + [""]
170
- temp = line.split(/[ \t\(\),]/) - junk
171
- if temp[2] and temp[2][0].chr =~ /[#;]/ # Comments, semi...
172
- temp = temp[0..1]
173
- end
174
- if temp[-1] =~ /\#\{/ # #{} means trouble
175
- str = ""
162
+ def scan(line)
163
+ line.strip!
164
+ if line =~ /^load/ or line =~ /^auto/ or line =~ /^require/
165
+ @has_dep = true # At least one dependency found.
166
+ # Kludge!!
167
+ junk = %w[ require load autoload ( ) , ] + [""]
168
+ temp = line.split(/[ \t\(\),]/) - junk
169
+ if temp[2] and temp[2][0].chr =~ /[#;]/ # Comments, semi...
170
+ temp = temp[0..1]
171
+ end
172
+ if temp[-1] =~ /\#\{/ # #{} means trouble
173
+ str = ""
174
+ else
175
+ str = unquote(temp[-1]) # May return nil.
176
+ end
177
+ str
176
178
  else
177
- str = unquote(temp[-1]) # May return nil.
179
+ nil
178
180
  end
179
- str
180
- else
181
- nil
182
181
  end
183
- end
184
182
 
185
183
  #
186
184
  # find_files - The heart of the program. Search for files using $:
187
185
  #
188
186
 
189
- def find_files(source)
190
- # loadable - This file or some variant can be found in one of the
191
- # directories in $:
192
- loadable = false
193
-
194
- files = [] # Save a list of load/require files.
195
- found = [] # Save a list of files found (.rb only for now)
196
-
197
- # Open the file, strip embedded docs, and look for load/require statements.
198
-
199
- begin
200
- File.open(source).doc_skip {|line| files << scan(line)}
201
- rescue => err
202
- puts "Problem processing file #{source}: #{err}"
203
- caller.each {|x| puts " #{x}"}
204
- exit 3
205
- end
187
+ def find_files(source)
188
+ # loadable - This file or some variant can be found in one of the
189
+ # directories in $:
190
+ loadable = false
206
191
 
207
- # If no dependencies, don't bother searching!
208
- if ! @has_dep
209
- puts "No dependencies found."
210
- exit 0
211
- end
192
+ files = [] # Save a list of load/require files.
193
+ found = [] # Save a list of files found (.rb only for now)
212
194
 
213
- files.compact!
214
- catch(:skip) do
215
- for file in files
216
-
217
- if file == "" # Warning
218
- @warnfiles << source
219
- next
220
- end
221
-
222
- throw :skip if (@inpath.include? file) || (@cantfind.include? file)
223
-
224
- if file =~ /\.rb$/ then # Don't add suffix to *.rb
225
- suffixes = [""] # Hmm... .rbw?? Probably not needed.
226
- else
227
- suffixes = @suffixes # Use any suffix (extension)
228
- end
229
-
230
- # Look through search path (@search_path)
231
-
232
- for dir in @search_path
233
-
234
- for suf in suffixes
235
- filename = dir + file + suf
236
- loadable = test ?e, filename
237
- break if loadable
195
+ # Open the file, strip embedded docs, and look for load/require statements.
196
+
197
+ begin
198
+ File.open(source).doc_skip { |line| files << scan(line) }
199
+ rescue => err
200
+ puts "Problem processing file #{source}: #{err}"
201
+ caller.each { |x| puts " #{x}" }
202
+ exit 3
203
+ end
204
+
205
+ # If no dependencies, don't bother searching!
206
+ if !@has_dep
207
+ puts "No dependencies found."
208
+ exit 0
209
+ end
210
+
211
+ files.compact!
212
+ catch(:skip) do
213
+ for file in files
214
+
215
+ if file == "" # Warning
216
+ @warnfiles << source
217
+ next
238
218
  end
239
-
240
- if loadable
241
- @inpath << filename # Files we found in RUBYLIB
242
- # Add to 'found' if it's a source file (so we can recurse)
243
- found << filename if filename =~ /\.rb$/
244
- break
219
+
220
+ throw :skip if (@inpath.include? file) || (@cantfind.include? file)
221
+
222
+ if file =~ /\.rb$/ # Don't add suffix to *.rb
223
+ suffixes = [""] # Hmm... .rbw?? Probably not needed.
224
+ else
225
+ suffixes = @suffixes # Use any suffix (extension)
245
226
  end
246
-
247
- end
248
-
249
- @cantfind << file if !loadable
250
- end
251
- end
252
227
 
253
- found.uniq!
254
- found.compact!
228
+ # Look through search path (@search_path)
255
229
 
256
- @graph.add_vertex(source)
230
+ for dir in @search_path
257
231
 
258
- list = found
259
- found.each {
260
- |x|
261
- @graph.add_edge(source,x)
262
- list += find_files(x)
263
- }
264
-
265
- list
266
- end
232
+ for suf in suffixes
233
+ filename = dir + file + suf
234
+ loadable = test ?e, filename
235
+ break if loadable
236
+ end
267
237
 
268
- #
269
- # print_list - Print a header message followed by a list of files
270
- # or directories.
271
- #
238
+ if loadable
239
+ @inpath << filename # Files we found in RUBYLIB
240
+ # Add to 'found' if it's a source file (so we can recurse)
241
+ found << filename if filename =~ /\.rb$/
242
+ break
243
+ end
272
244
 
273
- def print_list(header, list)
274
- return if list.empty?
275
- puts header + "\n\n" # Extra newlines
276
- list.each {|x| puts " #{x}"}
277
- puts "\n" # Extra newline
278
- end
245
+ end
279
246
 
280
- SEP = File::Separator
281
- DIRSEP = if SEP=="/" then ":" else ";" end
282
-
283
- def execute
284
- @has_dep = false
285
- @warnfiles = []
286
- @newdirs = []
287
- @inpath = []
288
- @cantfind = []
289
- @suffixes = [""] + %w[ .rb .o .so .dll ]
290
- @rdirs = []
291
- @global_found = []
292
- @graph = RGL::DirectedAdjacencyGraph.new
293
-
294
- # No parameters? Usage message
295
-
296
- if not ARGV[0]
297
- puts "Usage: ruby rdep.rb sourcefile [searchroot]"
298
- exit 0
299
- end
300
-
301
- # Does sourcefile exist?
302
-
303
- if ! test ?e, ARGV[0]
304
- puts "#{ARGV[0]} does not exist."
305
- exit 1
306
- end
307
-
308
- # Is sourcefile a "real" file?
309
-
310
- if ! test ?f, ARGV[0]
311
- puts "#{ARGV[0]} is not a regular file."
312
- exit 2
313
- end
247
+ @cantfind << file if !loadable
248
+ end
249
+ end
250
+
251
+ found.uniq!
252
+ found.compact!
314
253
 
315
- # Be sure to search under the dir where the
316
- # program lives...
254
+ @graph.add_vertex(source)
317
255
 
318
- @proghome = File.dirname(File.expand_path(ARGV[0]))
319
- if @proghome != File.expand_path(".")
320
- $: << @proghome
256
+ list = found
257
+ found.each { |x|
258
+ @graph.add_edge(source, x)
259
+ list += find_files(x)
260
+ }
261
+
262
+ list
321
263
  end
322
-
323
- # Get list of dirs in $:
324
-
325
- @search_path = $:
326
- @search_path.collect! {|x| x[-1] == SEP ? x : x + SEP }
327
-
328
- # All real work happens here -- big recursive find
329
-
330
- find_files(ARGV[0])
331
-
332
- @warnfiles.uniq!
333
- @cantfind.uniq!
334
- @newdirs.uniq!
335
- @inpath.map! {|x| File.expand_path(x)}
336
- @inpath.uniq!
337
-
264
+
338
265
  #
339
- # Now, what are all the results? Report to user.
266
+ # print_list - Print a header message followed by a list of files
267
+ # or directories.
340
268
  #
341
-
342
- if @inpath[0]
343
- print_list("Found in search path:", @inpath)
344
- if ! @cantfind.empty? && @warnfiles.empty?
345
- puts "This will probably be sufficient.\n"
346
- end
269
+
270
+ def print_list(header, list)
271
+ return if list.empty?
272
+ puts header + "\n\n" # Extra newlines
273
+ list.each { |x| puts " #{x}" }
274
+ puts "\n" # Extra newline
347
275
  end
348
276
 
349
- # Did we use any dirs under the "home"?
277
+ SEP = File::Separator
278
+ DIRSEP = SEP == "/" ? ":" : ";"
279
+
280
+ def execute
281
+ @has_dep = false
282
+ @warnfiles = []
283
+ @newdirs = []
284
+ @inpath = []
285
+ @cantfind = []
286
+ @suffixes = [""] + %w[ .rb .o .so .dll ]
287
+ @rdirs = []
288
+ @global_found = []
289
+ @graph = RGL::DirectedAdjacencyGraph.new
290
+
291
+ # No parameters? Usage message
292
+
293
+ if not ARGV[0]
294
+ puts "Usage: ruby rdep.rb sourcefile [searchroot]"
295
+ exit 0
296
+ end
297
+
298
+ # Does sourcefile exist?
299
+
300
+ if !test ?e, ARGV[0]
301
+ puts "#{ARGV[0]} does not exist."
302
+ exit 1
303
+ end
304
+
305
+ # Is sourcefile a "real" file?
306
+
307
+ if !test ?f, ARGV[0]
308
+ puts "#{ARGV[0]} is not a regular file."
309
+ exit 2
310
+ end
311
+
312
+ # Be sure to search under the dir where the
313
+ # program lives...
314
+
315
+ @proghome = File.dirname(File.expand_path(ARGV[0]))
316
+ if @proghome != File.expand_path(".")
317
+ $: << @proghome
318
+ end
319
+
320
+ # Get list of dirs in $:
350
321
 
351
- homedirs = @inpath.find_all {|x| x =~ Regexp.new("^"+@proghome)}
352
- if homedirs[0] # not empty
353
- homedirs.map! {|x| File.dirname(x) }.uniq!
354
- puts "Consider adding these directories to RUBYPATH:\n\n"
355
- homedirs.each {|x| puts " #{x}" }
356
- puts
357
- if @warnfiles[0] and homedirs == [] # There are unparseable statements.
322
+ @search_path = $:
323
+ @search_path.collect! { |x| x[-1] == SEP ? x : x + SEP }
324
+
325
+ # All real work happens here -- big recursive find
326
+
327
+ find_files(ARGV[0])
328
+
329
+ @warnfiles.uniq!
330
+ @cantfind.uniq!
331
+ @newdirs.uniq!
332
+ @inpath.map! { |x| File.expand_path(x) }
333
+ @inpath.uniq!
334
+
335
+ #
336
+ # Now, what are all the results? Report to user.
337
+ #
338
+
339
+ if @inpath[0]
340
+ print_list("Found in search path:", @inpath)
341
+ if !@cantfind.empty? && @warnfiles.empty?
342
+ puts "This will probably be sufficient.\n"
343
+ end
344
+ end
345
+
346
+ # Did we use any dirs under the "home"?
347
+
348
+ homedirs = @inpath.find_all { |x| x =~ Regexp.new("^"+@proghome) }
349
+ if homedirs[0] # not empty
350
+ homedirs.map! { |x| File.dirname(x) }.uniq!
351
+ puts "Consider adding these directories to RUBYPATH:\n\n"
352
+ homedirs.each { |x| puts " #{x}" }
353
+ puts
354
+ if @warnfiles[0] and homedirs == [] # There are unparseable statements.
355
+ puts "This will probably NOT be sufficient. See below.\n\n"
356
+ end
357
+ end
358
+
359
+ # What's our opinion?
360
+
361
+ if @cantfind[0] # There are unknown files.
358
362
  puts "This will probably NOT be sufficient. See below.\n\n"
363
+ elsif @warnfiles[0] and homedirs == [] # There are unparseable statements.
364
+ puts "Files may still be missing. See below.\n\n"
365
+ else # We think everything is OK.
366
+ puts "This will probably be sufficient."
359
367
  end
368
+
369
+ # Report unknown files
370
+ print_list("Not located anywhere:", @cantfind)
371
+
372
+ # Print warning about load/require strings we couldn't understand
373
+ print_list("Warning: Unparseable usages of 'load' or 'require' in:",
374
+ @warnfiles)
360
375
  end
361
-
362
- # What's our opinion?
363
-
364
- if @cantfind[0] # There are unknown files.
365
- puts "This will probably NOT be sufficient. See below.\n\n"
366
- elsif @warnfiles[0] and homedirs == [] # There are unparseable statements.
367
- puts "Files may still be missing. See below.\n\n"
368
- else # We think everything is OK.
369
- puts "This will probably be sufficient."
370
- end
371
-
372
- # Report unknown files
373
- print_list("Not located anywhere:", @cantfind)
374
-
375
- # Print warning about load/require strings we couldn't understand
376
- print_list("Warning: Unparseable usages of 'load' or 'require' in:",
377
- @warnfiles)
378
- end
379
376
 
380
377
  end
381
378
 
@@ -383,13 +380,12 @@ d = Dependency.new
383
380
  d.execute
384
381
  begin
385
382
  d.graph.write_to_graphic_file('png',
386
- File.basename(ARGV[0]),
387
- 'label'=>"Dependencies of #{ARGV[0]}")
383
+ File.basename(ARGV[0]),
384
+ 'label' => "Dependencies of #{ARGV[0]}")
388
385
  rescue ArgumentError
389
386
  d.graph.write_to_graphic_file('png',
390
- File.basename(ARGV[0]))
387
+ File.basename(ARGV[0]))
391
388
  end
392
389
 
393
-
394
- exit 0
395
390
 
391
+ exit 0