RuTu 0.0.1
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/README +1 -0
- data/ext/RuTuExt.c +144 -0
- data/ext/extconf.rb +3 -0
- data/lib/RuTu.rb +205 -0
- data/sample.rb +12 -0
- metadata +50 -0
data/README
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby sample.rb | dot -Tgif > sample.gif
|
data/ext/RuTuExt.c
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "st.h"
|
3
|
+
|
4
|
+
#include <assert.h>
|
5
|
+
/*
|
6
|
+
struct RBasic {
|
7
|
+
unsigned long flags;
|
8
|
+
VALUE klass;
|
9
|
+
};
|
10
|
+
struct RObject {
|
11
|
+
struct RBasic basic;
|
12
|
+
struct st_table *iv_tbl;
|
13
|
+
};
|
14
|
+
struct RClass {
|
15
|
+
struct RBasic basic;
|
16
|
+
struct st_table *iv_tbl;
|
17
|
+
struct st_table *m_tbl;
|
18
|
+
VALUE super;
|
19
|
+
};
|
20
|
+
*/
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
VALUE RuTuExt__obj_id(VALUE dummy, VALUE v)
|
25
|
+
{
|
26
|
+
return rb_obj_id(v);
|
27
|
+
}
|
28
|
+
VALUE RuTuExt__equal(VALUE dummy, VALUE v1, VALUE v2) // rb_obj_equal
|
29
|
+
{
|
30
|
+
if (v1 == v2) return Qtrue;
|
31
|
+
return Qfalse;
|
32
|
+
}
|
33
|
+
VALUE RuTuExt__klass(VALUE dummy, VALUE self)
|
34
|
+
{
|
35
|
+
return RBASIC(self)->klass;
|
36
|
+
}
|
37
|
+
VALUE RuTuExt__iv_tbl(VALUE dummy, VALUE obj)
|
38
|
+
{
|
39
|
+
//return rb_fix_new(RCLASS(klass)->m_tbl);
|
40
|
+
//assert((RCLASS(klass)->m_tbl & 1) == 0); // doesn't matter......
|
41
|
+
return (VALUE) ROBJECT(obj)->iv_tbl; // note: can't be inspected
|
42
|
+
}
|
43
|
+
VALUE RuTuExt__m_tbl(VALUE dummy, VALUE klass)
|
44
|
+
{
|
45
|
+
//return rb_fix_new(RCLASS(klass)->m_tbl);
|
46
|
+
//assert((RCLASS(klass)->m_tbl & 1) == 0); // doesn't matter......
|
47
|
+
return (VALUE) RCLASS(klass)->m_tbl; // note: can't be inspected
|
48
|
+
}
|
49
|
+
VALUE RuTuExt__super(VALUE dummy, VALUE klass)
|
50
|
+
{
|
51
|
+
return RCLASS(klass)->super;
|
52
|
+
}
|
53
|
+
VALUE RuTuExt__singleton_class(VALUE dummy, VALUE klass)
|
54
|
+
{
|
55
|
+
if (FL_TEST(klass, FL_SINGLETON)) return Qtrue;
|
56
|
+
return Qfalse;
|
57
|
+
}
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
VALUE RuTuExt__class_path(VALUE obj, VALUE klass)
|
62
|
+
{
|
63
|
+
return rb_class_path(klass);
|
64
|
+
}
|
65
|
+
//VALUE RuTuExt_class2name(VALUE klass)
|
66
|
+
//{
|
67
|
+
// return rb_class2name(klass);
|
68
|
+
//}
|
69
|
+
|
70
|
+
//int myprint(ID id, VALUE value, st_data_t dummy)
|
71
|
+
//{
|
72
|
+
// printf("myprint: %d %s\n", id, rb_id2name(id));
|
73
|
+
// return ST_CONTINUE;
|
74
|
+
//}
|
75
|
+
//
|
76
|
+
//int myprint_m_tbl_entry(ID id, VALUE value, st_data_t dummy)
|
77
|
+
//{
|
78
|
+
// printf("myprint_m_tbl_entry: %d %s %s\n", id, rb_id2name(id), rb_obj_classname(value));
|
79
|
+
// return ST_CONTINUE;
|
80
|
+
//}
|
81
|
+
|
82
|
+
/*
|
83
|
+
VALUE RuTuExt_foo(VALUE obj, VALUE x)
|
84
|
+
{
|
85
|
+
//printf("rb_obj_classname of obj: %s\n", rb_obj_classname(obj));
|
86
|
+
printf("x: %ld\n", x);
|
87
|
+
printf("klass: %ld\n", RBASIC(x)->klass);
|
88
|
+
printf("iv_tbl: %ld\n", ROBJECT(x)->iv_tbl);
|
89
|
+
printf("m_tbl: %ld\n", RCLASS(x)->m_tbl);
|
90
|
+
printf("===== each iv_tbl\n");
|
91
|
+
st_foreach(ROBJECT(x)->iv_tbl, myprint, (st_data_t) NULL);
|
92
|
+
printf("===== each m_tbl\n");
|
93
|
+
st_foreach(RCLASS(x)->m_tbl, myprint_m_tbl_entry, (st_data_t) NULL);
|
94
|
+
return x;
|
95
|
+
}
|
96
|
+
*/
|
97
|
+
|
98
|
+
//VALUE RuTuExt_class_show_methods(VALUE module, VALUE klass)
|
99
|
+
//{
|
100
|
+
// while (klass)
|
101
|
+
// {
|
102
|
+
// //printf("klass: %ld %s======\n", klass, RSTRING(rb_class_name(klass))->ptr);
|
103
|
+
// //printf("klass: %ld %s======\n", klass, rb_class2name(klass));
|
104
|
+
// printf("klass: %ld %s======\n", klass, RSTRING(rb_class_path(klass))->ptr);
|
105
|
+
// //st_foreach(ROBJECT(klass)->iv_tbl, myprint, (st_data_t) NULL);
|
106
|
+
// printf("--\n");
|
107
|
+
// st_foreach(RCLASS(klass)->m_tbl, myprint_m_tbl_entry, (st_data_t) NULL);
|
108
|
+
// klass = RCLASS(klass)->super;
|
109
|
+
// }
|
110
|
+
// return klass;
|
111
|
+
//}
|
112
|
+
//
|
113
|
+
//
|
114
|
+
//VALUE RuTuExt_obj_show_methods(VALUE module, VALUE obj)
|
115
|
+
//{
|
116
|
+
// return RuTuExt_class_show_methods(module, CLASS_OF(obj));
|
117
|
+
//}
|
118
|
+
//
|
119
|
+
//VALUE RuTuExt_class_instance_methods(VALUE dummy, VALUE klass)
|
120
|
+
//{
|
121
|
+
// return rb_class_instance_methods(0, NULL, klass);
|
122
|
+
//}
|
123
|
+
|
124
|
+
|
125
|
+
void Init_RuTuExt()
|
126
|
+
{
|
127
|
+
VALUE mRuTuExt;
|
128
|
+
mRuTuExt = rb_define_module("RuTuExt");
|
129
|
+
// printf("hihi\n");
|
130
|
+
rb_define_module_function(mRuTuExt, "_obj_id", RuTuExt__obj_id, 1);
|
131
|
+
rb_define_module_function(mRuTuExt, "_equal?", RuTuExt__equal, 2);
|
132
|
+
rb_define_module_function(mRuTuExt, "_klass", RuTuExt__klass, 1);
|
133
|
+
rb_define_module_function(mRuTuExt, "_iv_tbl", RuTuExt__iv_tbl, 1);
|
134
|
+
rb_define_module_function(mRuTuExt, "_m_tbl", RuTuExt__m_tbl, 1);
|
135
|
+
rb_define_module_function(mRuTuExt, "_super", RuTuExt__super, 1);
|
136
|
+
rb_define_module_function(mRuTuExt, "_class_path", RuTuExt__class_path, 1);
|
137
|
+
//rb_define_module_function(mRuTuExt, "_instance_methods", RuTuExt_class_instance_methods, 1);
|
138
|
+
rb_define_module_function(mRuTuExt, "_singleton_class?", RuTuExt__singleton_class, 1);
|
139
|
+
/*
|
140
|
+
rb_define_module_function(mRuTuExt, "foo", RuTuExt_foo, 1);
|
141
|
+
rb_define_module_function(mRuTuExt, "RuTuExt_obj_show_methods", RuTuExt_obj_show_methods, 1);
|
142
|
+
rb_define_module_function(mRuTuExt, "RuTuExt_class_show_methods", RuTuExt_class_show_methods, 1);
|
143
|
+
*/
|
144
|
+
}
|
data/ext/extconf.rb
ADDED
data/lib/RuTu.rb
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
require "set"
|
2
|
+
require "RuTuExt"
|
3
|
+
require "cgi"
|
4
|
+
|
5
|
+
module RuTu
|
6
|
+
|
7
|
+
class ValueNode
|
8
|
+
def initialize(g, v)
|
9
|
+
@graph = g
|
10
|
+
@value = v
|
11
|
+
end
|
12
|
+
def same_value?(v)
|
13
|
+
RuTuExt._equal?(@value, v)
|
14
|
+
end
|
15
|
+
def _obj_id
|
16
|
+
RuTuExt._obj_id(@value)
|
17
|
+
end
|
18
|
+
def walk(new_value, node_class, relation)
|
19
|
+
n = @graph.add(new_value, node_class)
|
20
|
+
@graph.add_edge(self, n, relation)
|
21
|
+
n
|
22
|
+
end
|
23
|
+
|
24
|
+
def node_id
|
25
|
+
"node#{ _obj_id() }"
|
26
|
+
end
|
27
|
+
def fields
|
28
|
+
[ :header ]
|
29
|
+
end
|
30
|
+
def header_value
|
31
|
+
[ self.class.name.gsub(/.*::/, ''), _obj_id() ]
|
32
|
+
end
|
33
|
+
def color
|
34
|
+
"black"
|
35
|
+
end
|
36
|
+
def to_dot
|
37
|
+
label = fields().map do |f|
|
38
|
+
v = self.respond_to?("#{f}_value") ? self.send("#{f}_value") : f
|
39
|
+
v = [ v ].flatten.map { |x| CGI.escapeHTML(x.to_s()) }.join("<br/>")
|
40
|
+
%Q! <tr><td port="#{f}">#{v}</td></tr> !
|
41
|
+
end.join(" ")
|
42
|
+
label = "<table>#{label}</table>"
|
43
|
+
node_id() + " [ shape=plaintext, color=#{color()}, label=<#{label}> ]"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class RBasicNode < ValueNode
|
48
|
+
def flags; end
|
49
|
+
def _klass
|
50
|
+
RuTuExt._klass(@value)
|
51
|
+
end
|
52
|
+
def klass
|
53
|
+
walk(_klass(), RClassNode, "klass")
|
54
|
+
end
|
55
|
+
def fields
|
56
|
+
super() + [ :flags, :klass ]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class RObjectNode < RBasicNode
|
61
|
+
def _iv_tbl
|
62
|
+
RuTuExt._iv_tbl(@value)
|
63
|
+
end
|
64
|
+
def iv_tbl
|
65
|
+
walk(_iv_tbl(), St_TableNode, "iv_tbl")
|
66
|
+
end
|
67
|
+
def fields
|
68
|
+
super() + [ :iv_tbl ]
|
69
|
+
end
|
70
|
+
def color
|
71
|
+
"yellow"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class RClassNode < RObjectNode
|
76
|
+
def header_value
|
77
|
+
[ super(), RuTuExt._class_path(@value) ]
|
78
|
+
end
|
79
|
+
def _m_tbl
|
80
|
+
RuTuExt._m_tbl(@value)
|
81
|
+
end
|
82
|
+
def m_tbl
|
83
|
+
walk(_m_tbl(), St_TableNode, "m_tbl")
|
84
|
+
end
|
85
|
+
def _super
|
86
|
+
RuTuExt._super(@value)
|
87
|
+
end
|
88
|
+
def super
|
89
|
+
walk(_super(), RClassNode, "super")
|
90
|
+
end
|
91
|
+
alias :zuper :super
|
92
|
+
def fields
|
93
|
+
super() + [ :m_tbl, :super ]
|
94
|
+
end
|
95
|
+
def color
|
96
|
+
"red"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class NotValueNode < ValueNode
|
101
|
+
def inspect
|
102
|
+
"i was never here"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class St_TableNode < NotValueNode
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
class NullNode < ValueNode
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
class Edge
|
117
|
+
def initialize(from, to, relation, options = {})
|
118
|
+
@from, @to, @relation, @options = from, to, relation, options
|
119
|
+
end
|
120
|
+
def same?(from, to, relation)
|
121
|
+
@from == from && @to == to && @relation == relation
|
122
|
+
end
|
123
|
+
def to_dot(to_set)
|
124
|
+
"#{@from.node_id}:#{@relation} -> #{@to.node_id}:header [ label = #{@relation} ]" +
|
125
|
+
((@relation == "klass" && to_set.add?(@to)) ? "{ rank = same; #{@from.node_id}; #{@to.node_id}; }" : "")
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class Graph
|
130
|
+
def initialize
|
131
|
+
@nodes = [] #Set.new
|
132
|
+
@edges = [] #Set.new
|
133
|
+
end
|
134
|
+
|
135
|
+
def add(value, node_class)
|
136
|
+
rtn = @nodes.find { |n| n.same_value?(value) }
|
137
|
+
if not rtn
|
138
|
+
node_class = NullNode if false == value
|
139
|
+
rtn = node_class.new(self, value)
|
140
|
+
@nodes << rtn
|
141
|
+
end
|
142
|
+
rtn
|
143
|
+
end
|
144
|
+
def add_edge(from, to, relation)
|
145
|
+
rtn = @edges.find { |e| e.same?(from, to, relation) }
|
146
|
+
if not rtn
|
147
|
+
rtn = Edge.new(from, to, relation)
|
148
|
+
@edges << rtn
|
149
|
+
end
|
150
|
+
rtn
|
151
|
+
end
|
152
|
+
|
153
|
+
# depth = 0 => no-op
|
154
|
+
# depth = -1 => no limit
|
155
|
+
def closure(init_nodes, relations, depth = -1)
|
156
|
+
nodes = Array.new init_nodes
|
157
|
+
s = 0
|
158
|
+
e = nodes.size
|
159
|
+
while s < e && depth != 0
|
160
|
+
for i in (s ... e) do
|
161
|
+
relations.each do |r|
|
162
|
+
nodes |= [ nodes[i].send(r) ] if nodes[i].respond_to?(r)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
depth = depth - 1
|
166
|
+
s = e
|
167
|
+
e = nodes.size
|
168
|
+
end
|
169
|
+
nodes
|
170
|
+
end
|
171
|
+
|
172
|
+
def to_dot
|
173
|
+
to_set = Set.new
|
174
|
+
return <<-"EOG"
|
175
|
+
digraph G {
|
176
|
+
# rankdir=LR
|
177
|
+
node [fontname=Luxi]
|
178
|
+
edge [fontname=Luxi]
|
179
|
+
#{ @nodes.map { |n| n.to_dot + "\n" } }
|
180
|
+
#{ @edges.map { |e| e.to_dot(to_set) + "\n" } }
|
181
|
+
}
|
182
|
+
EOG
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
__END__
|
188
|
+
|
189
|
+
#module M; end
|
190
|
+
#class A
|
191
|
+
# include M
|
192
|
+
#end
|
193
|
+
#a = A.new
|
194
|
+
#def a.foo; end
|
195
|
+
#
|
196
|
+
class A
|
197
|
+
end
|
198
|
+
a = A.new
|
199
|
+
|
200
|
+
|
201
|
+
|
202
|
+
g = Graph.new
|
203
|
+
a_ = g.add(a, RObjectNode)
|
204
|
+
g.closure([ a_.klass ], [:klass, :super])
|
205
|
+
puts g.to_dot
|
data/sample.rb
ADDED
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.2
|
3
|
+
specification_version: 1
|
4
|
+
name: RuTu
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.0.1
|
7
|
+
date: 2007-06-03 00:00:00 +00:00
|
8
|
+
summary: a tool for visualizing object graphs
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email:
|
12
|
+
homepage: lcamel@gmail.com
|
13
|
+
rubyforge_project: rutu
|
14
|
+
description:
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Luoh Ren-Shan
|
31
|
+
files:
|
32
|
+
- lib/RuTu.rb
|
33
|
+
- ext/RuTuExt.c
|
34
|
+
- ext/extconf.rb
|
35
|
+
- sample.rb
|
36
|
+
- README
|
37
|
+
test_files: []
|
38
|
+
|
39
|
+
rdoc_options: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
executables: []
|
44
|
+
|
45
|
+
extensions:
|
46
|
+
- ext/extconf.rb
|
47
|
+
requirements:
|
48
|
+
- "\"dot\" in the GraphViz package"
|
49
|
+
dependencies: []
|
50
|
+
|