looksee 0.0.1 → 0.0.2

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.
@@ -1,3 +1,10 @@
1
+ == 0.0.2 2009-07-28
2
+
3
+ * Added #grep to filter methods shown: lp(object).grep(/pattern/)
4
+ * Fix #1: Play nice with Wirble.
5
+ * Fix #3: Don't die when examining immediate objects (fixnum, symbol,
6
+ true, false, nil)
7
+
1
8
  == 0.0.1 2009-07-05
2
9
 
3
10
  * Hi.
@@ -9,10 +9,13 @@ ext/looksee/node-1.9.h
9
9
  lib/looksee.rb
10
10
  lib/looksee/shortcuts.rb
11
11
  lib/looksee/version.rb
12
+ lib/looksee/wirble_compatibility.rb
13
+ looksee.gemspec
12
14
  script/console
13
15
  script/destroy
14
16
  script/generate
15
17
  spec/looksee_spec.rb
16
18
  spec/spec_helper.rb
19
+ spec/wirble_compatibility_spec.rb
17
20
  tasks/extconf.rake
18
21
  tasks/extconf/looksee.rake
data/Rakefile CHANGED
@@ -6,12 +6,11 @@ require 'fileutils'
6
6
  require './lib/looksee/version'
7
7
 
8
8
  Hoe.plugin :newgem
9
- Hoe.plugin :cucumberfeatures
9
+ Hoe.plugin :email # from seattlerb - configure via ~/.hoerc
10
10
 
11
11
  $hoe = Hoe.spec 'looksee' do
12
12
  self.developer 'George Ogata', 'george.ogata@gmail.com'
13
13
  self.rubyforge_name = self.name # TODO this is default value
14
- self.description_sections = %w'description synopsis'
15
14
  # self.extra_deps = [['activesupport','>= 2.0.2']]
