looksee 0.2.1 → 1.0.0

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 (57) hide show
  1. data/CHANGELOG +14 -0
  2. data/LICENSE +22 -0
  3. data/README.markdown +161 -0
  4. data/Rakefile +9 -36
  5. data/ext/extconf.rb +9 -0
  6. data/ext/mri/1.9.2/debug.h +36 -0
  7. data/ext/mri/1.9.2/id.h +170 -0
  8. data/ext/mri/1.9.2/method.h +103 -0
  9. data/ext/mri/1.9.2/node.h +483 -0
  10. data/ext/mri/1.9.2/thread_pthread.h +27 -0
  11. data/ext/mri/1.9.2/vm_core.h +707 -0
  12. data/ext/mri/1.9.2/vm_opts.h +51 -0
  13. data/ext/mri/env-1.8.h +27 -0
  14. data/ext/mri/eval_c-1.8.h +27 -0
  15. data/ext/mri/mri.c +269 -0
  16. data/ext/{looksee → mri}/node-1.9.h +0 -0
  17. data/ext/rbx/rbx.c +13 -0
  18. data/lib/looksee.rb +4 -385
  19. data/lib/looksee/adapter.rb +10 -0
  20. data/lib/looksee/adapter/base.rb +100 -0
  21. data/lib/looksee/adapter/rubinius.rb +73 -0
  22. data/lib/looksee/clean.rb +122 -0
  23. data/lib/looksee/columnizer.rb +73 -0
  24. data/lib/looksee/core_ext.rb +59 -0
  25. data/lib/looksee/editor.rb +58 -0
  26. data/lib/looksee/help.rb +54 -0
  27. data/lib/looksee/inspector.rb +55 -0
  28. data/lib/looksee/lookup_path.rb +95 -0
  29. data/lib/looksee/rbx.bundle +0 -0
  30. data/lib/looksee/shortcuts.rb +1 -105
  31. data/lib/looksee/version.rb +9 -1
  32. data/lib/looksee/wirble_compatibility.rb +2 -3
  33. data/spec/adapter_spec.rb +546 -0
  34. data/spec/columnizer_spec.rb +52 -0
  35. data/spec/core_ext_spec.rb +41 -0
  36. data/spec/editor_spec.rb +128 -0
  37. data/spec/inspector_spec.rb +178 -0
  38. data/spec/lookup_path_spec.rb +84 -0
  39. data/spec/spec_helper.rb +13 -127
  40. data/spec/support/core_ext.rb +25 -0
  41. data/spec/support/temporary_classes.rb +102 -0
  42. data/spec/support/test_adapter.rb +72 -0
  43. data/spec/wirble_compatibility_spec.rb +20 -23
  44. metadata +91 -57
  45. data/.autotest +0 -9
  46. data/History.txt +0 -22
  47. data/Manifest.txt +0 -21
  48. data/README.rdoc +0 -129
  49. data/ext/looksee/extconf.rb +0 -6
  50. data/ext/looksee/looksee.c +0 -144
  51. data/looksee.gemspec +0 -44
  52. data/script/console +0 -7
  53. data/script/destroy +0 -14
  54. data/script/generate +0 -14
  55. data/spec/looksee_spec.rb +0 -425
  56. data/tasks/extconf.rake +0 -13
  57. data/tasks/extconf/looksee.rake +0 -43
