looksee 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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