16
15
  self.extra_dev_deps = [
17
16
  ['newgem', ">= #{::Newgem::VERSION}"],
@@ -36,7 +36,7 @@ VALUE Looksee_internal_superclass(VALUE self, VALUE internal_class) {
36
36
  * object's birth class.
37
37
  */
38
38
  VALUE Looksee_internal_class(VALUE self, VALUE object) {
39
- return RBASIC(object)->klass;
39
+ return CLASS_OF(object);
40
40
  }
41
41
 
42
42
  /*
@@ -77,7 +77,7 @@ module Looksee
77
77
  normalized_options[option] = true
78
78
  end
79
79
  normalized_options.update(hash_options)
80
- LookupPath.new(object, normalized_options)
80
+ LookupPath.for(object, normalized_options)
81
81
  end
82
82
 
83
83
  #
@@ -149,6 +149,10 @@ module Looksee
149
149
  class LookupPath
150
150
  attr_reader :entries
151
151
 
152
+ def initialize(entries)
153
+ @entries = entries
154
+ end
155
+
152
156
  #
153
157
  # Create a LookupPath for the given object.
154
158
  #
@@ -160,23 +164,38 @@ module Looksee
160
164
  # :private
161
165
  # :overridden
162
166
  #
163
- def initialize(object, options={})
164
- @entries = []
165
- seen = {}
166
- Looksee.lookup_modules(object).each do |mod|
167
- entry = Entry.new(mod, seen, options)
168
- entry.methods.each{|m| seen[m] = true}
169
- @entries << entry
167
+ def self.for(object, options={})
168
+ entries = entries_for(object, options)
169
+ new(entries)
170
+ end
171
+
172
+ #
173
+ # Return a new LookupPath which only contains names matching the
174
+ # given pattern.
175
+ #
176
+ def grep(pattern)
177
+ entries = self.entries.map do |entry|
178
+ entry.grep(pattern)
170
179
  end
180
+ self.class.new(entries)
171
181
  end
172
182
 
173
183
  def inspect(options={})
174
184
  options = normalize_inspect_options(options)
175
- entries.map{|e| e.inspect(options)}.join
185
+ entries.map{|e| e.inspect(options)}.join("\n")
176
186
  end
177
187
 
178
188
  private # -------------------------------------------------------
179
189
 
190
+ def self.entries_for(object, options)
191
+ seen = {}
192
+ Looksee.lookup_modules(object).map do |mod|
193
+ entry = Entry.for(mod, seen, options)
194
+ entry.methods.each{|m| seen[m] = true}
195
+ entry
196
+ end
197
+ end
198
+
180
199
  def normalize_inspect_options(options)
181
200
  options[:width] ||= ENV['COLUMNS'].to_i.nonzero? || Looksee.default_width
182
201
  options
@@ -189,21 +208,39 @@ module Looksee
189
208
  # information (public, private, etc.).
190
209
  #
191
210
  class Entry
192
- #
193
- # Don't call me, silly. I'm just part of a LookupPath.
194
- #
195
- def initialize(mod, seen, options)
211
+ def initialize(mod, methods=[], visibilities={})
196
212
  @module = mod
197
- @methods = []
198
- @visibilities = {}
199
- add_methods(Looksee.internal_public_instance_methods(mod).map{|sym| sym.to_s} , :public , seen) if options[:public ]
200
- add_methods(Looksee.internal_protected_instance_methods(mod).map{|sym| sym.to_s}, :protected, seen) if options[:protected]
201
- add_methods(Looksee.internal_private_instance_methods(mod).map{|sym| sym.to_s} , :private , seen) if options[:private ]
202
- @methods.sort!
213
+ @methods = methods
214
+ @visibilities = visibilities
215
+ end
216
+
217
+ def self.for(mod, seen, options)
218
+ entry = new(mod)
219
+ entry.initialize_for(seen, options)
220
+ entry
203
221
  end
204
222
 
205
223
  attr_reader :module, :methods
206
224
 
225
+ def initialize_for(seen, options)
226
+ add_methods(Looksee.internal_public_instance_methods(@module).map{|sym| sym.to_s} , :public , seen) if options[:public ]
227
+ add_methods(Looksee.internal_protected_instance_methods(@module).map{|sym| sym.to_s}, :protected, seen) if options[:protected]
228
+ add_methods(Looksee.internal_private_instance_methods(@module).map{|sym| sym.to_s} , :private , seen) if options[:private ]
229
+ @methods.sort!
230
+ end
231
+
232
+ def grep(pattern)
233
+ methods = []
234
+ visibilities = {}
235
+ @methods.each do |name|
236
+ if name[pattern]
237
+ methods << name
238
+ visibilities[name] = @visibilities[name]
239
+ end
240
+ end
241
+ self.class.new(@module, methods, visibilities)
242
+ end
243
+
207
244
  #
208
245
  # Return the name of the class or module.
209
246
  #
@@ -236,7 +273,8 @@ module Looksee
236
273
  # columns. Pass a :width option to control the output width.
237
274
  #
238
275
  def inspect(options={})
239
- styled_module_name << "\n" << Columnizer.columnize(styled_methods, options[:width])
276
+ string = styled_module_name << "\n" << Columnizer.columnize(styled_methods, options[:width])
277
+ string.chomp
240
278
  end
241
279
 
242
280
  private # -----------------------------------------------------
@@ -268,6 +306,8 @@ module Looksee
268
306
  # sequences.
269
307
  #
270
308
  def columnize(strings, width)
309
+ return '' if strings.empty?
310
+
271
311
  num_columns = 1
272
312
  layout = [strings]
273
313
  loop do
@@ -330,3 +370,5 @@ module Looksee
330
370
  end
331
371
  end
332
372
  end
373
+
374
+ require 'looksee/wirble_compatibility'
@@ -1,3 +1,3 @@
1
1
  module Looksee
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  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
+ IRB::Irb.method_defined?(:non_color_output_value)
12
+ end
13
+
14
+ def hook_into_wirble_load
15
+ unless Object.const_defined?(:Wirble)
16
+ Object.const_set :Wirble, Module.new
17
+ end
18
+ Wirble.send :extend, WirbleLoadHook
19
+ end
20
+
21
+ def hook_into_wirble_colorize
22
+ class << Wirble
23
+ def colorize_with_looksee(*args)
24
+ # If this gets called twice, Wirble will fuck up the
25
+ # aliases. Disable colorizing first to reset them.
26
+ if WirbleCompatibility.hooked_into_irb_output_value?
27
+ Wirble::Colorize.disable
28
+ end
29
+ colorize_without_looksee(*args)
30
+ WirbleCompatibility.hook_into_irb_output_value
31
+ end
32
+
33
+ alias colorize_without_looksee colorize
34
+ alias colorize colorize_with_looksee
35
+ end
36
+ end
37
+
38
+ def hook_into_irb_output_value
39
+ IRB::Irb.class_eval do
40
+ def output_value_with_looksee
41
+ if @context.last_value.is_a?(Looksee::LookupPath)
42
+ non_color_output_value
43
+ else
44
+ output_value_without_looksee
45
+ end
46
+ end
47
+
48
+ alias output_value_without_looksee output_value
49
+ alias output_value output_value_with_looksee
50
+ end
51
+ end
52
+
53
+ def hooked_into_irb_output_value?
54
+ IRB::Irb.method_defined?(:output_value_with_looksee)
55
+ end
56
+
57
+ def init
58
+ #
59
+ # How wirble is used:
60
+ #
61
+ # * Wirble is required/loaded. Defines Wirble module, with methods like Wirble.colorize.
62
+ # * Wirble.init is called. Nothing interesting.
63
+ # * Wirble.colorize is called. Hooks into IRB::Irb.output_value via an alias.
64
+ #
65
+ if !wirble_loaded?
66
+ hook_into_wirble_load
67
+ elsif !wirble_colorizing?
68
+ hook_into_wirble_colorize
69
+ else
70
+ hook_into_irb_output_value
71
+ end
72
+ end
73
+ end
74
+
75
+ module WirbleLoadHook
76
+ def singleton_method_added(name)
77
+ if name == :colorize && !respond_to?(:colorize_with_looksee)
78
+ WirbleCompatibility.hook_into_wirble_colorize
79
+ end
80
+ super
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ Looksee::WirbleCompatibility.init
@@ -0,0 +1,44 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{looksee}
5
+ s.version = "0.0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["George Ogata"]
9
+ s.date = %q{2009-07-05}
10
+ s.description = %q{Looksee lets you examine the method lookup path of objects in ways not
11
+ possible in plain ruby.}
12
+ s.email = ["george.ogata@gmail.com"]
13
+ s.extensions = ["ext/looksee/extconf.rb"]
14
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt"]
15
+ s.files = [".autotest", "History.txt", "Manifest.txt", "README.rdoc", "Rakefile", "ext/looksee/extconf.rb", "ext/looksee/looksee.c", "ext/looksee/node-1.9.h", "lib/looksee.rb", "lib/looksee/shortcuts.rb", "lib/looksee/version.rb", "script/console", "script/destroy", "script/generate", "spec/looksee_spec.rb", "spec/spec_helper.rb", "tasks/extconf.rake", "tasks/extconf/looksee.rake"]
16
+ s.homepage = %q{http://github.com/oggy/looksee}
17
+ s.rdoc_options = ["--main", "README.rdoc"]
18
+ s.require_paths = ["lib", "ext/looksee"]
19
+ s.rubyforge_project = %q{looksee}
20
+ s.rubygems_version = %q{1.3.4}
21
+ s.summary = %q{Looksee lets you examine the method lookup path of objects in ways not possible in plain ruby.}
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 3
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ s.add_development_dependency(%q<newgem>, [">= 1.5.1"])
29
+ s.add_development_dependency(%q<rspec>, [">= 1.2.7"])
30
+ s.add_development_dependency(%q<mocha>, [">= 0.9.5"])
31
+ s.add_development_dependency(%q<hoe>, [">= 2.3.2"])
32
+ else
33
+ s.add_dependency(%q<newgem>, [">= 1.5.1"])
34
+ s.add_dependency(%q<rspec>, [">= 1.2.7"])
35
+ s.add_dependency(%q<mocha>, [">= 0.9.5"])
36
+ s.add_dependency(%q<hoe>, [">= 2.3.2"])
37
+ end
38
+ else
39
+ s.add_dependency(%q<newgem>, [">= 1.5.1"])
40
+ s.add_dependency(%q<rspec>, [">= 1.2.7"])
41
+ s.add_dependency(%q<mocha>, [">= 0.9.5"])
42
+ s.add_dependency(%q<hoe>, [">= 2.3.2"])
43
+ end
44
+ end
@@ -50,7 +50,7 @@ describe Looksee do
50
50
  temporary_module :Mod1
51
51
  temporary_module :Mod2
52
52
  temporary_class :Base
53
- temporary_class :Derived, Base do
53
+ temporary_class :Derived, :superclass => Base do
54
54
  include Mod1
55
55
  include Mod2
56
56
  end
@@ -71,6 +71,10 @@ describe Looksee do
71
71
  result = filtered_lookup_modules(C)
72
72
  result.should == %w'#<Class:C> #<Class:Object> Class Module Object Kernel'
73
73
  end
74
+
75
+ it "should work for immediate objects" do
76
+ filtered_lookup_modules(1).first.should == 'Fixnum'
77
+ end
74
78
  end
75
79
 
76
80
  describe ".lookup_path" do
@@ -83,67 +87,26 @@ describe Looksee do
83
87
  it "should return a LookupPath object for the given object" do
84
88
  object = Object.new
85
89
  Looksee.stubs(:default_lookup_path_options).returns({})
86
- Looksee::LookupPath.expects(:new).with(object, {})
90
+ Looksee::LookupPath.expects(:for).with(object, {})
87
91
  lookup_path = Looksee.lookup_path(object)
88
92
  end
89
93
 
90
94
  it "should allow symbol arguments as shortcuts for true options" do
91
95
  object = Object.new
92
96
  Looksee.stubs(:default_lookup_path_options).returns({})
93
- Looksee::LookupPath.expects(:new).with(object, {:public => true, :overridden => true})
97
+ Looksee::LookupPath.expects(:for).with(object, {:public => true, :overridden => true})
94
98
  Looksee.lookup_path(object, :public, :overridden)
95
99
  end
96
100
 
97
101
  it "should merge the default options, with the symbols, and the options hash" do
98
102
  object = Object.new
99
103
  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})
104
+ Looksee::LookupPath.expects(:for).with(object, {:public => false, :protected => true, :private => false})
101
105
  Looksee.lookup_path(object, :protected, :private, :private => false)
102
106
  end
103
107
  end
104
108
 
105
109
  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
110
  def self.target_method(name)
148
111
  define_method(:target_method){name}
149
112
  end
@@ -151,38 +114,33 @@ describe Looksee do
151
114
  def self.it_should_list_methods_with_visibility(visibility)
152
115
  it "should return the list of #{visibility} instance methods defined directly on a class" do
153
116
  temporary_class :C
154
- remove_methods C
155
- define_methods C, visibility => [:one, :two]
117
+ replace_methods C, visibility => [:one, :two]
156
118
  Looksee.send(target_method, C).to_set.should == Set[:one, :two]
157
119
  end
158
120
 
159
121
  it "should return the list of #{visibility} instance methods defined directly on a module" do
160
122
  temporary_module :M
161
- remove_methods M
162
- define_methods M, visibility => [:one, :two]
123
+ replace_methods M, visibility => [:one, :two]
163
124
  Looksee.send(target_method, M).to_set.should == Set[:one, :two]
164
125
  end
165
126
 
166
127
  it "should return the list of #{visibility} instance methods defined directly on a singleton class" do
167
128
  temporary_class :C
168
129
  c = C.new
169
- remove_methods c.singleton_class
170
- define_methods c.singleton_class, visibility => [:one, :two]
130
+ replace_methods c.singleton_class, visibility => [:one, :two]
171
131
  Looksee.send(target_method, c.singleton_class).to_set.should == Set[:one, :two]
172
132
  end
173
133
 
174
134
  it "should return the list of #{visibility} instance methods defined directly on a class' singleton class" do
175
135
  temporary_class :C
176
- remove_methods C.singleton_class, :class_singleton => true
177
- define_methods C.singleton_class, visibility => [:one, :two]
136
+ replace_methods C.singleton_class, visibility => [:one, :two], :class_singleton => true
178
137
  Looksee.send(target_method, C.singleton_class).to_set.should == Set[:one, :two]
179
138
  end
180
139
 
181
140
  # Worth checking as ruby keeps undef'd methods in method tables.
182
141
  it "should not return undefined methods" do
183
142
  temporary_class :C
184
- remove_methods C
185
- define_methods C, visibility => [:removed]
143
+ replace_methods C, visibility => [:removed]
186
144
  C.send(:undef_method, :removed)
187
145
  Looksee.send(target_method, C).to_set.should == Set[]
188
146
  end
@@ -191,8 +149,7 @@ describe Looksee do
191
149
  def self.it_should_not_list_methods_with_visibility(visibility1, visibility2)
192
150
  it "should not return any #{visibility1} or #{visibility2} instance methods" do
193
151
  temporary_class :C
194
- remove_methods C
195
- define_methods C, {visibility1 => [:a], visibility2 => [:b]}
152
+ replace_methods C, {visibility1 => [:a], visibility2 => [:b]}
196
153
  Looksee.send(target_method, C).to_set.should == Set[]
197
154
  end
198
155
  end
@@ -218,31 +175,59 @@ describe Looksee do
218
175
  end
219
176
 
220
177
  describe Looksee::LookupPath do
221
- before do
222
- Looksee.default_lookup_path_options = {}
223
- end
224
-
225
178
  include TemporaryClasses
226
179
 
180
+ def stub_methods(mod, public, protected, private)
181
+ Looksee.stubs(:internal_public_instance_methods ).with(mod).returns(public)
182
+ Looksee.stubs(:internal_protected_instance_methods).with(mod).returns(protected)
183
+ Looksee.stubs(:internal_private_instance_methods ).with(mod).returns(private)
184
+ end
185
+
227
186
  describe "#entries" do
228
187
  it "should contain an entry for each module in the object's lookup path" do
229
188
  object = Object.new
230
189
  temporary_class :C
231
190
  temporary_class :D
232
191
  Looksee.stubs(:lookup_modules).with(object).returns([C, D])
233
- Looksee::LookupPath.new(object).entries.map{|entry| entry.module_name}.should == %w'C D'
192
+ Looksee::LookupPath.for(object).entries.map{|entry| entry.module_name}.should == %w'C D'
193
+ end
194
+ end
195
+
196
+ describe "grep" do
197
+ it "should only include methods matching the given regexp" do
198
+ temporary_class :C
199
+ temporary_class :D
200
+ stub_methods(C, ['axbyc', 'xy'], [], [])
201
+ stub_methods(D, ['axbyc', 'xdy'], [], [])
202
+ object = Object.new
203
+ Looksee.stubs(:lookup_modules).with(object).returns([C, D])
204
+ lookup_path = Looksee::LookupPath.for(object, :public => true, :overridden => true).grep(/x.y/)
205
+ lookup_path.entries.map{|entry| entry.module_name}.should == %w'C D'
206
+ lookup_path.entries[0].methods.to_set.should == Set['axbyc']
207
+ lookup_path.entries[1].methods.to_set.should == Set['axbyc', 'xdy']
208
+ end
209
+
210
+ it "should only include methods including the given string" do
211
+ temporary_class :C
212
+ temporary_class :D
213
+ stub_methods(C, ['axxa', 'axa'], [], [])
214
+ stub_methods(D, ['bxxb', 'axxa'], [], [])
215
+ object = Object.new
216
+ Looksee.stubs(:lookup_modules).with(object).returns([C, D])
217
+ lookup_path = Looksee::LookupPath.for(object, :public => true, :overridden => true).grep('xx')
218
+ lookup_path.entries.map{|entry| entry.module_name}.should == %w'C D'
219
+ lookup_path.entries[0].methods.to_set.should == Set['axxa']
220
+ lookup_path.entries[1].methods.to_set.should == Set['axxa', 'bxxb']
234
221
  end
235
222
  end
236
223
 
237
224
  describe "#inspect" do
238
225
  before do
239
- Looksee.stubs(:styles).returns(Hash.new{'%s'})
226
+ Looksee.stubs(:default_lookup_path_options).returns({})
240
227
  end
241
228
 
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)
229
+ before do
230
+ Looksee.stubs(:styles).returns(Hash.new{'%s'})
246
231
  end
247
232
 
248
233
  describe "contents" do
@@ -258,8 +243,8 @@ describe Looksee::LookupPath do
258
243
  end
259
244
 
260
245
  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
246
+ lookup_path = Looksee::LookupPath.for(@object, :public => true, :overridden => true)
247
+ lookup_path.inspect.should == <<-EOS.demargin.chomp
263
248
  |C
264
249
  | public1 public2
265
250
  |M
@@ -268,8 +253,8 @@ describe Looksee::LookupPath do
268
253
  end
269
254
 
270
255
  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
256
+ lookup_path = Looksee::LookupPath.for(@object, :protected => true, :overridden => true)
257
+ lookup_path.inspect.should == <<-EOS.demargin.chomp
273
258
  |C
274
259
  | protected1 protected2
275
260
  |M
@@ -278,8 +263,8 @@ describe Looksee::LookupPath do
278
263
  end
279
264
 
280
265
  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
266
+ lookup_path = Looksee::LookupPath.for(@object, :private => true, :overridden => true)
267
+ lookup_path.inspect.should == <<-EOS.demargin.chomp
283
268
  |C
284
269
  | private1 private2
285
270
  |M
@@ -288,8 +273,8 @@ describe Looksee::LookupPath do
288
273
  end
289
274
 
290
275
  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
276
+ lookup_path = Looksee::LookupPath.for(@object, :public => true, :private => true, :overridden => true)
277
+ lookup_path.inspect.should == <<-EOS.demargin.chomp
293
278
  |C
294
279
  | private1 private2 public1 public2
295
280
  |M
@@ -300,8 +285,8 @@ describe Looksee::LookupPath do
300
285
  it "should show singleton classes as class names in brackets" do
301
286
  Looksee.stubs(:lookup_modules).with(C).returns([C.singleton_class])
302
287
  stub_methods(C.singleton_class, ['public1', 'public2'], [], [])
303
- lookup_path = Looksee::LookupPath.new(C, :public => true)
304
- lookup_path.inspect.should == <<-EOS.demargin
288
+ lookup_path = Looksee::LookupPath.for(C, :public => true)
289
+ lookup_path.inspect.should == <<-EOS.demargin.chomp
305
290
  |[C]
306
291
  | public1 public2
307
292
  EOS
@@ -310,12 +295,22 @@ describe Looksee::LookupPath do
310
295
  it "should handle singleton classes of singleton classes correctly" do
311
296
  Looksee.stubs(:lookup_modules).with(C.singleton_class).returns([C.singleton_class.singleton_class])
312
297
  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
298
+ lookup_path = Looksee::LookupPath.for(C.singleton_class, :public => true)
299
+ lookup_path.inspect.should == <<-EOS.demargin.chomp
315
300
  |[[C]]
316
301
  | public1 public2
317
302
  EOS
318
303
  end
304
+
305
+ it "should not show any blank lines if a module has no methods" do
306
+ stub_methods(C, [], [], [])
307
+ lookup_path = Looksee::LookupPath.for(@object, :public => true, :overridden => true)
308
+ lookup_path.inspect.should == <<-EOS.demargin.chomp
309
+ |C
310
+ |M
311
+ | public1 public2
312
+ EOS
313
+ end
319
314
  end
320
315
 
321
316
  describe "styles" do
@@ -334,8 +329,8 @@ describe Looksee::LookupPath do
334
329
  temporary_class :C
335
330
  Looksee.stubs(:lookup_modules).returns([C])
336
331
  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
332
+ lookup_path = Looksee::LookupPath.for(Object.new, :public => true, :protected => true, :private => true, :overridden => true)
333
+ lookup_path.inspect.should == <<-EOS.demargin.chomp
339
334
  |\`C\'
340
335
  | <private> [protected] {public}
341
336
  EOS
@@ -347,8 +342,8 @@ describe Looksee::LookupPath do
347
342
  temporary_class :C
348
343
  Looksee.stubs(:lookup_modules).returns([C])
349
344
  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
345
+ lookup_path = Looksee::LookupPath.for(Object.new, :public => true)
346
+ lookup_path.inspect(:width => 20).should == <<-EOS.demargin.chomp
352
347
  |C
353
348
  | aa c ee g i
354
349
  | b dd f hh
@@ -361,8 +356,8 @@ describe Looksee::LookupPath do
361
356
  Looksee.stubs(:lookup_modules).returns([A, B])
362
357
  stub_methods(A, ['a', 'long_long_long_long_name'], [], [])
363
358
  stub_methods(B, ['long_long_long', 'short'], [], [])
364
- lookup_path = Looksee::LookupPath.new(Object.new, :public => true)
365
- lookup_path.inspect.should == <<-EOS.demargin
359
+ lookup_path = Looksee::LookupPath.for(Object.new, :public => true)
360
+ lookup_path.inspect.should == <<-EOS.demargin.chomp
366
361
  |A
367
362
  | a long_long_long_long_name
368
363
  |B
@@ -2,6 +2,7 @@ require 'spec'
2
2
  require 'mocha'
3
3
  require 'looksee'
4
4
 
5
+ require 'rbconfig'
5
6
  require 'set'
6
7
 
7
8
  Spec::Runner.configure do |config|
@@ -59,8 +60,8 @@ module TemporaryClasses
59
60
  #
60
61
  # Create a temporary class with the given name and superclass.
61
62
  #
62
- def temporary_class(name, superclass=Object, &block)
63
- klass = Class.new(superclass)
63
+ def temporary_class(name, options={}, &block)
64
+ klass = Class.new(options[:superclass] || Object)
64
65
  Object.const_set(name, klass)
65
66
  klass.class_eval(&block) if block
66
67
  @temporary_modules << klass
@@ -77,4 +78,62 @@ module TemporaryClasses
77
78
  @temporary_modules << mod
78
79
  mod
79
80
  end
81
+
82
+ #
83
+ # Remove all methods defined exactly on the given module.
84
+ #
85
+ # As Ruby's reflection on singleton classes of classes isn't quite
86
+ # adequate, you need to provide a :class_singleton option when such
87
+ # a class is given.
88
+ #
89
+ def remove_methods(mod, opts={})
90
+ names = all_instance_methods(mod)
91
+
92
+ # all_instance_methods can't get just the methods on a class
93
+ # singleton class. Filter out superclass methods here.
94
+ if opts[:class_singleton]
95
+ klass = ObjectSpace.each_object(mod){|klass| break klass}
96
+ names -= all_instance_methods(klass.superclass.singleton_class)
97
+ end
98
+
99
+ names.sort_by{|name| name.in?([:remove_method, :send]) ? 1 : 0}.flatten
100
+ names.each do |name|
101
+ mod.send :remove_method, name
102
+ end
103
+ end
104
+
105
+ #
106
+ # Replace the methods of the given module with those named.
107
+ #
108
+ # +methods+ is a hash of visibilities to names.
109
+ #
110
+ # As Ruby's reflection on singleton classes of classes isn't quite
111
+ # adequate, you need to provide a :class_singleton option when such
112
+ # a class is given.
113
+ #
114
+ # e.g.:
115
+ #
116
+ # replace_methods MyClass, :public => [:a, :b]
117
+ #
118
+ def replace_methods(mod, options={})
119
+ remove_methods(mod, options)
120
+ mod.module_eval do
121
+ [:public, :protected, :private].each do |visibility|
122
+ Array(options[visibility]).each do |name|
123
+ define_method(name){}
124
+ send visibility, name
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ private # ---------------------------------------------------------
131
+
132
+ def all_instance_methods(mod)
133
+ names =
134
+ mod.public_instance_methods(false) +
135
+ mod.protected_instance_methods(false) +
136
+ mod.private_instance_methods(false)
137
+ names.map{|name| name.to_sym} # they're strings in ruby <1.9
138
+ end
80
139
  end
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+ gem 'wirble' # die if wirble unavailable
3
+
4
+ describe Looksee::WirbleCompatibility do
5
+ describe "when looksee is loaded" do
6
+ #
7
+ # Run the given ruby string, and return the standard output.
8
+ #
9
+ def init_irb_with(code)
10
+ code = <<-EOS.demargin.gsub(/\n/, ';')
11
+ |#{code}
12
+ |#{stubbing_code}
13
+ |lp Object.new
14
+ EOS
15
+ irb = File.join Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'].sub(/ruby/, 'irb')
16
+ lib_dir = File.expand_path('lib')
17
+ # irb hangs when using readline without a tty
18
+ output = IO.popen("#{irb} -f --noreadline --noprompt --noverbose -I#{lib_dir} 2>&1", 'r+') do |io|
19
+ io.puts code
20
+ io.flush
21
+ io.close_write
22
+ io.read
23
+ end
24
+ end
25
+
26
+ def stubbing_code
27
+ <<-EOS.demargin
28
+ |C = Class.new
29
+ |
30
+ |Looksee.styles = Hash.new{'%s'}
31
+ |Looksee.styles[:public] = "\\e[1;32m%s\\e[0m"
32
+ |
33
+ |def Looksee.lookup_modules(object)
34
+ | [C]
35
+ |end
36
+ |def Looksee.internal_public_instance_methods(mod)
37
+ | [:a]
38
+ |end
39
+ |def Looksee.internal_protected_instance_methods(mod)
40
+ | []
41
+ |end
42
+ |def Looksee.internal_private_instance_methods(mod)
43
+ | []
44
+ |end
45
+ EOS
46
+ end
47
+
48
+ it "should work if wirble is not loaded" do
49
+ output = init_irb_with(<<-EOS.demargin)
50
+ |require 'irb'
51
+ |require 'looksee/shortcuts'
52
+ |require 'wirble'
53
+ |Wirble.init
54
+ |Wirble.colorize
55
+ EOS
56
+ output.should == <<-EOS.demargin
57
+ |C
58
+ | \e[1;32ma\e[0m
59
+ EOS
60
+ end
61
+
62
+ it "should work if wirble is loaded, but not initialized" do
63
+ output = init_irb_with(<<-EOS.demargin)
64
+ |require 'irb'
65
+ |require 'wirble'
66
+ |require 'looksee/shortcuts'
67
+ |Wirble.init
68
+ |Wirble.colorize
69
+ EOS
70
+ output.should == <<-EOS.demargin
71
+ |C
72
+ | \e[1;32ma\e[0m
73
+ EOS
74
+ end
75
+
76
+ it "should work if wirble is loaded and initialized, but colorizing is off" do
77
+ output = init_irb_with(<<-EOS.demargin)
78
+ |require 'irb'
79
+ |require 'wirble'
80
+ |Wirble.init
81
+ |require 'looksee/shortcuts'
82
+ |Wirble.colorize
83
+ EOS
84
+ output.should == <<-EOS.demargin
85
+ |C
86
+ | \e[1;32ma\e[0m
87
+ EOS
88
+ end
89
+
90
+ it "should work if wirble is loaded, initialized, and colorizing is on" do
91
+ output = init_irb_with(<<-EOS.demargin)
92
+ |require 'irb'
93
+ |require 'wirble'
94
+ |Wirble.init
95
+ |Wirble.colorize
96
+ |require 'looksee/shortcuts'
97
+ EOS
98
+ output.should == <<-EOS.demargin
99
+ |C
100
+ | \e[1;32ma\e[0m
101
+ EOS
102
+ end
103
+
104
+ it "should work if wirble colorizing is enabled twice" do
105
+ output = init_irb_with(<<-EOS.demargin)
106
+ |require 'irb'
107
+ |require 'looksee/shortcuts'
108
+ |require 'wirble'
109
+ |Wirble.init
110
+ |Wirble.colorize
111
+ |Wirble.colorize
112
+ EOS
113
+ output.should == <<-EOS.demargin
114
+ |C
115
+ | \e[1;32ma\e[0m
116
+ EOS
117
+ end
118
+ end
119
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: looksee
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - George Ogata
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-05 00:00:00 -04:00
12
+ date: 2009-08-01 00:00:00 +12:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -55,81 +55,6 @@ dependencies:
55
55
  description: |-
56
56
  Looksee lets you examine the method lookup path of objects in ways not
57
57
  possible in plain ruby.
58
-
59
- Pop this in your .irbrc :
60
-
61
- require 'looksee/shortcuts'
62
-
63
- This defines a method +lp+ ("lookup path") which lets you do:
64
-
65
- irb(main):001:0> lp []
66
- => Array
67
- & concat frozen? push taguri
68
- * count hash rassoc taguri=
69
- + cycle include? reject take
70
- - delete index reject! take_while
71
- << delete_at indexes replace to_a
72
- <=> delete_if indices reverse to_ary
73
- == drop insert reverse! to_s
74
- [] drop_while inspect reverse_each to_yaml
75
- []= each join rindex transpose
76
- assoc each_index last select uniq
77
- at empty? length shift uniq!
78
- choice eql? map shuffle unshift
79
- clear fetch map! shuffle! values_at
80
- collect fill nitems size yaml_initialize
81
- collect! find_index pack slice zip
82
- combination first permutation slice! |
83
- compact flatten pop sort
84
- compact! flatten! product sort!
85
- Enumerable
86
- all? each_slice first min reverse_each
87
- any? each_with_index grep min_by select
88
- collect entries group_by minmax sort
89
- count enum_cons include? minmax_by sort_by
90
- cycle enum_slice inject none? take
91
- detect enum_with_index map one? take_while
92
- drop find max partition to_a
93
- drop_while find_all max_by reduce zip
94
- each_cons find_index member? reject
95
- Object
96
- taguri taguri= to_yaml to_yaml_properties to_yaml_style
97
- Kernel
98
- == hash object_id
99
- === id private_methods
100
- =~ inspect protected_methods
101
- __id__ instance_eval public_methods
102
- __send__ instance_exec respond_to?
103
- class instance_of? send
104
- clone instance_variable_defined? singleton_methods
105
- display instance_variable_get taint
106
- dup instance_variable_set tainted?
107
- enum_for instance_variables tap
108
- eql? is_a? to_a
109
- equal? kind_of? to_enum
110
- extend method to_s
111
- freeze methods type
112
- frozen? nil? untaint
113
-
114
- It'll also color the methods according to whether they're public,
115
- protected, private, or overridden. So pretty. You gotta try it.
116
-
117
- By default, it shows public and protected methods. Add private ones
118
- like so:
119
-
120
- lp [], :private => true
121
- lp [], :private # shortcut
122
-
123
- Or if you don't want protected:
124
-
125
- lp [], :protected => false
126
-
127
- There are variations too. And you can configure things. And you can
128
- use it as a library without polluting the built-in classes. See:
129
-
130
- $ ri Looksee
131
-
132
- Enjoy!
133
58
  email:
134
59
  - george.ogata@gmail.com
135
60
  executables: []
@@ -151,11 +76,14 @@ files:
151
76
  - lib/looksee.rb
152
77
  - lib/looksee/shortcuts.rb
153
78
  - lib/looksee/version.rb
79
+ - lib/looksee/wirble_compatibility.rb
80
+ - looksee.gemspec
154
81
  - script/console
155
82
  - script/destroy
156
83
  - script/generate
157
84
  - spec/looksee_spec.rb
158
85
  - spec/spec_helper.rb
86
+ - spec/wirble_compatibility_spec.rb
159
87
  - tasks/extconf.rake
160
88
  - tasks/extconf/looksee.rake
161
89
  has_rdoc: true
@@ -187,6 +115,6 @@ rubyforge_project: looksee
187
115
  rubygems_version: 1.3.4
188
116
  signing_key:
189
117
  specification_version: 3
190
- summary: Looksee lets you examine the method lookup path of objects in ways not possible in plain ruby
118
+ summary: Looksee lets you examine the method lookup path of objects in ways not possible in plain ruby.
191
119
  test_files: []
192
120