@@ -0,0 +1,51 @@
1
+ /*-*-c-*-*/
2
+ /**********************************************************************
3
+
4
+ vm_opts.h - VM optimize option
5
+
6
+ $Author: akr $
7
+
8
+ Copyright (C) 2004-2007 Koichi Sasada
9
+
10
+ **********************************************************************/
11
+
12
+
13
+ #ifndef RUBY_VM_OPTS_H
14
+ #define RUBY_VM_OPTS_H
15
+
16
+ /* Compile options.
17
+ * You can change these options at runtime by VM::CompileOption.
18
+ * Following definitions are default values.
19
+ */
20
+
21
+ #define OPT_TRACE_INSTRUCTION 1
22
+ #define OPT_TAILCALL_OPTIMIZATION 0
23
+ #define OPT_PEEPHOLE_OPTIMIZATION 1
24
+ #define OPT_SPECIALISED_INSTRUCTION 1
25
+ #define OPT_INLINE_CONST_CACHE 1
26
+
27
+
28
+ /* Build Options.
29
+ * You can't change these options at runtime.
30
+ */
31
+
32
+ /* C compiler depend */
33
+ #define OPT_DIRECT_THREADED_CODE 1
34
+ #define OPT_TOKEN_THREADED_CODE 0
35
+ #define OPT_CALL_THREADED_CODE 0
36
+
37
+ /* VM running option */
38
+ #define OPT_CHECKED_RUN 1
39
+ #define OPT_INLINE_METHOD_CACHE 1
40
+ #define OPT_BLOCKINLINING 0
41
+
42
+ /* architecture independent, affects generated code */
43
+ #define OPT_OPERANDS_UNIFICATION 0
44
+ #define OPT_INSTRUCTIONS_UNIFICATION 0
45
+ #define OPT_UNIFY_ALL_COMBINATION 0
46
+ #define OPT_STACK_CACHING 0
47
+
48
+ /* misc */
49
+ #define SUPPORT_JOKE 0
50
+
51
+ #endif /* RUBY_VM_OPTS_H */
data/ext/mri/env-1.8.h ADDED
@@ -0,0 +1,27 @@
1
+ struct FRAME {
2
+ VALUE self;
3
+ int argc;
4
+ ID last_func;
5
+ ID orig_func;
6
+ VALUE last_class;
7
+ struct FRAME *prev;
8
+ struct FRAME *tmp;
9
+ struct RNode *node;
10
+ int iter;
11
+ int flags;
12
+ unsigned long uniq;
13
+ };
14
+
15
+ struct SCOPE {
16
+ struct RBasic super;
17
+ ID *local_tbl;
18
+ VALUE *local_vars;
19
+ int flags;
20
+ };
21
+
22
+ struct RVarmap {
23
+ struct RBasic super;
24
+ ID id;
25
+ VALUE val;
26
+ struct RVarmap *next;
27
+ };
@@ -0,0 +1,27 @@
1
+ struct BLOCK {
2
+ NODE *var;
3
+ NODE *body;
4
+ VALUE self;
5
+ struct FRAME frame;
6
+ struct SCOPE *scope;
7
+ VALUE klass;
8
+ NODE *cref;
9
+ int iter;
10
+ int vmode;
11
+ int flags;
12
+ int uniq;
13
+ struct RVarmap *dyna_vars;
14
+ VALUE orig_thread;
15
+ VALUE wrapper;
16
+ VALUE block_obj;
17
+ struct BLOCK *outer;
18
+ struct BLOCK *prev;
19
+ };
20
+
21
+ struct METHOD {
22
+ VALUE klass, rklass;
23
+ VALUE recv;
24
+ ID id, oid;
25
+ int safe_level;
26
+ NODE *body;
27
+ };
data/ext/mri/mri.c ADDED
@@ -0,0 +1,269 @@
1
+ #include "ruby.h"
2
+
3
+ #if RUBY_VERSION >= 192
4
+ # include "vm_core.h"
5
+ # include "method.h"
6
+ # include "ruby/st.h"
7
+ #elif RUBY_VERSION >= 190
8
+ # include "node-1.9.h"
9
+ # include "ruby/st.h"
10
+ #else
11
+ # include "node.h"
12
+ # include "st.h"
13
+ #endif
14
+
15
+ #if RUBY_VERSION < 187
16
+ # define RCLASS_IV_TBL(c) (RCLASS(c)->iv_tbl)
17
+ # define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
18
+ # define RCLASS_SUPER(c) (RCLASS(c)->super)
19
+ #endif
20
+
21
+ /*
22
+ * Return the internal superclass of this class.
23
+ *
24
+ * This is either a Class or "IClass." IClasses represent Modules
25
+ * included in the ancestry, and should be treated as opaque objects
26
+ * in ruby space. Convert the IClass to a Module using #iclass_to_module
27
+ * before using it in ruby.
28
+ */
29
+ VALUE Looksee_internal_superclass(VALUE self, VALUE internal_class) {
30
+ VALUE super = RCLASS_SUPER(internal_class);
31
+ if (!super)
32
+ return Qnil;
33
+ return super;
34
+ }
35
+
36
+ /*
37
+ * Return the internal class of the given object.
38
+ *
39
+ * This is either the object's singleton class, if it exists, or the
40
+ * object's birth class.
41
+ */
42
+ VALUE Looksee_internal_class(VALUE self, VALUE object) {
43
+ return CLASS_OF(object);
44
+ }
45
+
46
+ /*
47
+ * Return the class or module that the given internal class
48
+ * represents.
49
+ *
50
+ * If a class is given, this is the class. If an iclass is given,
51
+ * this is the module it represents in the lookup chain.
52
+ */
53
+ VALUE Looksee_internal_class_to_module(VALUE self, VALUE internal_class) {
54
+ if (!SPECIAL_CONST_P(internal_class)) {
55
+ switch (BUILTIN_TYPE(internal_class)) {
56
+ case T_ICLASS:
57
+ return RBASIC(internal_class)->klass;
58
+ case T_CLASS:
59
+ return internal_class;
60
+ }
61
+ }
62
+ rb_raise(rb_eArgError, "not an internal class: %s", RSTRING_PTR(rb_inspect(internal_class)));
63
+ }
64
+
65
+ #if RUBY_VERSION >= 192
66
+
67
+ # define VISIBILITY_TYPE rb_method_flag_t
68
+
69
+ typedef struct add_method_if_matching_arg {
70
+ VALUE names;
71
+ VISIBILITY_TYPE visibility;
72
+ } add_method_if_matching_arg_t;
73
+
74
+ static int add_method_if_matching(ID method_name, rb_method_entry_t *me, add_method_if_matching_arg_t *arg) {
75
+ if (method_name == ID_ALLOCATOR)
76
+ return ST_CONTINUE;
77
+
78
+ if (UNDEFINED_METHOD_ENTRY_P(me))
79
+ return ST_CONTINUE;
80
+
81
+ if ((me->flag & NOEX_MASK) == arg->visibility)
82
+ rb_ary_push(arg->names, ID2SYM(method_name));
83
+
84
+ return ST_CONTINUE;
85
+ }
86
+
87
+ static int add_method_if_undefined(ID method_name, rb_method_entry_t *me, VALUE *names) {
88
+ if (UNDEFINED_METHOD_ENTRY_P(me))
89
+ rb_ary_push(*names, ID2SYM(method_name));
90
+ return ST_CONTINUE;
91
+ }
92
+
93
+ #else
94
+
95
+ # if RUBY_VERSION >= 190
96
+ # define VISIBILITY(node) ((node)->nd_body->nd_noex & NOEX_MASK)
97
+ # else
98
+ # define VISIBILITY(node) ((node)->nd_noex & NOEX_MASK)
99
+ # endif
100
+
101
+ # define VISIBILITY_TYPE unsigned long
102
+
103
+ typedef struct add_method_if_matching_arg {
104
+ VALUE names;
105
+ VISIBILITY_TYPE visibility;
106
+ } add_method_if_matching_arg_t;
107
+
108
+ static int add_method_if_matching(ID method_name, NODE *body, add_method_if_matching_arg_t *arg) {
109
+ /* This entry is for the internal allocator function. */
110
+ if (method_name == ID_ALLOCATOR)
111
+ return ST_CONTINUE;
112
+
113
+ /* Module#undef_method:
114
+ * * sets body->nd_body to NULL in ruby <= 1.8
115
+ * * sets body to NULL in ruby >= 1.9
116
+ */
117
+ if (!body || !body->nd_body)
118
+ return ST_CONTINUE;
119
+
120
+ if (VISIBILITY(body) == arg->visibility)
121
+ rb_ary_push(arg->names, ID2SYM(method_name));
122
+ return ST_CONTINUE;
123
+ }
124
+
125
+ static int add_method_if_undefined(ID method_name, NODE *body, VALUE *names) {
126
+ if (!body || !body->nd_body)
127
+ rb_ary_push(*names, ID2SYM(method_name));
128
+ return ST_CONTINUE;
129
+ }
130
+
131
+ #endif
132
+
133
+ static VALUE internal_instance_methods(VALUE klass, VISIBILITY_TYPE visibility) {
134
+ add_method_if_matching_arg_t arg;
135
+ arg.names = rb_ary_new();
136
+ arg.visibility = visibility;
137
+ st_foreach(RCLASS_M_TBL(klass), add_method_if_matching, (st_data_t)&arg);
138
+ return arg.names;
139
+ }
140
+
141
+ /*
142
+ * Return the list of public instance methods (as Symbols) of the
143
+ * given internal class.
144
+ */
145
+ VALUE Looksee_internal_public_instance_methods(VALUE self, VALUE klass) {
146
+ return internal_instance_methods(klass, NOEX_PUBLIC);
147
+ }
148
+
149
+ /*
150
+ * Return the list of protected instance methods (as Symbols) of the
151
+ * given internal class.
152
+ */
153
+ VALUE Looksee_internal_protected_instance_methods(VALUE self, VALUE klass) {
154
+ return internal_instance_methods(klass, NOEX_PROTECTED);
155
+ }
156
+
157
+ /*
158
+ * Return the list of private instance methods (as Symbols) of the
159
+ * given internal class.
160
+ */
161
+ VALUE Looksee_internal_private_instance_methods(VALUE self, VALUE klass) {
162
+ return internal_instance_methods(klass, NOEX_PRIVATE);
163
+ }
164
+
165
+ /*
166
+ * Return the list of undefined instance methods (as Symbols) of the
167
+ * given internal class.
168
+ */
169
+ VALUE Looksee_internal_undefined_instance_methods(VALUE self, VALUE klass) {
170
+ VALUE names = rb_ary_new();
171
+ st_foreach(RCLASS_M_TBL(klass), add_method_if_undefined, (st_data_t)&names);
172
+ return names;
173
+ }
174
+
175
+ VALUE Looksee_singleton_class_p(VALUE self, VALUE object) {
176
+ return BUILTIN_TYPE(object) == T_CLASS && FL_TEST(object, FL_SINGLETON) ? Qtrue : Qfalse;
177
+ }
178
+
179
+ VALUE Looksee_singleton_instance(VALUE self, VALUE singleton_class) {
180
+ if (BUILTIN_TYPE(singleton_class) == T_CLASS && FL_TEST(singleton_class, FL_SINGLETON)) {
181
+ VALUE object;
182
+ if (!st_lookup(RCLASS_IV_TBL(singleton_class), rb_intern("__attached__"), (st_data_t *)&object))
183
+ rb_raise(rb_eRuntimeError, "[looksee bug] can't find singleton object");
184
+ return object;
185
+ } else {
186
+ rb_raise(rb_eTypeError, "expected singleton class, got %s", rb_obj_classname(singleton_class));
187
+ }
188
+ }
189
+
190
+ VALUE Looksee_module_name(VALUE self, VALUE module) {
191
+ if (BUILTIN_TYPE(module) == T_CLASS || BUILTIN_TYPE(module) == T_MODULE) {
192
+ VALUE name = rb_mod_name(module);
193
+ return name == Qnil ? rb_str_new2("") : name;
194
+ } else {
195
+ rb_raise(rb_eTypeError, "expected module, got %s", rb_obj_classname(module));
196
+ }
197
+ }
198
+
199
+ #if RUBY_VERSION < 190
200
+
201
+ #include "env-1.8.h"
202
+ #include "eval_c-1.8.h"
203
+
204
+ /*
205
+ * Return the source file and line number of the given object and method.
206
+ */
207
+ VALUE Looksee_source_location(VALUE self, VALUE unbound_method) {
208
+ if (!rb_obj_is_kind_of(unbound_method, rb_cUnboundMethod))
209
+ rb_raise(rb_eTypeError, "expected UnboundMethod, got %s", rb_obj_classname(unbound_method));
210
+
211
+ struct METHOD *method;
212
+ Data_Get_Struct(unbound_method, struct METHOD, method);
213
+
214
+ NODE *node;
215
+ switch (nd_type(method->body)) {
216
+ // Can't be a FBODY or ZSUPER.
217
+ case NODE_SCOPE:
218
+ node = method->body->nd_defn;
219
+ break;
220
+ case NODE_BMETHOD:
221
+ {
222
+ struct BLOCK *block;
223
+ Data_Get_Struct(method->body->nd_orig, struct BLOCK, block);
224
+ (node = block->frame.node) || (node = block->body);
225
+ // Proc#to_s suggests this may be NULL sometimes.
226
+ if (!node)
227
+ return Qnil;
228
+ }
229
+ break;
230
+ case NODE_DMETHOD:
231
+ {
232
+ struct METHOD *original_method;
233
+ NODE *body = method->body;
234
+ Data_Get_Struct(body->nd_orig, struct METHOD, original_method);
235
+ node = original_method->body->nd_defn;
236
+ }
237
+ break;
238
+ default:
239
+ rb_raise(rb_eRuntimeError, "[LOOKSEE BUG] unexpected NODE type: %d", nd_type(method->body));
240
+ }
241
+ VALUE file = rb_str_new2(node->nd_file);
242
+ VALUE line = INT2NUM(nd_line(node));
243
+ VALUE location = rb_ary_new2(2);
244
+ rb_ary_store(location, 0, file);
245
+ rb_ary_store(location, 1, line);
246
+ return location;
247
+ }
248
+
249
+ #endif
250
+
251
+ void Init_mri(void) {
252
+ VALUE mLooksee = rb_const_get(rb_cObject, rb_intern("Looksee"));
253
+ VALUE mAdapter = rb_const_get(mLooksee, rb_intern("Adapter"));
254
+ VALUE mBase = rb_const_get(mAdapter, rb_intern("Base"));
255
+ VALUE mMRI = rb_define_class_under(mAdapter, "MRI", mBase);
256
+ rb_define_method(mMRI, "internal_superclass", Looksee_internal_superclass, 1);
257
+ rb_define_method(mMRI, "internal_class", Looksee_internal_class, 1);
258
+ rb_define_method(mMRI, "internal_class_to_module", Looksee_internal_class_to_module, 1);
259
+ rb_define_method(mMRI, "internal_public_instance_methods", Looksee_internal_public_instance_methods, 1);
260
+ rb_define_method(mMRI, "internal_protected_instance_methods", Looksee_internal_protected_instance_methods, 1);
261
+ rb_define_method(mMRI, "internal_private_instance_methods", Looksee_internal_private_instance_methods, 1);
262
+ rb_define_method(mMRI, "internal_undefined_instance_methods", Looksee_internal_undefined_instance_methods, 1);
263
+ rb_define_method(mMRI, "singleton_class?", Looksee_singleton_class_p, 1);
264
+ rb_define_method(mMRI, "singleton_instance", Looksee_singleton_instance, 1);
265
+ rb_define_method(mMRI, "module_name", Looksee_module_name, 1);
266
+ #if RUBY_VERSION < 190
267
+ rb_define_method(mMRI, "source_location", Looksee_source_location, 1);
268
+ #endif
269
+ }
File without changes
data/ext/rbx/rbx.c ADDED
@@ -0,0 +1,13 @@
1
+ #include "ruby.h"
2
+
3
+ VALUE Looksee_internal_class(VALUE self, VALUE object) {
4
+ return CLASS_OF(object);
5
+ }
6
+
7
+ void Init_rbx(void) {
8
+ VALUE mLooksee = rb_const_get(rb_cObject, rb_intern("Looksee"));
9
+ VALUE mAdapter = rb_const_get(mLooksee, rb_intern("Adapter"));
10
+ VALUE mBase = rb_const_get(mAdapter, rb_intern("Base"));
11
+ VALUE mRubinius = rb_define_class_under(mAdapter, "Rubinius", mBase);
12
+ rb_define_method(mRubinius, "internal_class", Looksee_internal_class, 1);
13
+ }
data/lib/looksee.rb CHANGED
@@ -1,386 +1,5 @@
1
- require "rbconfig"
2
- require File.dirname(__FILE__) + "/../ext/looksee/looksee.#{Config::CONFIG['DLEXT']}"
3
- require "looksee/version"
1
+ require 'looksee/clean'
2
+ require 'looksee/core_ext'
4
3
 
