drx 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 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
+