rdot 1.0.4

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.
Files changed (5) hide show
  1. data/.yardopts +9 -0
  2. data/README.md +152 -0
  3. data/bin/rdot +531 -0
  4. data/lib/rdot.rb +762 -0
  5. metadata +67 -0
@@ -0,0 +1,762 @@
1
+ # encoding: utf-8
2
+
3
+ require 'is/monkey/sandbox'
4
+ require 'is/monkey/namespace'
5
+
6
+ # @private
7
+ class Module
8
+
9
+ def module_scope
10
+ m = self.inspect
11
+ if m[0...8] == '#<Class:'
12
+ s = m.rindex '>'
13
+ v = m[8...s]
14
+ begin
15
+ value = sandbox { eval v }
16
+ return [value, :class]
17
+ rescue
18
+ return [nil, nil]
19
+ end
20
+ else
21
+ return [self, :instance]
22
+ end
23
+ end
24
+
25
+ alias :rdot_old_attr :attr
26
+ alias :rdot_old_attr_reader :attr_reader
27
+ alias :rdot_old_attr_writer :attr_writer
28
+ alias :rdot_old_attr_accessor :attr_accessor
29
+
30
+ def parse_caller clr
31
+ clr.each do |s|
32
+ if s.include?('`<module:') || s.include?('`<class:') ||
33
+ s.include?("`singletonclass'") || s.include?('`block in <')
34
+ a = s.split(':')
35
+ begin
36
+ return [a[0], a[1].to_i]
37
+ rescue
38
+ end
39
+ end
40
+ end
41
+ return nil
42
+ end
43
+
44
+ def attr *names
45
+ RDot.register_attribute *module_scope, names, '[r]', parse_caller(caller)
46
+ rdot_old_attr *names
47
+ end
48
+
49
+ def attr_reader *names
50
+ RDot.register_attribute *module_scope, names, '[r]', parse_caller(caller)
51
+ rdot_old_attr_reader *names
52
+ end
53
+
54
+ def attr_writer *names
55
+ RDot.register_attribute *module_scope, names, '[w]', parse_caller(caller)
56
+ rdot_old_attr_writer *names
57
+ end
58
+
59
+ def attr_accessor *names
60
+ RDot.register_attribute *module_scope, names, '[rw]', parse_caller(caller)
61
+ rdot_old_attr_accessor *names
62
+ end
63
+
64
+ private :module_scope, :parse_caller, :attr, :attr_reader, :attr_writer,
65
+ :attr_accessor, :rdot_old_attr, :rdot_old_attr_accessor,
66
+ :rdot_old_attr_reader, :rdot_old_attr_writer
67
+
68
+ end
69
+
70
+ module RDot
71
+
72
+ VERSION = '1.0.4'
73
+
74
+ class << self
75
+
76
+ # @private
77
+ def register_attribute mod, scope, names, access, source
78
+ @attributes ||= {}
79
+ @attributes[mod] ||= {}
80
+ @attributes[mod][scope] ||= {}
81
+ names.each do |name|
82
+ @attributes[mod][scope][name.intern] = {
83
+ :access => access,
84
+ :source => source
85
+ }
86
+ end
87
+ end
88
+
89
+ # @private
90
+ def get_file file
91
+ src = File.expand_path file
92
+ $:.each do |dir|
93
+ dir = File.expand_path dir
94
+ len = dir.length
95
+ if src[0...len] == dir
96
+ src = src[len..-1]
97
+ if src[0] == '/'
98
+ src = src[1..-1]
99
+ end
100
+ return src
101
+ end
102
+ end
103
+ return file
104
+ end
105
+
106
+ # @private
107
+ def get_method_object mod, scope, name
108
+ case scope
109
+ when :instance
110
+ mod.instance_method(name)
111
+ when :class
112
+ mod.singleton_class.instance_method(name)
113
+ end
114
+ end
115
+
116
+ # @private
117
+ def add_method acc, mod, scope, visibility, name, opts
118
+ m = get_method_object mod, scope, name
119
+ src = m.source_location
120
+ obj = {}
121
+ nm = name.to_s
122
+ nm = nm[0..-2] if nm[-1] == '='
123
+ nm = nm.intern
124
+ if @attributes && @attributes[mod] && @attributes[mod][scope] &&
125
+ @attributes[mod][scope][nm]
126
+ src = @attributes[mod][scope][nm][:source]
127
+ obj[:access] = @attributes[mod][scope][nm][:access]
128
+ end
129
+ if src
130
+ obj[:file] = get_file src[0]
131
+ obj[:line] = src[1]
132
+ if opts[:exclude_files]
133
+ opts[:exclude_files].each do |f|
134
+ if File.expand_path(f) == File.expand_path(src[0])
135
+ return nil
136
+ end
137
+ end
138
+ end
139
+ if opts[:filter_files]
140
+ opts[:filter_files].each do |f|
141
+ if File.expand_path(f) != File.expand_path(src[0])
142
+ return nil
143
+ end
144
+ end
145
+ end
146
+ elsif opts[:filter_files]
147
+ return nil
148
+ end
149
+ acc[scope] ||= {}
150
+ acc[scope][visibility] ||= {}
151
+ if opts[:select_attributes] && obj[:access]
152
+ obj[:signature] = nm.to_s + ' ' + obj[:access]
153
+ acc[scope][visibility][:attributes] ||= {}
154
+ acc[scope][visibility][:attributes][nm] = obj
155
+ else
156
+ if ! opts[:hide_arguments]
157
+ ltr = 'a'
158
+ obj[:signature] = name.to_s + '(' + m.parameters.map do |q, n|
159
+ nm = n || ltr
160
+ ltr = ltr.succ
161
+ case q
162
+ when :req
163
+ nm
164
+ when :opt
165
+ "#{nm} = <…>"
166
+ when :rest
167
+ "*#{nm}"
168
+ when :block
169
+ "&#{nm}"
170
+ end
171
+ end.join(', ') + ')'
172
+ else
173
+ obj[:signature] = name.to_s + '()'
174
+ end
175
+ acc[scope][visibility][:methods] ||= {}
176
+ acc[scope][visibility][:methods][name] = obj
177
+ end
178
+ return obj
179
+ end
180
+
181
+ # @private
182
+ def get_module mod, opts
183
+ result = {}
184
+ result[:module] = mod
185
+ incs = mod.included_modules - [mod]
186
+ exts = mod.singleton_class.included_modules - Module.included_modules
187
+ if Class === mod
188
+ exts -= Class.included_modules
189
+ result[:superclass] = mod.superclass && mod.superclass.inspect || nil
190
+ if mod.superclass
191
+ incs -= mod.superclass.included_modules
192
+ exts -= mod.superclass.singleton_class.included_modules
193
+ end
194
+ end
195
+ incs.dup.each { |d| incs -= d.included_modules }
196
+ exts.dup.each { |d| exts -= d.included_modules }
197
+ result[:included] = incs.map &:inspect
198
+ result[:extended] = exts.map &:inspect
199
+ result[:nested] = mod.namespace && mod.namespace.inspect || nil
200
+ if opts[:no_scan]
201
+ return result
202
+ end
203
+ if ! opts[:hide_constants]
204
+ result[:constants] = {}
205
+ mod.constants(false).each do |c|
206
+ next if mod == Object && c == :Config
207
+ if (auto = mod.autoload?(c))
208
+ result[:constants][c] = 'auto:' + get_file(auto)
209
+ elsif mod.const_defined? c
210
+ result[:constants][c] = mod.const_get(c).class.inspect
211
+ else
212
+ result[:constants][c] = 'undefined'
213
+ end
214
+ end
215
+ end
216
+ if ! opts[:hide_methods]
217
+ mod.public_instance_methods(false).each do |m|
218
+ add_method result, mod, :instance, :public, m, opts
219
+ end
220
+ mod.singleton_class.public_instance_methods(false).each do |m|
221
+ add_method result, mod, :class, :public, m, opts
222
+ end
223
+ if opts[:show_protected]
224
+ mod.protected_instance_methods(false).each do |m|
225
+ add_method result, mod, :instance, :protected, m, opts
226
+ end
227
+ mod.singleton_class.protected_instance_methods(false).each do |m|
228
+ add_method result, mod, :class, :protected, m, opts
229
+ end
230
+ end
231
+ if opts[:show_private]
232
+ mod.private_instance_methods(false).each do |m|
233
+ add_method result, mod, :instance, :private, m, opts
234
+ end
235
+ mod.singleton_class.private_instance_methods(false).each do |m|
236
+ add_method result, mod, :class, :private, m, opts
237
+ end
238
+ end
239
+ end
240
+ result
241
+ end
242
+
243
+ # @private
244
+ def add_module acc, mod, opts
245
+ if opts[:exclude_classes]
246
+ opts[:exclude_classes].each do |c|
247
+ return nil if mod <= c
248
+ end
249
+ end
250
+ if opts[:filter_classes]
251
+ opts[:filter_classes].each do |c|
252
+ return nil unless mod <= c
253
+ end
254
+ end
255
+ if opts[:exclude_namespaces]
256
+ opts[:exclude_namespaces].each do |n|
257
+ return nil if mod == n || mod.in?(n)
258
+ end
259
+ end
260
+ if opts[:filter_namespaces]
261
+ opts[:filter_namespaces].each do |n|
262
+ return nil unless mod == n || mod.in?(n)
263
+ end
264
+ end
265
+ if opts[:filter_global]
266
+ return nil unless mod.global?
267
+ end
268
+ acc[mod.inspect] = get_module mod, opts
269
+ end
270
+
271
+ # Make hash with data of objectspace.
272
+ #
273
+ # @param [Hash] opts Options (see also {dot} & {diff}).
274
+ # @option opts [Array<Class>] :exclude_classes don't add classes listed and
275
+ # their descendants;
276
+ # @option opts [Array<String>] :exclude_files don't add methods defined in
277
+ # files listed;
278
+ # @option opts [Array<Module>] :exclude_namespaces don't add classes/modules
279
+ # listed and their inners;
280
+ # @option opts [Array<Class>] :filter_classes add only classes listed and
281
+ # their descendants;
282
+ # @option opts [Array<String>] :filter_files add only methods defined in
283
+ # files listed;
284
+ # @option opts [Boolean] :filter_global add only classes/modules in global
285
+ # namespace;
286
+ # @option opts [Array<Module>] :filter_namespaces add only classes/modules
287
+ # listed and their inners;
288
+ # @option opts [Boolean] :hide_arguments don't add arguments info to
289
+ # methods' names;
290
+ # @option opts [Boolean] :hide_constants don't add constants' data;
291
+ # @option opts [Boolean] :hide_methods don't add methods' data;
292
+ # @option opts [Boolean] :select_attributes make attributes data instead
293
+ # getter and setter methods;
294
+ # @option opts [Boolean] :show_private add data of private methods;
295
+ # @option opts [Boolean] :show_protected add data of protected methods.
296
+ # @return [Hash] Objectspace.
297
+ def snapshot opts = {}
298
+ opts = defaults.merge opts
299
+ result = {}
300
+ ObjectSpace.each_object(Module) { |m| add_module result, m, opts }
301
+ result
302
+ end
303
+
304
+ # @private
305
+ def diff_module base, other, opts
306
+ if ! other
307
+ return base.merge :new => true
308
+ end
309
+ if opts[:show_preloaded]
310
+ return base
311
+ end
312
+ result = {}
313
+ result[:module] = base[:module]
314
+ result[:superclass] = base[:superclass]
315
+ result[:nested] = base[:nested]
316
+ result[:included] = base[:included] - other[:included]
317
+ result[:extended] = base[:extended] - other[:extended]
318
+ result[:constants] = {}
319
+ if base[:constants]
320
+ base[:constants].each do |c|
321
+ if base[:constants][c] != other[:constants][c]
322
+ result[:constants][c] = base[:constants][c]
323
+ end
324
+ end
325
+ end
326
+ [:class, :instance].each do |s|
327
+ [:public, :protected, :private].each do |v|
328
+ [:attributes, :methods].each do |k|
329
+ if base[s] && base[s][v] && base[s][v][k]
330
+ base[s][v][k].each do |n, m|
331
+ unless other[s] && other[s][v] && other[s][v][k] &&
332
+ other[s][v][k][n] &&
333
+ other[s][v][k][n][:file] == m[:file] &&
334
+ other[s][v][k][n][:line] == m[:line]
335
+ result[s] ||= {}
336
+ result[s][v] ||= {}
337
+ result[s][v][k] ||= {}
338
+ result[s][v][k][n] = m
339
+ end
340
+ end
341
+ end
342
+ end
343
+ end
344
+ end
345
+ if result[:included].empty? && result[:extended].empty? &&
346
+ result[:constants].empty? && result[:class].nil? &&
347
+ result[:instance].nil?
348
+ nil
349
+ else
350
+ if result[:module] == Object
351
+ result[:included] << 'Kernel' if ! result[:included].include?(Kernel)
352
+ end
353
+ result
354
+ end
355
+ end
356
+
357
+ # Make diff between two objectspaces.
358
+ #
359
+ # @param [Hash] base 'New' objectspace.
360
+ # @param [Hash] other 'Old' objectspace
361
+ # @param [Hash] opts Options (see also {snapshot} & {dot}).
362
+ # @option opts [Boolean] :show_preloaded if true old classes/modules will not
363
+ # deleted from difference.
364
+ # @return [Hash] Difference objectspace.
365
+ def diff base, other, opts = {}
366
+ opts = defaults.merge opts
367
+ if other == nil
368
+ return base
369
+ end
370
+ result = {}
371
+ base.each do |n, m|
372
+ d = diff_module m, other[n], opts
373
+ result[n] = d if d
374
+ end
375
+ result
376
+ end
377
+
378
+ # @private
379
+ def find_module space, name
380
+ return space[name] if space[name]
381
+ begin
382
+ mod = sandbox { eval name }
383
+ return get_module(mod, :no_scan => true)
384
+ rescue
385
+ end
386
+ nil
387
+ end
388
+
389
+ # Default values for {dot} options.
390
+ #
391
+ # @return [Hash] see source for details or {dot} for description.
392
+ def defaults
393
+ {
394
+ :graph_fontname => 'sans-serif',
395
+ :graph_fontsize => 24,
396
+ :graph_label => 'RDot Graph',
397
+ :node_fontname => 'monospace',
398
+ :node_fontsize => 9,
399
+ :color_class => '#BBFFBB',
400
+ :color_class_preloaded => '#CCEECC',
401
+ :color_class_core => '#DDFF99',
402
+ :color_exception => '#FFBBBB',
403
+ :color_exception_preloaded => '#EECCCC',
404
+ :color_exception_core => '#FFDD99',
405
+ :color_module => '#BBBBFF',
406
+ :color_module_preloaded => '#CCCCEE',
407
+ :color_module_core => '#99DDFF',
408
+ :color_protected => '#EEEEEE',
409
+ :color_private => '#DDDDDD',
410
+ :color_inherited => '#0000FF',
411
+ :color_included => '#00AAFF',
412
+ :color_extended => '#AA00FF',
413
+ :color_nested => '#EEEEEE'
414
+ }
415
+ end
416
+
417
+ # @private
418
+ def node_name name
419
+ 'node_' + name.gsub(/\W/, '_')
420
+ end
421
+
422
+ # @private
423
+ def module_stage m
424
+ if @preset.include? m[:module]
425
+ :core
426
+ elsif m[:new]
427
+ :new
428
+ else
429
+ :old
430
+ end
431
+ end
432
+
433
+ # @private
434
+ def node_color m, opts
435
+ mod = m[:module]
436
+ stg = module_stage m
437
+ if Class === mod
438
+ if mod <= Exception
439
+ case stg
440
+ when :core
441
+ opts[:color_exception_core]
442
+ when :old
443
+ opts[:color_exception_preloaded]
444
+ when :new
445
+ opts[:color_exception]
446
+ end
447
+ else
448
+ case stg
449
+ when :core
450
+ opts[:color_class_core]
451
+ when :old
452
+ opts[:color_class_preloaded]
453
+ when :new
454
+ opts[:color_class]
455
+ end
456
+ end
457
+ else
458
+ case stg
459
+ when :core
460
+ opts[:color_module_core]
461
+ when :old
462
+ opts[:color_module_preloaded]
463
+ when :new
464
+ opts[:color_module]
465
+ end
466
+ end
467
+ end
468
+
469
+ # @private
470
+ def module_kind m
471
+ stg = module_stage m
472
+ if Class === m[:module]
473
+ if m[:module] <= Exception
474
+ "[#{stg}] exception"
475
+ else
476
+ "[#{stg}] class"
477
+ end
478
+ else
479
+ "[#{stg}] module"
480
+ end
481
+ end
482
+
483
+ # @private
484
+ def escape s
485
+ s.gsub('&', '&amp;').gsub('<', '&lt;').gsub('>', '&gt;').gsub("\n", '\n')
486
+ end
487
+
488
+ # @private
489
+ def dot_constants m
490
+ result = []
491
+ if m[:constants]
492
+ m[:constants].sort.each do |n, c|
493
+ result << "#{escape(n.to_s)} &lt;#{escape(c)}&gt;"
494
+ end
495
+ end
496
+ if result.size != 0
497
+ '<TR><TD ROWSPAN="' + result.size.to_s +
498
+ '" ALIGN="RIGHT" VALIGN="TOP">const</TD><TD COLSPAN="3" ALIGN="LEFT">' +
499
+ result.join('</TD></TR><TR><TD COLSPAN="3" ALIGN="LEFT">') +
500
+ '</TD></TR>'
501
+ else
502
+ ''
503
+ end
504
+ end
505
+
506
+ # @private
507
+ def dot_scope m, scope, opts
508
+ result = []
509
+ if m[scope]
510
+ if m[scope][:public]
511
+ if m[scope][:public][:attributes]
512
+ m[scope][:public][:attributes].sort.each do |n, a|
513
+ result << '<TD ALIGN="LEFT">' + escape(a[:signature]) +
514
+ '</TD><TD ALIGN="RIGHT">' + escape(a[:file].to_s) +
515
+ '</TD><TD ALIGN="RIGHT">' + a[:line].to_s + '</TD>'
516
+ end
517
+ end
518
+ if m[scope][:public][:methods]
519
+ m[scope][:public][:methods].sort.each do |n, a|
520
+ result << '<TD ALIGN="LEFT">' + escape(a[:signature]) +
521
+ '</TD><TD ALIGN="RIGHT">' + escape(a[:file].to_s) +
522
+ '</TD><TD ALIGN="RIGHT">' + a[:line].to_s + '</TD>'
523
+ end
524
+ end
525
+ end
526
+ if m[scope][:protected]
527
+ if m[scope][:protected][:attributes]
528
+ m[scope][:protected][:attributes].sort.each do |n, a|
529
+ result << '<TD BGCOLOR="' + opts[:color_protected] +
530
+ '" ALIGN="LEFT">' + escape(a[:signature]) +
531
+ '</TD><TD BGCOLOR="' + opts[:color_protected] +
532
+ '" ALIGN="RIGHT">' + escape(a[:file].to_s) +
533
+ '</TD><TD BGCOLOR="' + opts[:color_protected] +
534
+ '" ALIGN="RIGHT">' + a[:line].to_s + '</TD>'
535
+ end
536
+ end
537
+ if m[scope][:protected][:methods]
538
+ m[scope][:protected][:methods].sort.each do |n, a|
539
+ result << '<TD BGCOLOR="' + opts[:color_protected] +
540
+ '" ALIGN="LEFT">' + escape(a[:signature]) +
541
+ '</TD><TD BGCOLOR="' + opts[:color_protected] +
542
+ '" ALIGN="RIGHT">' + escape(a[:file].to_s) +
543
+ '</TD><TD BGCOLOR="' + opts[:color_protected] +
544
+ '" ALIGN="RIGHT">' + a[:line].to_s + '</TD>'
545
+ end
546
+ end
547
+ end
548
+ if m[scope][:private]
549
+ if m[scope][:private][:attributes]
550
+ m[scope][:private][:attributes].sort.each do |n, a|
551
+ result << '<TD BGCOLOR="' + opts[:color_private] +
552
+ '" ALIGN="LEFT">' + escape(a[:signature]) +
553
+ '</TD><TD BGCOLOR="' + opts[:color_private] +
554
+ '" ALIGN="RIGHT">' + escape(a[:file].to_s) +
555
+ '</TD><TD BGCOLOR="' + opts[:color_private] +
556
+ '" ALIGN="RIGHT">' + a[:line].to_s + '</TD>'
557
+ end
558
+ end
559
+ if m[scope][:private][:methods]
560
+ m[scope][:private][:methods].sort.each do |n, a|
561
+ result << '<TD BGCOLOR="' + opts[:color_private] +
562
+ '" ALIGN="LEFT">' + escape(a[:signature]) +
563
+ '</TD><TD BGCOLOR="' + opts[:color_private] +
564
+ '" ALIGN="RIGHT">' + escape(a[:file].to_s) +
565
+ '</TD><TD BGCOLOR="' + opts[:color_private] +
566
+ '" ALIGN="RIGHT">' + a[:line].to_s + '</TD>'
567
+ end
568
+ end
569
+ end
570
+ end
571
+ if result.size != 0
572
+ '<TR><TD ROWSPAN="' + result.size.to_s +
573
+ '" ALIGN="RIGHT" VALIGN="TOP">' + scope.to_s + '</TD>' +
574
+ result.join('</TR><TR>') + '</TR>'
575
+ else
576
+ ''
577
+ end
578
+ end
579
+
580
+ # @private
581
+ def node_label name, m, opts
582
+ result = []
583
+ result << '<TABLE CELLBORDER="0" CELLSPACING="0">'
584
+ result << '<TR>'
585
+ result << '<TD ALIGN="RIGHT" BGCOLOR="' + node_color(m, opts) + '">'
586
+ result << '<B>'
587
+ result << module_kind(m)
588
+ result << '</B>'
589
+ result << '</TD>'
590
+ result << '<TD COLSPAN="3" ALIGN="LEFT" BGCOLOR="' +
591
+ node_color(m, opts) + '">'
592
+ result << '<B>'
593
+ result << escape(name)
594
+ result << '</B>'
595
+ result << '</TD>'
596
+ result << '</TR>'
597
+ result << dot_constants(m)
598
+ result << dot_scope(m, :class, opts)
599
+ result << dot_scope(m, :instance, opts)
600
+ result << '</TABLE>'
601
+ result.join ''
602
+ end
603
+
604
+ # @private
605
+ def dot_module space, name, m, opts
606
+ if m == nil
607
+ $stderr.puts "Warning: nil module by name \"#{name}\"!"
608
+ return nil
609
+ end
610
+ if @processed.include?(m[:module])
611
+ return nil
612
+ else
613
+ @processed << m[:module]
614
+ end
615
+ result = []
616
+ result << node_name(name) + '['
617
+ result << ' label=<' + node_label(name, m, opts) + '>'
618
+ result << '];'
619
+ if m[:nested] && ! opts[:hide_nested]
620
+ ns = find_module space, m[:nested]
621
+ result << dot_module(space, m[:nested], ns, opts)
622
+ @nested << node_name(m[:nested]) + ' -> ' + node_name(name) + ';'
623
+ end
624
+ if ! opts[:hide_extended]
625
+ m[:extended].each do |e|
626
+ ext = find_module space, e
627
+ result << dot_module(space, e, ext, opts)
628
+ @extended << node_name(e) + ' -> ' + node_name(name) + ';'
629
+ end
630
+ end
631
+ if ! opts[:hide_included]
632
+ m[:included].each do |i|
633
+ next if m[:module].name == 'CMath' && i == 'Math'
634
+ inc = find_module space, i
635
+ result << dot_module(space, i, inc, opts)
636
+ @included << node_name(i) + ' -> ' + node_name(name) + ';'
637
+ end
638
+ end
639
+ if m[:superclass]
640
+ spc = find_module space, m[:superclass]
641
+ result << dot_module(space, m[:superclass], spc, opts)
642
+ @inherited << node_name(m[:superclass]) + ' -> ' + node_name(name) + ';'
643
+ end
644
+ result.join "\n "
645
+ end
646
+
647
+ # Make .dot text from snapshot or difference.
648
+ #
649
+ # @param [Hash] space Snapshot or difference objectspace.
650
+ # @param [Hash] opts Options (see also {snapshot} & {diff}). This Hash will
651
+ # be merged over default values (see {defaults}).
652
+ # @option opts [String] :color_class class node title background color;
653
+ # @option opts [String] :color_class_core core class node title background
654
+ # color;
655
+ # @option opts [String] :color_class_preloaded preloaded class node title
656
+ # background color;
657
+ # @option opts [String] :color_exception exception node title background
658
+ # color;
659
+ # @option opts [String] :color_exception_core core exception node title
660
+ # background color;
661
+ # @option opts [String] :color_exception_preloaded preloaded exception node
662
+ # title background color;
663
+ # @option opts [String] :color_extended color of 'extended' edges;
664
+ # @option opts [String] :color_included color of 'included' edges;
665
+ # @option opts [String] :color_inherited color of 'inherited' edges;
666
+ # @option opts [String] :color_module module node title background color;
667
+ # @option opts [String] :color_module_core core module node title background
668
+ # color;
669
+ # @option opts [String] :color_module_preloaded preloaded module title
670
+ # background color;
671
+ # @option opts [String] :color_nested color of 'nested' edges;
672
+ # @option opts [String] :color_private background color for private methods;
673
+ # @option opts [String] :color_protected background color for protected
674
+ # methods;
675
+ # @option opts [String] :graph_fontname font name of graph title;
676
+ # @option opts [Numeric] :graph_fontsize font size of graph title;
677
+ # @option opts [String] :graph_label graph title;
678
+ # @option opts [Boolean] :hide_extended if true hide 'extended' edges;
679
+ # @option opts [Boolean] :hide_included if true hide 'included' edges;
680
+ # @option opts [Boolean] :hide_nested if true hide 'nested' edges;
681
+ # @option opts [String] :node_fontname font name of class/module nodes;
682
+ # @option opts [Numeric] :node_fontsize font size of class/module nodes.
683
+ # @return [String] Text of .dot-file.
684
+ def dot space, opts = {}
685
+ opts = defaults.merge opts
686
+ result = []
687
+ result << 'digraph graph_RDot{'
688
+ result << ' graph['
689
+ result << ' rankdir=LR,'
690
+ result << ' splines=true,'
691
+ result << ' labelloc=t,'
692
+ result << ' fontname="' + opts[:graph_fontname] + '",'
693
+ result << ' fontsize=' + opts[:graph_fontsize].to_s + ','
694
+ result << ' label="' + opts[:graph_label] + '"'
695
+ result << ' ];'
696
+ result << ' node['
697
+ result << ' shape=plaintext,'
698
+ result << ' fontname="' + opts[:node_fontname] + '",'
699
+ result << ' fontsize=' + opts[:node_fontsize].to_s + ''
700
+ result << ' ];'
701
+ result << ' edge['
702
+ result << ' dir=back,'
703
+ result << ' arrowtail=vee,'
704
+ result << ' penwidth=0.5, arrowsize=0.5'
705
+ result << ' ];'
706
+ @processed = []
707
+ @nested = []
708
+ @extended = []
709
+ @included = []
710
+ @inherited = []
711
+ space.each do |n, m|
712
+ mm = dot_module space, n, m, opts
713
+ result << ' ' + mm if mm
714
+ end
715
+ result << ' subgraph subNested{'
716
+ result << ' edge['
717
+ result << ' color="' + opts[:color_nested] + '",'
718
+ result << ' weight=8,'
719
+ result << ' minlen=0'
720
+ result << ' ];'
721
+ result << ' ' + @nested.join("\n ")
722
+ result << ' }'
723
+ result << ' subgraph subExtended{'
724
+ result << ' edge['
725
+ result << ' color="' + opts[:color_extended] + '",'
726
+ result << ' weight=1,'
727
+ result << ' minlen=0'
728
+ result << ' ];'
729
+ result << ' ' + @extended.join("\n ")
730
+ result << ' }'
731
+ result << ' subgraph subIncluded{'
732
+ result << ' edge['
733
+ result << ' color="' + opts[:color_included] + '",'
734
+ result << ' weight=2,'
735
+ result << ' minlen=1'
736
+ result << ' ];'
737
+ result << ' ' + @included.join("\n ")
738
+ result << ' }'
739
+ result << ' subgraph subInherited{'
740
+ result << ' edge['
741
+ result << ' color="' + opts[:color_inherited] + '",'
742
+ result << ' weight=4,'
743
+ result << ' minlen=1'
744
+ result << ' ];'
745
+ result << ' ' + @inherited.join("\n ")
746
+ result << ' }'
747
+ result << '}'
748
+ result.join "\n"
749
+ end
750
+
751
+ private :get_file, :get_method_object, :get_module, :add_method,
752
+ :add_module, :diff_module, :find_module, :dot_module, :node_name,
753
+ :node_color, :node_label, :module_kind, :dot_constants, :dot_scope,
754
+ :module_stage, :escape
755
+
756
+ end
757
+
758
+ @preset = []
759
+ ObjectSpace.each_object(Module) { |m| @preset << m if m != ::RDot }
760
+
761
+ end
762
+