looksee 1.0.0-universal-java-1.6

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 (45) hide show
  1. data/CHANGELOG +14 -0
  2. data/LICENSE +22 -0
  3. data/README.markdown +161 -0
  4. data/Rakefile +10 -0
  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/mri/node-1.9.h +35 -0
  17. data/ext/rbx/rbx.c +13 -0
  18. data/lib/looksee.rb +5 -0
  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/jruby.jar +0 -0
  29. data/lib/looksee/lookup_path.rb +95 -0
  30. data/lib/looksee/rbx.bundle +0 -0
  31. data/lib/looksee/shortcuts.rb +3 -0
  32. data/lib/looksee/version.rb +11 -0
  33. data/lib/looksee/wirble_compatibility.rb +86 -0
  34. data/spec/adapter_spec.rb +546 -0
  35. data/spec/columnizer_spec.rb +52 -0
  36. data/spec/core_ext_spec.rb +41 -0
  37. data/spec/editor_spec.rb +128 -0
  38. data/spec/inspector_spec.rb +178 -0
  39. data/spec/lookup_path_spec.rb +84 -0
  40. data/spec/spec_helper.rb +25 -0
  41. data/spec/support/core_ext.rb +25 -0
  42. data/spec/support/temporary_classes.rb +102 -0
  43. data/spec/support/test_adapter.rb +72 -0
  44. data/spec/wirble_compatibility_spec.rb +116 -0
  45. metadata +158 -0
