oggy-looksee 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,54 @@
1
+ =begin
2
+
3
+ Include this to pollute the standard ruby modules with handy aliases.
4
+ Perfect for your .irbrc, or for punching into your program to work out
5
+ what that +flazbot+ variable can do.
6
+
7
+ =end
8
+
9
+ require 'looksee'
10
+
11
+ class Object
12
+ private # ---------------------------------------------------------
13
+
14
+ #
15
+ # Alias for Looksee.lookup_path.
16
+ #
17
+ # (Added by Looksee.)
18
+ #
19
+ def lp(*args)
20
+ Looksee.lookup_path(*args)
21
+ end
22
+
23
+ #
24
+ # Run Looksee.lookup_path on an instance of the given class.
25
+ #
26
+ # (Added by Looksee.)
27
+ #
28
+ def lpi(klass, *args)
29
+ Looksee.lookup_path(klass.allocate, *args)
30
+ end
31
+
32
+ public # ----------------------------------------------------------
33
+
34
+ #
35
+ # Call Looksee.lookup_path on this object.
36
+ #
37
+ # (Added by Looksee.)
38
+ #
39
+ def lookup_path(*args)
40
+ Looksee.lookup_path(self, *args)
41
+ end
42
+
43
+ #
44
+ # Dump the lookup path to standard output, and return self.
45
+ #
46
+ # Good for stuffing in a call chain.
47
+ #
48
+ # (Added by Looksee.)
49
+ #
50
+ def dump_lookup_path(*args)
51
+ p lookup_path(*args)
52
+ self
53
+ end
54
+ end
@@ -0,0 +1,3 @@
1
+ module Looksee
2
+ VERSION = '0.0.1'
3
+ end
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/looksee.rb'}"
9
+ puts "Loading looksee gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,374 @@
1
+ require 'spec_helper'
2
+
3
+ describe Looksee do
4
+ include TemporaryClasses
5
+
6
+ describe ".lookup_modules" do
7
+ #
8
+ # Wrapper for the method under test.
9
+ #
10
+ # Filter out modules which are hard to test against, and returns
11
+ # the list of module names. #inspect strings are used for names
12
+ # of singleton classes, since they have no name.
13
+ #
14
+ def filtered_lookup_modules(object)
15
+ result = Looksee.lookup_modules(object)
16
+ # Singleton classes have no name ('' in <1.9, nil in 1.9+). Use
17
+ # the inspect string instead.
18
+ names = result.map{|mod| mod.name.to_s.empty? ? mod.inspect : mod.name}
19
+ names.select{|name| deterministic_module_name?(name)}
20
+ end
21
+
22
+ #
23
+ # Return true if the given module name is of a module we can test
24
+ # for.
25
+ #
26
+ # This excludes ruby version dependent modules, and modules tossed
27
+ # into the hierarchy by testing frameworks.
28
+ #
29
+ def deterministic_module_name?(name)
30
+ junk_patterns = [
31
+ # pollution from testing libraries
32
+ 'Mocha', 'Spec',
33
+ # RSpec adds this under ruby 1.8.6
34
+ 'InstanceExecHelper',
35
+ # only in ruby 1.9
36
+ 'BasicObject',
37
+ # something pulls this in under ruby 1.9
38
+ 'PP',
39
+ ]
40
+
41
+ # Singleton classes of junk are junk.
42
+ while name =~ /\A#<Class:(.*)>\z/
43
+ name = $1
44
+ end
45
+
46
+ name !~ /\A(#{junk_patterns.join('|')})/
47
+ end
48
+
49
+ it "should contain an entry for each module in the object's lookup path" do
50
+ temporary_module :Mod1
51
+ temporary_module :Mod2
52
+ temporary_class :Base
53
+ temporary_class :Derived, Base do
54
+ include Mod1
55
+ include Mod2
56
+ end
57
+ filtered_lookup_modules(Derived.new) == %w'Derived Mod2 Mod1 Base Object Kernel'
58
+ end
59
+
60
+ it "contain an entry for the object's singleton class if it exists" do
61
+ object = Object.new
62
+ object.singleton_class
63
+
64
+ result = filtered_lookup_modules(object)
65
+ result.shift.should =~ /\A#<Class:\#<Object:0x[\da-f]+>>\z/
66
+ result.should == %w"Object Kernel"
67
+ end
68
+
69
+ it "should contain entries for singleton classes of all ancestors for class objects" do
70
+ temporary_class :C
71
+ result = filtered_lookup_modules(C)
72
+ result.should == %w'#<Class:C> #<Class:Object> Class Module Object Kernel'
73
+ end
74
+ end
75
+
76
+ describe ".lookup_path" do
77
+ it "should return a LookupPath object" do
78
+ object = Object.new
79
+ lookup_path = Looksee.lookup_path(object)
80
+ lookup_path.should be_a(Looksee::LookupPath)
81
+ end
82
+
83
+ it "should return a LookupPath object for the given object" do
84
+ object = Object.new
85
+ Looksee.stubs(:default_lookup_path_options).returns({})
86
+ Looksee::LookupPath.expects(:new).with(object, {})
87
+ lookup_path = Looksee.lookup_path(object)
88
+ end
89
+
90
+ it "should allow symbol arguments as shortcuts for true options" do
91
+ object = Object.new
92
+ Looksee.stubs(:default_lookup_path_options).returns({})
93
+ Looksee::LookupPath.expects(:new).with(object, {:public => true, :overridden => true})
94
+ Looksee.lookup_path(object, :public, :overridden)
95
+ end
96
+
97
+ it "should merge the default options, with the symbols, and the options hash" do
98
+ object = Object.new
99
+ Looksee.stubs(:default_lookup_path_options).returns({:public => false, :protected => false, :private => false})
100
+ Looksee::LookupPath.expects(:new).with(object, {:public => false, :protected => true, :private => false})
101
+ Looksee.lookup_path(object, :protected, :private, :private => false)
102
+ end
103
+ end
104
+
105
+ describe "internal instance methods:" do
106
+ #
107
+ # Remove all methods defined exactly on the given module. As Ruby's
108
+ # reflection on singleton classes of classes isn't quite adequate,
109
+ # you need to provide a :class_singleton option when such a class is
110
+ # given.
111
+ #
112
+ def remove_methods(mod, opts={})
113
+ names = all_instance_methods(mod)
114
+
115
+ # all_instance_methods can't get just the methods on a class
116
+ # singleton class. Filter out superclass methods here.
117
+ if opts[:class_singleton]
118
+ klass = ObjectSpace.each_object(mod){|klass| break klass}
119
+ names -= all_instance_methods(klass.superclass.singleton_class)
120
+ end
121
+
122
+ names.sort_by{|name| name.in?([:remove_method, :send]) ? 1 : 0}.flatten
123
+ names.each do |name|
124
+ mod.send :remove_method, name
125
+ end
126
+ end
127
+
128
+ def define_methods(mod, opts)
129
+ mod.module_eval do
130
+ [:public, :protected, :private].each do |visibility|
131
+ Array(opts[visibility]).each do |name|
132
+ define_method(name){}
133
+ send visibility, name
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ def all_instance_methods(mod)
140
+ names =
141
+ mod.public_instance_methods(false) +
142
+ mod.protected_instance_methods(false) +
143
+ mod.private_instance_methods(false)
144
+ names.map{|name| name.to_sym} # they're strings in ruby <1.9
145
+ end
146
+
147
+ def self.target_method(name)
148
+ define_method(:target_method){name}
149
+ end
150
+
151
+ def self.it_should_list_methods_with_visibility(visibility)
152
+ it "should return the list of #{visibility} instance methods defined directly on a class" do
153
+ temporary_class :C
154
+ remove_methods C
155
+ define_methods C, visibility => [:one, :two]
156
+ Looksee.send(target_method, C).to_set.should == Set[:one, :two]
157
+ end
158
+
159
+ it "should return the list of #{visibility} instance methods defined directly on a module" do
160
+ temporary_module :M
161
+ remove_methods M
162
+ define_methods M, visibility => [:one, :two]
163
+ Looksee.send(target_method, M).to_set.should == Set[:one, :two]
164
+ end
165
+
166
+ it "should return the list of #{visibility} instance methods defined directly on a singleton class" do
167
+ temporary_class :C
168
+ c = C.new
169
+ remove_methods c.singleton_class
170
+ define_methods c.singleton_class, visibility => [:one, :two]
171
+ Looksee.send(target_method, c.singleton_class).to_set.should == Set[:one, :two]
172
+ end
173
+
174
+ it "should return the list of #{visibility} instance methods defined directly on a class' singleton class" do
175
+ temporary_class :C
176
+ remove_methods C.singleton_class, :class_singleton => true
177
+ define_methods C.singleton_class, visibility => [:one, :two]
178
+ Looksee.send(target_method, C.singleton_class).to_set.should == Set[:one, :two]
179
+ end
180
+
181
+ # Worth checking as ruby keeps undef'd methods in method tables.
182
+ it "should not return undefined methods" do
183
+ temporary_class :C
184
+ remove_methods C
185
+ define_methods C, visibility => [:removed]
186
+ C.send(:undef_method, :removed)
187
+ Looksee.send(target_method, C).to_set.should == Set[]
188
+ end
189
+ end
190
+
191
+ def self.it_should_not_list_methods_with_visibility(visibility1, visibility2)
192
+ it "should not return any #{visibility1} or #{visibility2} instance methods" do
193
+ temporary_class :C
194
+ remove_methods C
195
+ define_methods C, {visibility1 => [:a], visibility2 => [:b]}
196
+ Looksee.send(target_method, C).to_set.should == Set[]
197
+ end
198
+ end
199
+
200
+ describe ".internal_public_instance_methods" do
201
+ target_method :internal_public_instance_methods
202
+ it_should_list_methods_with_visibility :public
203
+ it_should_not_list_methods_with_visibility :private, :protected
204
+ end
205
+
206
+ describe ".internal_protected_instance_methods" do
207
+ target_method :internal_protected_instance_methods
208
+ it_should_list_methods_with_visibility :protected
209
+ it_should_not_list_methods_with_visibility :public, :private
210
+ end
211
+
212
+ describe ".internal_private_instance_methods" do
213
+ target_method :internal_private_instance_methods
214
+ it_should_list_methods_with_visibility :private
215
+ it_should_not_list_methods_with_visibility :public, :protected
216
+ end
217
+ end
218
+ end
219
+
220
+ describe Looksee::LookupPath do
221
+ before do
222
+ Looksee.default_lookup_path_options = {}
223
+ end
224
+
225
+ include TemporaryClasses
226
+
227
+ describe "#entries" do
228
+ it "should contain an entry for each module in the object's lookup path" do
229
+ object = Object.new
230
+ temporary_class :C
231
+ temporary_class :D
232
+ Looksee.stubs(:lookup_modules).with(object).returns([C, D])
233
+ Looksee::LookupPath.new(object).entries.map{|entry| entry.module_name}.should == %w'C D'
234
+ end
235
+ end
236
+
237
+ describe "#inspect" do
238
+ before do
239
+ Looksee.stubs(:styles).returns(Hash.new{'%s'})
240
+ end
241
+
242
+ def stub_methods(mod, public, protected, private)
243
+ Looksee.stubs(:internal_public_instance_methods ).with(mod).returns(public)
244
+ Looksee.stubs(:internal_protected_instance_methods).with(mod).returns(protected)
245
+ Looksee.stubs(:internal_private_instance_methods ).with(mod).returns(private)
246
+ end
247
+
248
+ describe "contents" do
249
+ before do
250
+ temporary_module :M
251
+ temporary_class :C do
252
+ include M
253
+ end
254
+ @object = Object.new
255
+ Looksee.stubs(:lookup_modules).with(@object).returns([C, M])
256
+ stub_methods(C, ['public1', 'public2'], ['protected1', 'protected2'], ['private1', 'private2'])
257
+ stub_methods(M, ['public1', 'public2'], ['protected1', 'protected2'], ['private1', 'private2'])
258
+ end
259
+
260
+ it "should show only public instance methods when only public methods are requested" do
261
+ lookup_path = Looksee::LookupPath.new(@object, :public => true, :overridden => true)
262
+ lookup_path.inspect.should == <<-EOS.demargin
263
+ |C
264
+ | public1 public2
265
+ |M
266
+ | public1 public2
267
+ EOS
268
+ end
269
+
270
+ it "should show modules and protected instance methods when only protected methods are requested" do
271
+ lookup_path = Looksee::LookupPath.new(@object, :protected => true, :overridden => true)
272
+ lookup_path.inspect.should == <<-EOS.demargin
273
+ |C
274
+ | protected1 protected2
275
+ |M
276
+ | protected1 protected2
277
+ EOS
278
+ end
279
+
280
+ it "should show modules and private instance methods when only private methods are requested" do
281
+ lookup_path = Looksee::LookupPath.new(@object, :private => true, :overridden => true)
282
+ lookup_path.inspect.should == <<-EOS.demargin
283
+ |C
284
+ | private1 private2
285
+ |M
286
+ | private1 private2
287
+ EOS
288
+ end
289
+
290
+ it "should show modules with public and private instance methods when only public and private methods are requested" do
291
+ lookup_path = Looksee::LookupPath.new(@object, :public => true, :private => true, :overridden => true)
292
+ lookup_path.inspect.should == <<-EOS.demargin
293
+ |C
294
+ | private1 private2 public1 public2
295
+ |M
296
+ | private1 private2 public1 public2
297
+ EOS
298
+ end
299
+
300
+ it "should show singleton classes as class names in brackets" do
301
+ Looksee.stubs(:lookup_modules).with(C).returns([C.singleton_class])
302
+ stub_methods(C.singleton_class, ['public1', 'public2'], [], [])
303
+ lookup_path = Looksee::LookupPath.new(C, :public => true)
304
+ lookup_path.inspect.should == <<-EOS.demargin
305
+ |[C]
306
+ | public1 public2
307
+ EOS
308
+ end
309
+
310
+ it "should handle singleton classes of singleton classes correctly" do
311
+ Looksee.stubs(:lookup_modules).with(C.singleton_class).returns([C.singleton_class.singleton_class])
312
+ stub_methods(C.singleton_class.singleton_class, ['public1', 'public2'], [], [])
313
+ lookup_path = Looksee::LookupPath.new(C.singleton_class, :public => true)
314
+ lookup_path.inspect.should == <<-EOS.demargin
315
+ |[[C]]
316
+ | public1 public2
317
+ EOS
318
+ end
319
+ end
320
+
321
+ describe "styles" do
322
+ before do
323
+ styles = {
324
+ :module => "`%s'",
325
+ :public => "{%s}",
326
+ :protected => "[%s]",
327
+ :private => "<%s>",
328
+ :overridden => "(%s)",
329
+ }
330
+ Looksee.stubs(:styles).returns(styles)
331
+ end
332
+
333
+ it "should delimit each word with the configured delimiters" do
334
+ temporary_class :C
335
+ Looksee.stubs(:lookup_modules).returns([C])
336
+ stub_methods(C, ['public'], ['protected'], ['private'])
337
+ lookup_path = Looksee::LookupPath.new(Object.new, :public => true, :protected => true, :private => true, :overridden => true)
338
+ lookup_path.inspect.should == <<-EOS.demargin
339
+ |\`C\'
340
+ | <private> [protected] {public}
341
+ EOS
342
+ end
343
+ end
344
+
345
+ describe "layout" do
346
+ it "should wrap method lists at the configured number of columns, sorting vertically first, and aligning into a grid" do
347
+ temporary_class :C
348
+ Looksee.stubs(:lookup_modules).returns([C])
349
+ stub_methods(C, %w'aa b c dd ee f g hh i', [], [])
350
+ lookup_path = Looksee::LookupPath.new(Object.new, :public => true)
351
+ lookup_path.inspect(:width => 20).should == <<-EOS.demargin
352
+ |C
353
+ | aa c ee g i
354
+ | b dd f hh
355
+ EOS
356
+ end
357
+
358
+ it "should lay the methods of each module out independently" do
359
+ temporary_class :A
360
+ temporary_class :B
361
+ Looksee.stubs(:lookup_modules).returns([A, B])
362
+ stub_methods(A, ['a', 'long_long_long_long_name'], [], [])
363
+ stub_methods(B, ['long_long_long', 'short'], [], [])
364
+ lookup_path = Looksee::LookupPath.new(Object.new, :public => true)
365
+ lookup_path.inspect.should == <<-EOS.demargin
366
+ |A
367
+ | a long_long_long_long_name
368
+ |B
369
+ | long_long_long short
370
+ EOS
371
+ end
372
+ end
373
+ end
374
+ end