5
- #
6
- # Looksee lets you inspect the method lookup path of an object. There
7
- # are two ways to use it:
8
- #
9
- # 1. Keep all methods contained in the Looksee namespace:
10
- #
11
- # require 'looksee'
12
- #
13
- # 2. Let it all hang out:
14
- #
15
- # require 'looksee/shortcuts'
16
- #
17
- # The latter adds the following shortcuts to the built-in classes:
18
- #
19
- # Object#lookup_path
20
- # Object#dump_lookup_path
21
- # Object#lp
22
- # Object#lpi
23
- #
24
- # See their docs.
25
- #
26
- # == Usage
27
- #
28
- # In irb:
29
- #
30
- # require 'looksee/shortcuts'
31
- # lp some_object
32
- #
33
- # +lp+ returns a LookupPath object, which has +inspect+ defined to
34
- # print things out pretty. By default, it shows public, protected,
35
- # undefined, and overridden methods. They're all colored, which makes
36
- # showing overridden methods not such a strange idea.
37
- #
38
- # Some examples of the other shortcuts:
39
- #
40
- # lpi Array
41
- # some_object.lookup_path
42
- # foo.bar.baz.dump_lookup_path.and.more
43
- #
44
- # If you're being namespace-clean, you'll need to do:
45
- #
46
- # require 'looksee'
47
- # Looksee.lookup_path(thing) # like "lp thing"
48
- #
49
- # For a quick reference:
50
- #
51
- # Looksee.help
52
- #
53
- # == Configuration
54
- #
55
- # Set these:
56
- #
57
- # Looksee.default_lookup_path_options
58
- # Looksee.default_width
59
- # Looksee.styles
60
- #
61
- # See their docs.
62
- #
63
- module Looksee
64
- class << self
65
- #
66
- # Return a collection of methods that +object+ responds to,
67
- # according to the options given. The following options are
68
- # recognized:
69
- #
70
- # * +:public+ - include public methods
71
- # * +:protected+ - include protected methods
72
- # * +:private+ - include private methods
73
- # * +:undefined+ - include undefined methods (see Module#undef_method)
74
- # * +:overridden+ - include methods overridden by subclasses
75
- #
76
- # The default (if options is nil or omitted) is given by
77
- # #default_lookup_path_options.
78
- #
79
- def lookup_path(object, *options)
80
- normalized_options = Looksee.default_lookup_path_options.dup
81
- hash_options = options.last.is_a?(Hash) ? options.pop : {}
82
- options.each do |option|
83
- normalized_options[option] = true
84
- end
85
- normalized_options.update(hash_options)
86
- LookupPath.for(object, normalized_options)
87
- end
88
-
89
- #
90
- # The default options passed to lookup_path.
91
- #
92
- # Default: <tt>{:public => true, :protected => true, :undefined =>
93
- # true, :overridden => true}</tt>
94
- #
95
- attr_accessor :default_lookup_path_options
96
-
97
- #
98
- # The width to use for displaying output, when not available in
99
- # the COLUMNS environment variable.
100
- #
101
- # Default: 80
102
- #
103
- attr_accessor :default_width
104
-
105
- #
106
- # The default styles to use for the +inspect+ strings.
107
- #
108
- # This is a hash with keys:
109
- #
110
- # * :module
111
- # * :public
112
- # * :protected
113
- # * :private
114
- # * :undefined
115
- # * :overridden
116
- #
117
- # The values are format strings. They should all contain a single
118
- # "%s", which is where the name is inserted.
119
- #
120
- # Default:
121
- #
122
- # {
123
- # :module => "\e[1;37m%s\e[0m", # white
124
- # :public => "\e[1;32m%s\e[0m", # green
125
- # :protected => "\e[1;33m%s\e[0m", # yellow
126
- # :private => "\e[1;31m%s\e[0m", # red
127
- # :undefined => "\e[1;34m%s\e[0m", # blue
128
- # :overridden => "\e[1;30m%s\e[0m", # black
129
- # }
130
- #
131
- attr_accessor :styles
132
-
133
- #
134
- # Return the chain of classes and modules which comprise the
135
- # object's method lookup path.
136
- #
137
- def lookup_modules(object)
138
- modules = []
139
- klass = Looksee.internal_class(object)
140
- while klass
141
- modules << Looksee.internal_class_to_module(klass)
142
- klass = Looksee.internal_superclass(klass)
143
- end
144
- modules
145
- end
146
- end
147
-
148
- self.default_lookup_path_options = {:public => true, :protected => true, :undefined => true, :overridden => true}
149
- self.default_width = 80
150
- self.styles = {
151
- :module => "\e[1;37m%s\e[0m", # white
152
- :public => "\e[1;32m%s\e[0m", # green
153
- :protected => "\e[1;33m%s\e[0m", # yellow
154
- :private => "\e[1;31m%s\e[0m", # red
155
- :undefined => "\e[1;34m%s\e[0m", # blue
156
- :overridden => "\e[1;30m%s\e[0m", # black
157
- }
158
-
159
- class LookupPath
160
- attr_reader :entries
161
-
162
- def initialize(entries)
163
- @entries = entries
164
- end
165
-
166
- #
167
- # Create a LookupPath for the given object.
168
- #
169
- # Options may be given to restrict which visibilities are
170
- # included.
171
- #
172
- # :public
173
- # :protected
174
- # :private
175
- # :undefined
176
- # :overridden
177
- #
178
- def self.for(object, options={})
179
- entries = entries_for(object, options)
180
- new(entries)
181
- end
182
-
183
- #
184
- # Return a new LookupPath which only contains names matching the
185
- # given pattern.
186
- #
187
- def grep(pattern)
188
- entries = self.entries.map do |entry|
189
- entry.grep(pattern)
190
- end
191
- self.class.new(entries)
192
- end
193
-
194
- def inspect(options={})
195
- options = normalize_inspect_options(options)
196
- entries.map{|e| e.inspect(options)}.join("\n")
197
- end
198
-
199
- private # -------------------------------------------------------
200
-
201
- def self.entries_for(object, options)
202
- seen = {}
203
- Looksee.lookup_modules(object).map do |mod|
204
- entry = Entry.for(mod, seen, options)
205
- entry.methods.each{|m| seen[m] = true}
206
- entry
207
- end
208
- end
209
-
210
- def normalize_inspect_options(options)
211
- options[:width] ||= ENV['COLUMNS'].to_i.nonzero? || Looksee.default_width
212
- options
213
- end
214
-
215
- #
216
- # An entry in the LookupPath.
217
- #
218
- # Contains a module and its methods, along with visibility
219
- # information (public, private, etc.).
220
- #
221
- class Entry
222
- def initialize(mod, methods=[], visibilities={})
223
- @module = mod
224
- @methods = methods
225
- @visibilities = visibilities
226
- end
227
-
228
- def self.for(mod, seen, options)
229
- entry = new(mod)
230
- entry.initialize_for(seen, options)
231
- entry
232
- end
233
-
234
- attr_reader :module, :methods
235
-
236
- def initialize_for(seen, options)
237
- add_methods(Looksee.internal_public_instance_methods(@module).map{|sym| sym.to_s} , :public , seen) if options[:public ]
238
- add_methods(Looksee.internal_protected_instance_methods(@module).map{|sym| sym.to_s}, :protected, seen) if options[:protected]
239
- add_methods(Looksee.internal_private_instance_methods(@module).map{|sym| sym.to_s} , :private , seen) if options[:private ]
240
- add_methods(Looksee.internal_undefined_instance_methods(@module).map{|sym| sym.to_s}, :undefined, seen) if options[:undefined]
241
- @methods.sort!
242
- end
243
-
244
- def grep(pattern)
245
- methods = []
246
- visibilities = {}
247
- @methods.each do |name|
248
- if name[pattern]
249
- methods << name
250
- visibilities[name] = @visibilities[name]
251
- end
252
- end
253
- self.class.new(@module, methods, visibilities)
254
- end
255
-
256
- #
257
- # Return the name of the class or module.
258
- #
259
- # Singleton classes are displayed in brackets. Singleton class
260
- # of singleton classes are displayed in double brackets. But
261
- # you'd never need that, would you?
262
- #
263
- def module_name
264
- name = @module.to_s # #name doesn't do singleton classes right
265
- nil while name.sub!(/#<Class:(.*)>/, '[\\1]')
266
- name
267
- end
268
-
269
- #
270
- # Yield each method along with its visibility (:public,
271
- # :private, :protected, :undefined, or :overridden).
272
- #
273
- def each
274
- @methods.each do |name|
275
- yield name, @visibilities[name]
276
- end
277
- end
278
-
279
- include Enumerable
280
-
281
- #
282
- # Return a nice, pretty string for inspection.
283
- #
284
- # Contains the module name, plus the method names laid out in
285
- # columns. Pass a :width option to control the output width.
286
- #
287
- def inspect(options={})
288
- string = styled_module_name << "\n" << Columnizer.columnize(styled_methods, options[:width])
289
- string.chomp
290
- end
291
-
292
- private # -----------------------------------------------------
293
-
294
- def add_methods(methods, visibility, seen)
295
- methods.each do |method|
296
- @methods << method
297
- @visibilities[method] = seen[method] ? :overridden : visibility
298
- end
299
- end
300
-
301
- def styled_module_name
302
- Looksee.styles[:module] % module_name
303
- end
304
-
305
- def styled_methods
306
- map do |name, visibility|
307
- Looksee.styles[visibility] % name
308
- end
309
- end
310
- end
311
- end
312
-
313
- module Columnizer
314
- class << self
315
- #
316
- # Arrange the given strings in columns, restricted to the given
317
- # width. Smart enough to ignore content in terminal control
318
- # sequences.
319
- #
320
- def columnize(strings, width)
321
- return '' if strings.empty?
322
-
323
- num_columns = 1
324
- layout = [strings]
325
- loop do
326
- break if layout.first.length <= 1
327
- next_layout = layout_in_columns(strings, num_columns + 1)
328
- break if layout_width(next_layout) > width
329
- layout = next_layout
330
- num_columns += 1
331
- end
332
-
333
- pad_strings(layout)
334
- rectangularize_layout(layout)
335
- layout.transpose.map do |row|
336
- ' ' + row.compact.join(' ')
337
- end.join("\n") << "\n"
338
- end
339
-
340
- private # -----------------------------------------------------
341
-
342
- def layout_in_columns(strings, num_columns)
343
- strings_per_column = (strings.length / num_columns.to_f).ceil
344
- (0...num_columns).map{|i| strings[i*strings_per_column...(i+1)*strings_per_column] || []}
345
- end
346
-
347
- def layout_width(layout)
348
- widths = layout_column_widths(layout)
349
- widths.inject(0){|sum, w| sum + w} + 2*layout.length
350
- end
351
-
352
- def layout_column_widths(layout)
353
- layout.map do |column|
354
- column.map{|string| display_width(string)}.max || 0
355
- end
356
- end
357
-
358
- def display_width(string)
359
- # remove terminal control sequences
360
- string.gsub(/\e\[.*?m/, '').length
361
- end
362
-
363
- def pad_strings(layout)
364
- widths = layout_column_widths(layout)
365
- layout.each_with_index do |column, i|
366
- column_width = widths[i]
367
- column.each do |string|
368
- padding = column_width - display_width(string)
369
- string << ' '*padding
370
- end
371
- end
372
- end
373
-
374
- def rectangularize_layout(layout)
375
- return if layout.length == 1
376
- height = layout[0].length
377
- layout[1..-1].each do |column|
378
- column.length == height or
379
- column[height - 1] = nil
380
- end
381
- end
382
- end
383
- end
384
- end
385
-
386
- require 'looksee/wirble_compatibility'
4
+ # Ugh.
5
+ Looksee::WirbleCompatibility.init