@@ -0,0 +1,54 @@
1
+ module Looksee
2
+ class Help
3
+ def inspect
4
+ <<-EOS.gsub(/^ *\|/, '')
5
+ |== Looksee Quick Reference
6
+ |
7
+ | object.ls(*specifiers)
8
+ | Print the methods of \`object\'.
9
+ |
10
+ | Available specifiers:
11
+ |
12
+ | :public :private :overridden
13
+ | :protected :undefined
14
+ | Print methods with these visibilities.
15
+ |
16
+ | :nopublic :noprivate :nooverridden
17
+ | :noprotected :noundefined
18
+ | Do not print methods with these visibilities.
19
+ |
20
+ | "string"
21
+ | Print methods containing this string.
22
+ |
23
+ | /regexp/
24
+ | Print methods matching this regexp.
25
+ |
26
+ | Styles:
27
+ |
28
+ | #{Looksee.styles[:module] % 'Module'}
29
+ | #{Looksee.styles[:public] % 'public'} }
30
+ | #{Looksee.styles[:protected] % 'protected'} } like a traffic light!
31
+ | #{Looksee.styles[:private] % 'private'} }
32
+ | #{Looksee.styles[:undefined] % 'undefined'} ] like a ghost!
33
+ | #{Looksee.styles[:overridden] % 'overridden'} ] like a shadow!
34
+ |
35
+ | Customize with Looksee.styles:
36
+ |
37
+ | Looksee.styles = {
38
+ | :module => '**%s**',
39
+ | :private => '(%s)',
40
+ | ...
41
+ | }
42
+ |
43
+ | object.edit(method)
44
+ |
45
+ | Jump to the source of the given method. Set your editor
46
+ | with Looksee.editor or the LOOKSEE_EDITOR environment
47
+ | variable. "%f" expands to the file name, "%l" to the line
48
+ | number. Example:
49
+ |
50
+ | Looksee.editor = "emacs -nw +%f %l"
51
+ EOS
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,55 @@
1
+ module Looksee
2
+ class Inspector
3
+ def initialize(lookup_path, options={})
4
+ @lookup_path = lookup_path
5
+ @visibilities = (vs = options[:visibilities]) ? vs.to_set : Set[]
6
+ @filters = (fs = options[:filters]) ? fs.to_set : Set[]
7
+ @width = options[:width] || ENV['COLUMNS'].to_i.nonzero? || Looksee.default_width
8
+ end
9
+
10
+ attr_reader :lookup_path
11
+ attr_reader :visibilities
12
+ attr_reader :filters
13
+
14
+ def inspect
15
+ lookup_path.entries.reverse.map do |entry|
16
+ inspect_entry(entry)
17
+ end.join("\n")
18
+ end
19
+
20
+ private
21
+
22
+ def inspect_entry(entry)
23
+ string = styled_module_name(entry) << "\n"
24
+ string << Columnizer.columnize(styled_methods(entry), @width)
25
+ string.chomp
26
+ end
27
+
28
+ def styled_module_name(entry)
29
+ Looksee.styles[:module] % Looksee.adapter.describe_module(entry.module)
30
+ end
31
+
32
+ def styled_methods(entry)
33
+ pattern = filter_pattern
34
+ show_overridden = @visibilities.include?(:overridden)
35
+ entry.map do |name, visibility|
36
+ next if !selected?(name, visibility)
37
+ style = entry.overridden?(name) ? :overridden : visibility
38
+ next if style == :overridden && !show_overridden
39
+ Looksee.styles[style] % name
40
+ end.compact
41
+ end
42
+
43
+ def filter_pattern
44
+ strings = filters.grep(String)
45
+ regexps = filters.grep(Regexp)
46
+ string_patterns = strings.map{|s| Regexp.escape(s)}
47
+ regexp_patterns = regexps.map{|s| s.source}
48
+ /#{(string_patterns + regexp_patterns).join('|')}/
49
+ end
50
+
51
+ def selected?(name, visibility)
52
+ @visibilities.include?(visibility) && name =~ filter_pattern
53
+ end
54
+ end
55
+ end
Binary file
@@ -0,0 +1,95 @@
1
+ module Looksee
2
+ #
3
+ # Represents the method lookup path of an object, as a list of
4
+ # Entries.
5
+ #
6
+ class LookupPath
7
+ def initialize(object)
8
+ @object = object
9
+ @entries = create_entries
10
+ end
11
+
12
+ #
13
+ # The object this lookup path represents.
14
+ #
15
+ attr_reader :object
16
+
17
+ #
18
+ # List of Entry objects, each one representing a Module in the
19
+ # lookup path.
20
+ #
21
+ attr_reader :entries
22
+
23
+ def find(name)
24
+ entries.each do |entry|
25
+ visibility = entry.methods[name] or
26
+ next
27
+
28
+ if visibility == :undefined
29
+ return nil
30
+ else
31
+ return entry.module.instance_method(name)
32
+ end
33
+ end
34
+ nil
35
+ end
36
+
37
+ #
38
+ # Return a string showing the object's lookup path.
39
+ #
40
+ def inspect(options={})
41
+ Inspector.new(self, options).inspect
42
+ end
43
+
44
+ private # -------------------------------------------------------
45
+
46
+ def create_entries
47
+ seen = Set.new
48
+ Looksee.adapter.lookup_modules(object).map do |mod|
49
+ entry = Entry.new(mod, seen)
50
+ seen += entry.methods.keys
51
+ entry
52
+ end
53
+ end
54
+
55
+ #
56
+ # An entry in the LookupPath.
57
+ #
58
+ class Entry
59
+ def initialize(mod, overridden)
60
+ @module = mod
61
+ @methods = find_methods
62
+ @overridden = overridden
63
+ end
64
+
65
+ attr_reader :module, :methods
66
+
67
+ def overridden?(name)
68
+ @overridden.include?(name.to_s)
69
+ end
70
+
71
+ #
72
+ # Yield each method in alphabetical order along with its
73
+ # visibility (:public, :private, :protected, :undefined, or
74
+ # :overridden).
75
+ #
76
+ def each(&block)
77
+ @methods.sort.each(&block)
78
+ end
79
+
80
+ include Enumerable
81
+
82
+ private # -----------------------------------------------------
83
+
84
+ def find_methods
85
+ methods = {}
86
+ [:public, :protected, :private, :undefined].each do |visibility|
87
+ Looksee.adapter.send("internal_#{visibility}_instance_methods", @module).each do |method|
88
+ methods[method.to_s] = visibility
89
+ end
90
+ end
91
+ methods
92
+ end
93
+ end
94
+ end
95
+ end
Binary file
@@ -0,0 +1,3 @@
1
+ require 'looksee'
2
+
3
+ warn "'looksee/shortcuts' is deprecated; please require 'looksee' instead."
@@ -0,0 +1,11 @@
1
+ module Looksee
2
+ VERSION = [1, 0, 0]
3
+
4
+ class << VERSION
5
+ include Comparable
6
+
7
+ def to_s
8
+ join('.')
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,86 @@
1
+ module Looksee
2
+ module WirbleCompatibility
3
+ class << self
4
+ def wirble_loaded?
5
+ Object.const_defined?(:Wirble) &&
6
+ Wirble.is_a?(Module) &&
7
+ Wirble.respond_to?(:colorize)
8
+ end
9
+
10
+ def wirble_colorizing?
11
+ require 'irb'
12
+ IRB::Irb.method_defined?(:non_color_output_value)
13
+ end
14
+
15
+ def hook_into_wirble_load
16
+ unless Object.const_defined?(:Wirble)
17
+ Object.const_set :Wirble, Module.new
18
+ end
19
+ Wirble.send :extend, WirbleLoadHook
20
+ end
21
+
22
+ def hook_into_wirble_colorize
23
+ class << Wirble
24
+ def colorize_with_looksee(*args)
25
+ # If this gets called twice, Wirble will fuck up the
26
+ # aliases. Disable colorizing first to reset them.
27
+ if WirbleCompatibility.hooked_into_irb_output_value?
28
+ Wirble::Colorize.disable
29
+ end
30
+ colorize_without_looksee(*args)
31
+ WirbleCompatibility.hook_into_irb_output_value
32
+ end
33
+
34
+ alias colorize_without_looksee colorize
35
+ alias colorize colorize_with_looksee
36
+ end
37
+ end
38
+
39
+ def hook_into_irb_output_value
40
+ IRB::Irb.class_eval do
41
+ def output_value_with_looksee
42
+ case @context.last_value
43
+ when Looksee::Inspector, Looksee::Help
44
+ non_color_output_value
45
+ else
46
+ output_value_without_looksee
47
+ end
48
+ end
49
+
50
+ alias output_value_without_looksee output_value
51
+ alias output_value output_value_with_looksee
52
+ end
53
+ end
54
+
55
+ def hooked_into_irb_output_value?
56
+ IRB::Irb.method_defined?(:output_value_with_looksee)
57
+ end
58
+
59
+ def init
60
+ #
61
+ # How wirble is used:
62
+ #
63
+ # * Wirble is required/loaded. Defines Wirble module, with methods like Wirble.colorize.
64
+ # * Wirble.init is called. Nothing interesting.
65
+ # * Wirble.colorize is called. Hooks into IRB::Irb.output_value via an alias.
66
+ #
67
+ if !wirble_loaded?
68
+ hook_into_wirble_load
69
+ elsif !wirble_colorizing?
70
+ hook_into_wirble_colorize
71
+ else
72
+ hook_into_irb_output_value
73
+ end
74
+ end
75
+ end
76
+
77
+ module WirbleLoadHook
78
+ def singleton_method_added(name)
79
+ if name == :colorize && !respond_to?(:colorize_with_looksee)
80
+ WirbleCompatibility.hook_into_wirble_colorize
81
+ end
82
+ super
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,546 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Looksee.adapter" do
4
+ include TemporaryClasses
5
+
6
+ before do
7
+ @adapter = NATIVE_ADAPTER
8
+ end
9
+
10
+ describe "#lookup_modules" do
11
+ #
12
+ # Filter out modules which are hard to test against, and returns
13
+ # the list of module names. #inspect strings are used for names
14
+ # of singleton classes, since they have no name.
15
+ #
16
+ def filtered_lookup_modules(object)
17
+ result = @adapter.lookup_modules(object)
18
+ result.select{ |mod| deterministic_module?(mod) }
19
+ end
20
+
21
+ #
22
+ # Return true if the given module name is of a module we can test
23
+ # for.
24
+ #
25
+ # This excludes ruby version dependent modules, and modules tossed
26
+ # into the hierarchy by testing frameworks.
27
+ #
28
+ def deterministic_module?(mod)
29
+ junk_patterns = [
30
+ # pollution from testing libraries
31
+ 'Mocha', 'Spec',
32
+ # RSpec adds this under ruby 1.8.6
33
+ 'InstanceExecHelper',
34
+ # RSpec 2
35
+ 'RSpec::',
36
+ # only in ruby 1.9
37
+ 'BasicObject',
38
+ # something pulls this in under ruby 1.9
39
+ 'PP',
40
+ # our own pollution,
41
+ 'Looksee::Object',
42
+ ]
43
+ pattern = /\A(#{junk_patterns.join('|')})/
44
+
45
+ # Singleton classes of junk are junk.
46
+ if Looksee.ruby_engine == 'rbx'
47
+ # Rubinius singleton class #inspect strings aren't formatted
48
+ # like the others.
49
+ while mod.respond_to?(:__metaclass_object__) && (object = mod.__metaclass_object__).is_a?(Class)
50
+ mod = object
51
+ end
52
+ mod.name !~ pattern
53
+ else
54
+ name = mod.to_s
55
+ while name =~ /\A#<Class:(.*)>\z/
56
+ name = $1
57
+ end
58
+ name !~ pattern
59
+ end
60
+ end
61
+
62
+ it "should contain an entry for each module in the object's lookup path" do
63
+ temporary_module :Mod1
64
+ temporary_module :Mod2
65
+ temporary_class :Base
66
+ temporary_class :Derived, :superclass => Base do
67
+ include Mod1
68
+ include Mod2
69
+ end
70
+ filtered_lookup_modules(Derived.new) == [Derived, Mod2, Mod1, Base, Object, Kernel]
71
+ end
72
+
73
+ it "should contain an entry for the object's singleton class if it exists" do
74
+ object = Object.new
75
+ object.singleton_class
76
+
77
+ filtered_lookup_modules(object).should == [object.singleton_class, Object, Kernel]
78
+ end
79
+
80
+ it "should contain entries for singleton classes of all ancestors for class objects" do
81
+ temporary_class :C
82
+ filtered_lookup_modules(C).should == [C.singleton_class, Object.singleton_class, Class, Module, Object, Kernel]
83
+ end
84
+
85
+ it "should work for immediate objects" do
86
+ filtered_lookup_modules(1).first.should == Fixnum
87
+ end
88
+ end
89
+
90
+ describe "internal instance methods:" do
91
+ def self.target_method(name)
92
+ define_method(:target_method){name}
93
+ end
94
+
95
+ def self.it_should_list_methods_with_visibility(visibility)
96
+ it "should return the list of #{visibility} instance methods defined directly on a class" do
97
+ temporary_class :C
98
+ replace_methods C, visibility => [:one, :two]
99
+ @adapter.send(target_method, C).to_set.should == Set[:one, :two]
100
+ end
101
+
102
+ it "should return the list of #{visibility} instance methods defined directly on a module" do
103
+ temporary_module :M
104
+ replace_methods M, visibility => [:one, :two]
105
+ @adapter.send(target_method, M).to_set.should == Set[:one, :two]
106
+ end
107
+
108
+ it "should return the list of #{visibility} instance methods defined directly on a singleton class" do
109
+ temporary_class :C
110
+ c = C.new
111
+ replace_methods c.singleton_class, visibility => [:one, :two]
112
+ @adapter.send(target_method, c.singleton_class).to_set.should == Set[:one, :two]
113
+ end
114
+
115
+ it "should return the list of #{visibility} instance methods defined directly on a class' singleton class" do
116
+ temporary_class :C
117
+ replace_methods C.singleton_class, visibility => [:one, :two], :class_singleton => true
118
+ @adapter.send(target_method, C.singleton_class).to_set.should == Set[:one, :two]
119
+ end
120
+
121
+ # Worth checking as ruby keeps undef'd methods in method tables.
122
+ it "should not return undefined methods" do
123
+ temporary_class :C
124
+ replace_methods C, visibility => [:removed]
125
+ C.send(:undef_method, :removed)
126
+ @adapter.send(target_method, C).to_set.should == Set[]
127
+ end
128
+ end
129
+
130
+ def self.it_should_not_list_methods_with_visibility(visibility1, visibility2)
131
+ it "should not return any #{visibility1} or #{visibility2} instance methods" do
132
+ temporary_class :C
133
+ replace_methods C, {visibility1 => [:a], visibility2 => [:b]}
134
+ @adapter.send(target_method, C).to_set.should == Set[]
135
+ end
136
+ end
137
+
138
+ describe ".internal_public_instance_methods" do
139
+ target_method :internal_public_instance_methods
140
+ it_should_list_methods_with_visibility :public
141
+ it_should_not_list_methods_with_visibility :private, :protected
142
+ end
143
+
144
+ describe ".internal_protected_instance_methods" do
145
+ target_method :internal_protected_instance_methods
146
+ it_should_list_methods_with_visibility :protected
147
+ it_should_not_list_methods_with_visibility :public, :private
148
+ end
149
+
150
+ describe ".internal_private_instance_methods" do
151
+ target_method :internal_private_instance_methods
152
+ it_should_list_methods_with_visibility :private
153
+ it_should_not_list_methods_with_visibility :public, :protected
154
+ end
155
+
156
+ describe ".internal_undefined_instance_methods" do
157
+ it "should return the list of undefined instance methods directly on a class" do
158
+ temporary_class :C
159
+ C.send(:define_method, :f){}
160
+ C.send(:undef_method, :f)
161
+ @adapter.internal_undefined_instance_methods(C).should == [:f]
162
+ end
163
+
164
+ it "should return the list of undefined instance methods directly on a module" do
165
+ temporary_module :M
166
+ M.send(:define_method, :f){}
167
+ M.send(:undef_method, :f)
168
+ @adapter.internal_undefined_instance_methods(M).should == [:f]
169
+ end
170
+
171
+ it "should return the list of undefined instance methods directly on a singleton class" do
172
+ temporary_class :C
173
+ c = C.new
174
+ c.singleton_class.send(:define_method, :f){}
175
+ c.singleton_class.send(:undef_method, :f)
176
+ @adapter.internal_undefined_instance_methods(c.singleton_class).should == [:f]
177
+ end
178
+
179
+ it "should return the list of undefined instance methods directly on a class' singleton class" do
180
+ temporary_class :C
181
+ C.singleton_class.send(:define_method, :f){}
182
+ C.singleton_class.send(:undef_method, :f)
183
+ @adapter.internal_undefined_instance_methods(C.singleton_class).should == [:f]
184
+ end
185
+
186
+ it "should not return defined methods" do
187
+ temporary_class :C
188
+ C.send(:define_method, :f){}
189
+ @adapter.internal_undefined_instance_methods(C).should == []
190
+ end
191
+
192
+ it "should not return removed methods" do
193
+ temporary_class :C
194
+ C.send(:define_method, :f){}
195
+ C.send(:remove_method, :f)
196
+ @adapter.internal_undefined_instance_methods(C).should == []
197
+ end
198
+ end
199
+ end
200
+
201
+ describe "#singleton_class?" do
202
+ it "should return true if the object is a singleton class of an object" do
203
+ object = (class << Object.new; self; end)
204
+ @adapter.singleton_class?(object).should be_true
205
+ end
206
+
207
+ it "should return true if the object is a singleton class of a class" do
208
+ object = (class << Class.new; self; end)
209
+ @adapter.singleton_class?(object).should be_true
210
+ end
211
+
212
+ it "should return true if the object is a singleton class of a singleton class" do
213
+ object = (class << (class << Class.new; self; end); self; end)
214
+ @adapter.singleton_class?(object).should be_true
215
+ end
216
+
217
+ it "should return false if the object is just a class" do
218
+ object = Class.new
219
+ @adapter.singleton_class?(object).should be_false
220
+ end
221
+
222
+ it "should return false if the object is just a module" do
223
+ object = Module.new
224
+ @adapter.singleton_class?(object).should be_false
225
+ end
226
+
227
+ it "should return false if the object is just an object" do
228
+ object = Object.new
229
+ @adapter.singleton_class?(object).should be_false
230
+ end
231
+
232
+ it "should return false if the object is TrueClass" do
233
+ @adapter.singleton_class?(TrueClass).should be_false
234
+ end
235
+
236
+ it "should return false if the object is FalseClass" do
237
+ @adapter.singleton_class?(FalseClass).should be_false
238
+ end
239
+
240
+ it "should return false if the object is NilClass" do
241
+ @adapter.singleton_class?(NilClass).should be_false
242
+ end
243
+ end
244
+
245
+ describe "singleton_instance" do
246
+ it "should return the instance of the given singleton class" do
247
+ object = Object.new
248
+ @adapter.singleton_instance((class << object; self; end)).should equal(object)
249
+ end
250
+
251
+ it "should return the instance of the given class singleton class" do
252
+ klass = Class.new
253
+ @adapter.singleton_instance((class << klass; self; end)).should equal(klass)
254
+ end
255
+
256
+ it "should return the instance of the given module singleton class" do
257
+ mod = Module.new
258
+ @adapter.singleton_instance((class << mod; self; end)).should equal(mod)
259
+ end
260
+
261
+ it "should raise a TypeError if the given object is just a class" do
262
+ lambda do
263
+ @adapter.singleton_instance(Class.new)
264
+ end.should raise_error(TypeError)
265
+ end
266
+
267
+ it "should raise a TypeError if the given object is just a module" do
268
+ lambda do
269
+ @adapter.singleton_instance(Module.new)
270
+ end.should raise_error(TypeError)
271
+ end
272
+
273
+ it "should raise a TypeError if the given object is just a object" do
274
+ lambda do
275
+ @adapter.singleton_instance(Object.new)
276
+ end.should raise_error(TypeError)
277
+ end
278
+ end
279
+
280
+ describe "#module_name" do
281
+ it "should return the fully-qualified name of the given module" do
282
+ ::M = Module.new
283
+ M::N = Module.new
284
+ begin
285
+ @adapter.module_name(M::N).should == 'M::N'
286
+ ensure
287
+ Object.send :remove_const, :M
288
+ end
289
+ end
290
+
291
+ it "should return the fully-qualified name of the given class" do
292
+ ::M = Module.new
293
+ M::C = Class.new
294
+ begin
295
+ @adapter.module_name(M::C).should == 'M::C'
296
+ ensure
297
+ Object.send :remove_const, :M
298
+ end
299
+ end
300
+
301
+ it "should not be affected by overridding the module's #to_s or #name" do
302
+ begin
303
+ ::M = Module.new
304
+ ::M::C = Class.new do
305
+ def name
306
+ 'overridden'
307
+ end
308
+ def to_s
309
+ 'overridden'
310
+ end
311
+ end
312
+ @adapter.describe_module(M::C).should == 'M::C'
313
+ ensure
314
+ Object.send :remove_const, :M
315
+ end
316
+ end
317
+
318
+ it "should return an empty string for unnamed modules" do
319
+ @adapter.module_name(Module.new).should == ''
320
+ end
321
+
322
+ it "should return an empty string for unnamed classes" do
323
+ @adapter.module_name(Class.new).should == ''
324
+ end
325
+
326
+ it "should return an empty string for singleton classes" do
327
+ object = Object.new
328
+ @adapter.module_name((class << object; self; end)).should == ''
329
+ end
330
+
331
+ it "should raise a TypeError if the argumeent is not a module" do
332
+ lambda do
333
+ @adapter.module_name(Object.new)
334
+ end.should raise_error(TypeError)
335
+ end
336
+ end
337
+
338
+ describe "#describe_module" do
339
+ it "should return the fully-qualified name of a module" do
340
+ begin
341
+ ::M = Module.new
342
+ ::M::N = Module.new
343
+ @adapter.describe_module(::M::N).should == 'M::N'
344
+ ensure
345
+ Object.send :remove_const, :M
346
+ end
347
+ end
348
+
349
+ it "should not be affected by overridding the module's #to_s or #name" do
350
+ begin
351
+ ::M = Module.new
352
+ ::M::C = Class.new do
353
+ def name
354
+ 'overridden'
355
+ end
356
+ def to_s
357
+ 'overridden'
358
+ end
359
+ end
360
+ @adapter.describe_module(::M::C).should == 'M::C'
361
+ ensure
362
+ Object.send :remove_const, :M
363
+ end
364
+ end
365
+
366
+ describe "for an unnamed class" do
367
+ it "should describe the object as 'unnamed Class'" do
368
+ @adapter.describe_module(Class.new).should == 'unnamed Class'
369
+ end
370
+ end
371
+
372
+ describe "for an unnamed module" do
373
+ it "should describe the object as 'unnamed Module'" do
374
+ @adapter.describe_module(Module.new).should == 'unnamed Module'
375
+ end
376
+ end
377
+
378
+ describe "for a singleton class of an object" do
379
+ it "should describe the object in brackets" do
380
+ begin
381
+ ::M = Module.new
382
+ ::M::C = Class.new
383
+ object = M::C.new
384
+ @adapter.describe_module(object.singleton_class).should == '[M::C instance]'
385
+ ensure
386
+ Object.send :remove_const, :M
387
+ end
388
+ end
389
+ end
390
+
391
+ describe "for a singleton class of a named class" do
392
+ it "should return the class name in brackets" do
393
+ begin
394
+ ::M = Module.new
395
+ ::M::C = Class.new
396
+ @adapter.describe_module(M::C.singleton_class).should == '[M::C]'
397
+ ensure
398
+ Object.send :remove_const, :M
399
+ end
400
+ end
401
+ end
402
+
403
+ describe "for a singleton class of an unnamed class" do
404
+ it "should describe the object as '[unnamed Class]'" do
405
+ klass = Class.new
406
+ @adapter.describe_module(klass.singleton_class).should == '[unnamed Class]'
407
+ end
408
+ end
409
+
410
+ describe "for a singleton class of an unnamed module" do
411
+ it "should describe the object as '[unnamed Module]'" do
412
+ mod = Module.new
413
+ @adapter.describe_module(mod.singleton_class).should == '[unnamed Module]'
414
+ end
415
+ end
416
+
417
+ describe "for a singleton class of a singleton class" do
418
+ it "should return the object's class name in two pairs of brackets" do
419
+ begin
420
+ ::M = Module.new
421
+ ::M::C = Class.new
422
+ klass = M::C.singleton_class.singleton_class
423
+ @adapter.describe_module(klass).should == '[[M::C]]'
424
+ ensure
425
+ Object.send :remove_const, :M
426
+ end
427
+ end
428
+ end
429
+ end
430
+
431
+ describe "#source_location" do
432
+ def load_source(source)
433
+ @tmp = "#{ROOT}/spec/tmp"
434
+ @source_path = "#@tmp/c.rb"
435
+ FileUtils.mkdir_p @tmp
436
+ open(@source_path, 'w') { |f| f.print source }
437
+ load @source_path
438
+ @source_path
439
+ end
440
+
441
+ after do
442
+ FileUtils.rm_rf @tmp
443
+ Object.send(:remove_const, :C) if Object.const_defined?(:C)
444
+ end
445
+
446
+ it "should return the file and line number the given method was defined on" do
447
+ path = load_source <<-EOS.demargin
448
+ |class C
449
+ | def f
450
+ | end
451
+ |end
452
+ EOS
453
+ method = C.instance_method(:f)
454
+ @adapter.source_location(method).should == [path, 2]
455
+ end
456
+
457
+ it "should work for methods defined via a block (MRI BMETHOD)" do
458
+ path = load_source <<-EOS.demargin
459
+ |class C
460
+ | define_method :f do
461
+ | end
462
+ |end
463
+ EOS
464
+ method = C.instance_method(:f)
465
+ @adapter.source_location(method).should == [path, 2]
466
+ end
467
+
468
+ it "should work for methods defined via a proc (MRI BMETHOD)" do
469
+ path = load_source <<-EOS.demargin
470
+ |class C
471
+ | f = lambda do
472
+ | end
473
+ | define_method :f, f
474
+ |end
475
+ EOS
476
+ method = C.instance_method(:f)
477
+ @adapter.source_location(method).should == [path, 2]
478
+ end
479
+
480
+ it "should work for methods defined via a UnboundMethod (MRI DMETHOD)" do
481
+ path = load_source <<-EOS.demargin
482
+ |class C
483
+ | def f
484
+ | end
485
+ | define_method :g, instance_method(:f)
486
+ |end
487
+ EOS
488
+ method = C.instance_method(:g)
489
+ @adapter.source_location(method).should == [path, 2]
490
+ end
491
+
492
+ it "should work for methods defined via a BoundMethod (MRI DMETHOD)" do
493
+ path = load_source <<-EOS.demargin
494
+ |class C
495
+ | def f
496
+ | end
497
+ | define_method :g, new.method(:f)
498
+ |end
499
+ EOS
500
+ method = C.instance_method(:g)
501
+ @adapter.source_location(method).should == [path, 2]
502
+ end
503
+
504
+ it "should work for methods whose visibility is overridden in a subclass (MRI ZSUPER)" do
505
+ path = load_source <<-EOS.demargin
506
+ |class C
507
+ | def f
508
+ | end
509
+ |end
510
+ |class D < C
511
+ | private :f
512
+ |end
513
+ EOS
514
+ begin
515
+ method = D.instance_method(:f)
516
+ @adapter.source_location(method).should == [path, 2]
517
+ ensure
518
+ Object.send(:remove_const, :D)
519
+ end
520
+ end
521
+
522
+ it "should work for aliases (MRI FBODY)" do
523
+ path = load_source <<-EOS.demargin
524
+ |class C
525
+ | def f
526
+ | end
527
+ | alias g f
528
+ |end
529
+ EOS
530
+ method = C.instance_method(:g)
531
+ @adapter.source_location(method).should == [path, 2]
532
+ end
533
+
534
+ it "should raise a TypeError if the argument is not an UnboundMethod" do
535
+ path = load_source <<-EOS.demargin
536
+ |class C
537
+ | def f
538
+ | end
539
+ |end
540
+ EOS
541
+ lambda do
542
+ @adapter.source_location(nil)
543
+ end.should raise_error(TypeError)
544
+ end
545
+ end
546
+ end