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.
- data/History.txt +7 -0
- data/Manifest.txt +3 -0
- data/Rakefile +1 -2
- data/ext/looksee/looksee.c +1 -1
- data/lib/looksee.rb +62 -20
- data/lib/looksee/version.rb +1 -1
- data/lib/looksee/wirble_compatibility.rb +86 -0
- data/looksee.gemspec +44 -0
- data/spec/looksee_spec.rb +80 -85
- data/spec/spec_helper.rb +61 -2
- data/spec/wirble_compatibility_spec.rb +119 -0
- metadata +6 -78
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
@@ -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 :
|
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}"],
|
data/ext/looksee/looksee.c
CHANGED
data/lib/looksee.rb
CHANGED
@@ -77,7 +77,7 @@ module Looksee
|
|
77
77
|
normalized_options[option] = true
|
78
78
|
end
|
79
79
|
normalized_options.update(hash_options)
|
80
|
-
LookupPath.
|
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
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
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
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
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'
|
data/lib/looksee/version.rb
CHANGED
@@ -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
|
data/looksee.gemspec
ADDED
@@ -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
|
data/spec/looksee_spec.rb
CHANGED
@@ -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(:
|
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(:
|
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(:
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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(:
|
226
|
+
Looksee.stubs(:default_lookup_path_options).returns({})
|
240
227
|
end
|
241
228
|
|
242
|
-
|
243
|
-
Looksee.stubs(:
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
data/spec/spec_helper.rb
CHANGED
@@ -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,
|
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.
|
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-
|
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
|
|