drx 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,13 @@
1
+ = Dr. X, the Good Doctor
2
+
3
+ Doctor X is a utility for programmers who wish to understand Ruby's
4
+ object model better. It's a small 'gem' that exposes, in a Tk GUI,
5
+ almost everything about a Ruby object: its 'klass', 'super', 'iv_tbl',
6
+ 'm_tbl'. See your singletons with your very own eyes!
7
+
8
+ == Usage
9
+
10
+ This section is yet to be written. In the meanwhile, visit the homepage
11
+ to see usage example:
12
+
13
+ http://drx.rubyforge.org/
data/ext/drx_ext.c ADDED
@@ -0,0 +1,138 @@
1
+ #include "ruby.h"
2
+ #include "st.h"
3
+
4
+ // Helper for t_get_iv_tbl().
5
+ int record_var(st_data_t key, st_data_t value, VALUE hash) {
6
+ // I originally did the following, but it breaks for object::Tk*. Perhaps these
7
+ // values are T_NODEs? (e.g. aliases) @todo: debug using INT2FIX(TYPE(value)).
8
+ rb_hash_aset(hash, ID2SYM(key), value);
9
+ // So...
10
+ rb_hash_aset(hash, ID2SYM(key), Qtrue);
11
+ return ST_CONTINUE;
12
+ }
13
+
14
+ /**
15
+ * Gets the iv_tbl of the object, as a Ruby hash.
16
+ */
17
+ static VALUE t_get_iv_tbl(VALUE self, VALUE obj)
18
+ {
19
+ VALUE hash;
20
+ hash = rb_hash_new();
21
+
22
+ if (TYPE(obj) != T_OBJECT && TYPE(obj) != T_CLASS && TYPE(obj) != T_ICLASS && TYPE(obj) != T_MODULE) {
23
+ rb_raise(rb_eTypeError, "Only T_OBJECT/T_CLASS/T_MODULE is expected as the argument (got %d)", TYPE(obj));
24
+ }
25
+
26
+ if (ROBJECT(obj)->iv_tbl) {
27
+ st_foreach(ROBJECT(obj)->iv_tbl, record_var, (st_data_t)hash);
28
+ }
29
+
30
+ return hash;
31
+ }
32
+
33
+ /**
34
+ * Extracts one varibale from an object iv_tbl.
35
+ */
36
+ static VALUE t_get_ivar(VALUE self, VALUE obj, VALUE var_name)
37
+ {
38
+ const char *c_name;
39
+ if (TYPE(obj) != T_OBJECT && TYPE(obj) != T_CLASS && TYPE(obj) != T_ICLASS && TYPE(obj) != T_MODULE) {
40
+ rb_raise(rb_eTypeError, "Only T_OBJECT/T_CLASS/T_MODULE is expected as the argument (got %d)", TYPE(obj));
41
+ }
42
+ c_name = StringValuePtr(var_name);
43
+ return rb_iv_get(obj, c_name);
44
+ }
45
+
46
+ /**
47
+ * Returns a class's super.
48
+ *
49
+ * In contrast to Class#superclass, this function doesn't skip singletons and T_ICLASS.
50
+ */
51
+ static VALUE t_get_super(VALUE self, VALUE obj)
52
+ {
53
+ VALUE super;
54
+ if (TYPE(obj) != T_CLASS && TYPE(obj) != T_ICLASS && TYPE(obj) != T_MODULE) {
55
+ rb_raise(rb_eTypeError, "Only T_CLASS/T_MODULE is expected as the argument (got %d)", TYPE(obj));
56
+ }
57
+ return RCLASS(obj)->super ? RCLASS(obj)->super : Qnil;
58
+ }
59
+
60
+ /**
61
+ * Returns an object's klass.
62
+ *
63
+ * In contrast to Object#class, this function doesn't skip singletons and T_ICLASS.
64
+ */
65
+ static VALUE t_get_klass(VALUE self, VALUE obj)
66
+ {
67
+ return CLASS_OF(obj);
68
+ // Note: we can't simply do 'RBASIC(obj)->klass', because obj may be an 'immediate'.
69
+ }
70
+
71
+ /**
72
+ * Returns an object's flags.
73
+ */
74
+ static VALUE t_get_flags(VALUE self, VALUE obj)
75
+ {
76
+ return INT2NUM(RBASIC(obj)->flags);
77
+ }
78
+
79
+ // Helper for t_get_m_tbl().
80
+ int record_method(st_data_t key, st_data_t value, VALUE hash) {
81
+ // @todo: Store something useful in the values.
82
+ rb_hash_aset(hash, key == ID_ALLOCATOR ? rb_str_new2("<Allocator>") : ID2SYM(key), INT2FIX(666));
83
+ return ST_CONTINUE;
84
+ }
85
+
86
+ /**
87
+ * Gets the m_tbl of a class.
88
+ */
89
+ static VALUE t_get_m_tbl(VALUE self, VALUE obj)
90
+ {
91
+ VALUE hash;
92
+
93
+ if (TYPE(obj) != T_CLASS && TYPE(obj) != T_ICLASS && TYPE(obj) != T_MODULE) {
94
+ rb_raise(rb_eTypeError, "Only T_CLASS/T_MODULE is expected as the argument (got %d)", TYPE(obj));
95
+ }
96
+
97
+ hash = rb_hash_new();
98
+ st_foreach(RCLASS(obj)->m_tbl, record_method, (st_data_t)hash);
99
+ return hash;
100
+ }
101
+
102
+ /**
103
+ * Returns the object's "id".
104
+ *
105
+ * This is an alternative to Object#__id__ because the latter doesn't
106
+ * work for T_ICLASS.
107
+ */
108
+ static VALUE t_get_address(VALUE self, VALUE obj)
109
+ {
110
+ return INT2NUM(obj);
111
+ }
112
+
113
+ /**
114
+ * Gets the Ruby's engine type of a variable.
115
+ */
116
+ static VALUE t_get_type(VALUE self, VALUE obj)
117
+ {
118
+ return INT2NUM(TYPE(obj));
119
+ }
120
+
121
+ VALUE mDrx;
122
+
123
+ void Init_drx_ext() {
124
+ mDrx = rb_define_module("Drx");
125
+ rb_define_module_function(mDrx, "get_iv_tbl", t_get_iv_tbl, 1);
126
+ rb_define_module_function(mDrx, "get_m_tbl", t_get_m_tbl, 1);
127
+ rb_define_module_function(mDrx, "get_super", t_get_super, 1);
128
+ rb_define_module_function(mDrx, "get_klass", t_get_klass, 1);
129
+ rb_define_module_function(mDrx, "get_flags", t_get_flags, 1);
130
+ rb_define_module_function(mDrx, "get_address", t_get_address, 1);
131
+ rb_define_module_function(mDrx, "get_type", t_get_type, 1);
132
+ rb_define_module_function(mDrx, "get_ivar", t_get_ivar, 2);
133
+ rb_define_const(mDrx, "FL_SINGLETON", INT2FIX(FL_SINGLETON));
134
+ rb_define_const(mDrx, "T_OBJECT", INT2FIX(T_OBJECT));
135
+ rb_define_const(mDrx, "T_CLASS", INT2FIX(T_CLASS));
136
+ rb_define_const(mDrx, "T_ICLASS", INT2FIX(T_ICLASS));
137
+ rb_define_const(mDrx, "T_MODULE", INT2FIX(T_MODULE));
138
+ }
data/ext/extconf.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'mkmf'
2
+ create_makefile("drx_ext")
data/lib/drx.rb ADDED
@@ -0,0 +1,67 @@
1
+ require 'drx_ext' # Load the C extension
2
+
3
+ # Contains a simple utility function, Drx::examine.
4
+
5
+ module Drx
6
+
7
+ def self.obj_repr(obj)
8
+ is_singleton = Drx.is_class_like(obj) && (Drx.get_flags(obj) & Drx::FL_SINGLETON).nonzero?
9
+ is_iclass = Drx.get_type(obj) == Drx::T_ICLASS
10
+ if is_iclass
11
+ return "'ICLS { include " + obj_repr(Drx.get_klass(obj)) + " }"
12
+ else
13
+ return obj.inspect + (is_singleton ? " 'S" : "")
14
+ end
15
+ end
16
+
17
+ def self.examine(obj, level = 0, title = '', &block) # :yield:
18
+ # Note: since 'obj' may be a T_ICLASS, it doesn't repond to may methods,
19
+ # including is_a?. So when we're querying things we're using Drx calls
20
+ # instead.
21
+
22
+ $seen = {} if level.zero?
23
+ line = (' ' * level) + title + ' ' + obj_repr(obj)
24
+
25
+ address = Drx.get_address(obj)
26
+ seen = $seen[address]
27
+ $seen[address] = true
28
+
29
+ if seen
30
+ line += " [seen]" # #{address.to_s}"
31
+ end
32
+
33
+ if block_given?
34
+ yield line, obj
35
+ else
36
+ puts line
37
+ end
38
+
39
+ return if seen
40
+
41
+ if Drx.is_class_like(obj)
42
+ # Kernel has a NULL super.
43
+ # Modules too have NULL super, unless when 'include'ing.
44
+ if Drx.get_super(obj) # Warning: we can't do 'if !Drx.get_super(obj).#nil?' because
45
+ # T_ICLASS doesn't "have" #nil.
46
+ Drx.examine(Drx.get_super(obj), level+1, '[super]', &block)
47
+ end
48
+ end
49
+
50
+ # Dipslaying a T_ICLASS's klass isn't very useful, because the data
51
+ # is already mirrored in the m_tbl and iv_tvl of the T_ICLASS itself.
52
+ if Drx.get_type(obj) != Drx::T_ICLASS
53
+ Drx.examine(Drx.get_klass(obj), level+1, '[klass]', &block)
54
+ end
55
+ end
56
+
57
+ def self.has_iv_tbl(obj)
58
+ Drx.get_type(obj) == T_OBJECT or Drx.is_class_like(obj)
59
+ end
60
+
61
+ # Returns true if this object is either a class or a module.
62
+ # When true, you know it has 'm_tbl' and 'super'.
63
+ def self.is_class_like(obj)
64
+ [Drx::T_CLASS, Drx::T_ICLASS, Drx::T_MODULE].include? Drx.get_type(obj)
65
+ end
66
+
67
+ end
data/lib/drx_test.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'drxtk'
2
+
3
+ require 'date'
4
+
5
+ ##############################
6
+
7
+ class Zeman < DateTime
8
+ def int
9
+ end
10
+ end
11
+
12
+ zmn = Zeman.new
13
+
14
+ def zmn.koko
15
+ 9090
16
+ end
17
+
18
+ Drx.examine(zmn)
19
+
20
+ #############################
21
+
22
+ Drx.examinetk(zmn)
23
+
24
+ #Drx.examinetk(zmn)
25
+ #Drx.examinetk("some_string")
data/lib/drx_test2.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'dm-core'
3
+
4
+ class Post
5
+ include DataMapper::Resource
6
+
7
+ property :post_id, Integer, :serial => true
8
+ property :title, String
9
+ property :body, Text
10
+
11
+ belongs_to :user
12
+ end
13
+
14
+ class User
15
+ include DataMapper::Resource
16
+
17
+ property :user_uid, Integer, :serial => true
18
+ property :name, String
19
+ property :mail, String
20
+ end
21
+
22
+ post = Post.new
23
+
24
+ require 'drxtk'
25
+ Drx.see(post)
data/lib/drxtk.rb ADDED
@@ -0,0 +1,126 @@
1
+ require 'drx'
2
+ require 'tk'
3
+
4
+ module Drx
5
+ def self.examinetk(obj)
6
+ app = Drx::TkGUI::DrxWindow.new
7
+ app.display_value(obj)
8
+ app.run
9
+ end
10
+
11
+ # easier to type...
12
+ def self.see(obj)
13
+ examinetk(obj)
14
+ end
15
+ end
16
+
17
+ module Drx
18
+ module TkGUI
19
+
20
+ class ScrolledListbox < TkFrame
21
+ def initialize(*args, &block)
22
+ super(*args, &block)
23
+ @the_list = the_list = TkListbox.new(self) {
24
+ #pack :side => 'left'#, :expand => 'true', :fill => 'both'
25
+ }
26
+ TkScrollbar.new(self) { |s|
27
+ pack :side => 'right', :fill => 'y'
28
+ command { |*args| the_list.yview *args }
29
+ the_list.yscrollcommand { |first,last| s.set first,last }
30
+ }
31
+ TkScrollbar.new(self) { |s|
32
+ orient 'horizontal'
33
+ pack :side => 'bottom', :fill => 'x'
34
+ command { |*args| the_list.xview *args }
35
+ the_list.xscrollcommand { |first,last| s.set first,last }
36
+ }
37
+ @the_list.pack(:side => 'left', :expand => 'true', :fill => 'both')
38
+ end
39
+ def the_list
40
+ @the_list
41
+ end
42
+ end
43
+
44
+ class ::TkListbox
45
+ def get_selection
46
+ idx = curselection[0]
47
+ return get(idx)
48
+ end
49
+ def get_index
50
+ curselection[0]
51
+ end
52
+ end
53
+
54
+ class DrxWindow
55
+ def initialize
56
+ root = TkRoot.new
57
+ @list = (ScrolledListbox.new(root) {
58
+ #pack :side => 'left', :fill => 'y'
59
+ pack :side => 'left', :fill => 'both', :expand => true
60
+ }).the_list
61
+ @list.width 52
62
+ @list.height 25
63
+ @list.focus
64
+ @varsbox = (ScrolledListbox.new(root) {
65
+ #pack :side => 'left', :fill => 'y'
66
+ pack :side => 'left', :fill => 'both', :expand => true
67
+ }).the_list
68
+ @methodsbox = (ScrolledListbox.new(root) {
69
+ #pack :side => 'left', :fill => 'y'
70
+ pack :side => 'left', :fill => 'both', :expand => true
71
+ }).the_list
72
+
73
+ @list.bind('<ListboxSelect>') {
74
+ @current_object = @objs[@list.get_index]
75
+ display_variables(current_object)
76
+ display_methods(current_object)
77
+ }
78
+ @varsbox.bind('<ListboxSelect>') {
79
+ inspect_variable(current_object, @varsbox.get_selection)
80
+ }
81
+ end
82
+
83
+ # def current_object=(obj)
84
+ # @current_object = obj
85
+ # end
86
+
87
+ def current_object
88
+ @current_object
89
+ end
90
+
91
+ def display_variables(obj)
92
+ @varsbox.delete('0', 'end')
93
+ if (Drx.has_iv_tbl(obj))
94
+ vars = Drx.get_iv_tbl(obj).keys.map do |v| v.to_s end.sort
95
+ @varsbox.insert('end', *vars)
96
+ end
97
+ end
98
+
99
+ def inspect_variable(obj, var_name)
100
+ print "\n== Variable #{var_name}\n\n"
101
+ p Drx.get_ivar(obj, var_name)
102
+ end
103
+
104
+ def display_methods(obj)
105
+ @methodsbox.delete('0', 'end')
106
+ if (Drx.is_class_like(obj))
107
+ methods = Drx.get_m_tbl(obj).keys.map do |v| v.to_s end.sort
108
+ @methodsbox.insert('end', *methods)
109
+ end
110
+ end
111
+
112
+ def display_value(value)
113
+ @objs = []
114
+ Drx.examine(value) do |line, obj|
115
+ @list.insert('end', line)
116
+ @objs << obj
117
+ end
118
+ end
119
+
120
+ def run
121
+ Tk.mainloop
122
+ end
123
+ end
124
+
125
+ end # module TkGUI
126
+ end # module Drx
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: drx
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mooffie
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-03 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: mooffie@gmail.com
18
+ executables: []
19
+
20
+ extensions:
21
+ - ext/extconf.rb
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - README
26
+ - lib/drxtk.rb
27
+ - lib/drx_test2.rb
28
+ - lib/drx_test.rb
29
+ - lib/drx.rb
30
+ - ext/extconf.rb
31
+ - ext/drx_ext.c
32
+ has_rdoc: false
33
+ homepage: http://drx.rubyforge.org/
34
+ post_install_message:
35
+ rdoc_options: []
36
+
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: "1.8"
44
+ version:
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ requirements: []
52
+
53
+ rubyforge_project: drx
54
+ rubygems_version: 1.3.1
55
+ signing_key:
56
+ specification_version: 2
57
+ summary: Inspect Ruby objects.
58
+ test_files: []
59
+