RuTu 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|