looksee 1.0.0-universal-java-1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +14 -0
- data/LICENSE +22 -0
- data/README.markdown +161 -0
- data/Rakefile +10 -0
- data/ext/extconf.rb +9 -0
- data/ext/mri/1.9.2/debug.h +36 -0
- data/ext/mri/1.9.2/id.h +170 -0
- data/ext/mri/1.9.2/method.h +103 -0
- data/ext/mri/1.9.2/node.h +483 -0
- data/ext/mri/1.9.2/thread_pthread.h +27 -0
- data/ext/mri/1.9.2/vm_core.h +707 -0
- data/ext/mri/1.9.2/vm_opts.h +51 -0
- data/ext/mri/env-1.8.h +27 -0
- data/ext/mri/eval_c-1.8.h +27 -0
- data/ext/mri/mri.c +269 -0
- data/ext/mri/node-1.9.h +35 -0
- data/ext/rbx/rbx.c +13 -0
- data/lib/looksee.rb +5 -0
- data/lib/looksee/adapter.rb +10 -0
- data/lib/looksee/adapter/base.rb +100 -0
- data/lib/looksee/adapter/rubinius.rb +73 -0
- data/lib/looksee/clean.rb +122 -0
- data/lib/looksee/columnizer.rb +73 -0
- data/lib/looksee/core_ext.rb +59 -0
- data/lib/looksee/editor.rb +58 -0
- data/lib/looksee/help.rb +54 -0
- data/lib/looksee/inspector.rb +55 -0
- data/lib/looksee/jruby.jar +0 -0
- data/lib/looksee/lookup_path.rb +95 -0
- data/lib/looksee/rbx.bundle +0 -0
- data/lib/looksee/shortcuts.rb +3 -0
- data/lib/looksee/version.rb +11 -0
- data/lib/looksee/wirble_compatibility.rb +86 -0
- data/spec/adapter_spec.rb +546 -0
- data/spec/columnizer_spec.rb +52 -0
- data/spec/core_ext_spec.rb +41 -0
- data/spec/editor_spec.rb +128 -0
- data/spec/inspector_spec.rb +178 -0
- data/spec/lookup_path_spec.rb +84 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/core_ext.rb +25 -0
- data/spec/support/temporary_classes.rb +102 -0
- data/spec/support/test_adapter.rb +72 -0
- data/spec/wirble_compatibility_spec.rb +116 -0
- metadata +158 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
module Looksee
|
2
|
+
module Adapter
|
3
|
+
class Base
|
4
|
+
#
|
5
|
+
# Return the chain of classes and modules which comprise the
|
6
|
+
# object's method lookup path.
|
7
|
+
#
|
8
|
+
def lookup_modules(object)
|
9
|
+
modules = []
|
10
|
+
klass = internal_class(object)
|
11
|
+
while klass
|
12
|
+
modules << internal_class_to_module(klass)
|
13
|
+
klass = internal_superclass(klass)
|
14
|
+
end
|
15
|
+
modules
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Return a description of the given module.
|
20
|
+
#
|
21
|
+
# This is used for the module labels in the Inspector output.
|
22
|
+
#
|
23
|
+
def describe_module(mod)
|
24
|
+
num_brackets = 0
|
25
|
+
object = mod
|
26
|
+
while singleton_class?(object)
|
27
|
+
num_brackets += 1
|
28
|
+
object = singleton_instance(object)
|
29
|
+
end
|
30
|
+
|
31
|
+
if object.is_a?(Module)
|
32
|
+
description = module_name(object)
|
33
|
+
if description.empty?
|
34
|
+
description = "unnamed #{object.is_a?(Class) ? 'Class' : 'Module'}"
|
35
|
+
end
|
36
|
+
else
|
37
|
+
description = "#{module_name(object.class)} instance"
|
38
|
+
end
|
39
|
+
|
40
|
+
if num_brackets == 0
|
41
|
+
description
|
42
|
+
else
|
43
|
+
"#{'['*num_brackets}#{description}#{']'*num_brackets}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def internal_superclass(klass)
|
48
|
+
raise NotImplementedError, "abstract"
|
49
|
+
end
|
50
|
+
|
51
|
+
def internal_class(object)
|
52
|
+
raise NotImplementedError, "abstract"
|
53
|
+
end
|
54
|
+
|
55
|
+
def internal_class_to_module(internal_class)
|
56
|
+
raise NotImplementedError, "abstract"
|
57
|
+
end
|
58
|
+
|
59
|
+
def internal_public_instance_methods(mod)
|
60
|
+
raise NotImplementedError, "abstract"
|
61
|
+
end
|
62
|
+
|
63
|
+
def internal_protected_instance_methods(mod)
|
64
|
+
raise NotImplementedError, "abstract"
|
65
|
+
end
|
66
|
+
|
67
|
+
def internal_private_instance_methods(mod)
|
68
|
+
raise NotImplementedError, "abstract"
|
69
|
+
end
|
70
|
+
|
71
|
+
def internal_undefined_instance_methods(mod)
|
72
|
+
raise NotImplementedError, "abstract"
|
73
|
+
end
|
74
|
+
|
75
|
+
def singleton_class?(object)
|
76
|
+
raise NotImplementedError, "abstract"
|
77
|
+
end
|
78
|
+
|
79
|
+
def singleton_instance(singleton_class)
|
80
|
+
raise NotImplementedError, "abstract"
|
81
|
+
end
|
82
|
+
|
83
|
+
def module_name(mod)
|
84
|
+
raise NotImplementedError, "abstract"
|
85
|
+
end
|
86
|
+
|
87
|
+
if RUBY_VERSION >= '1.9.0' || Looksee.ruby_engine == 'rbx'
|
88
|
+
def source_location(method)
|
89
|
+
method.is_a?(UnboundMethod) or
|
90
|
+
raise TypeError, "expected UnboundMethod, got #{method.class}"
|
91
|
+
method.source_location
|
92
|
+
end
|
93
|
+
else
|
94
|
+
def source_location(method)
|
95
|
+
raise NotImplementedError, 'abstract'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'looksee/adapter/base'
|
2
|
+
require 'looksee/rbx'
|
3
|
+
|
4
|
+
module Looksee
|
5
|
+
module Adapter
|
6
|
+
class Rubinius < Base
|
7
|
+
def internal_superclass(klass)
|
8
|
+
klass.direct_superclass
|
9
|
+
end
|
10
|
+
|
11
|
+
def internal_class_to_module(internal_class)
|
12
|
+
if internal_class.is_a?(::Rubinius::IncludedModule)
|
13
|
+
internal_class.module
|
14
|
+
else
|
15
|
+
internal_class
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def internal_public_instance_methods(mod)
|
20
|
+
mod.method_table.public_names
|
21
|
+
end
|
22
|
+
|
23
|
+
def internal_protected_instance_methods(mod)
|
24
|
+
mod.method_table.protected_names
|
25
|
+
end
|
26
|
+
|
27
|
+
def internal_private_instance_methods(mod)
|
28
|
+
mod.method_table.private_names
|
29
|
+
end
|
30
|
+
|
31
|
+
def internal_undefined_instance_methods(mod)
|
32
|
+
names = []
|
33
|
+
mod.method_table.each_entry do |entry|
|
34
|
+
names << entry.name if entry.visibility.equal?(:undef)
|
35
|
+
end
|
36
|
+
names
|
37
|
+
end
|
38
|
+
|
39
|
+
def singleton_class?(object)
|
40
|
+
object.is_a?(Class) && object.__metaclass_object__
|
41
|
+
end
|
42
|
+
|
43
|
+
def singleton_instance(singleton_class)
|
44
|
+
singleton_class?(singleton_class) or
|
45
|
+
raise TypeError, "expected singleton class, got #{singleton_class.class}"
|
46
|
+
singleton_class.__metaclass_object__
|
47
|
+
end
|
48
|
+
|
49
|
+
def module_name(mod)
|
50
|
+
mod.is_a?(Module) or
|
51
|
+
raise TypeError, "expected module, got #{mod.class}"
|
52
|
+
mod.__name__
|
53
|
+
end
|
54
|
+
|
55
|
+
def source_location(method)
|
56
|
+
method.is_a?(UnboundMethod) or
|
57
|
+
raise TypeError, "expected UnboundMethod, got #{method.class}"
|
58
|
+
source_location = method.source_location and
|
59
|
+
return source_location
|
60
|
+
|
61
|
+
# #source_location doesn't always work. If it returns nil, try
|
62
|
+
# a little harder.
|
63
|
+
case (executable = method.executable)
|
64
|
+
when ::Rubinius::BlockEnvironment::AsMethod
|
65
|
+
method = executable.instance_variable_get(:@block_env).method
|
66
|
+
[method.file.to_s, method.lines[1]]
|
67
|
+
when ::Rubinius::DelegatedMethod
|
68
|
+
executable.instance_variable_get(:@receiver).source_location
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require "rbconfig"
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module Looksee
|
6
|
+
autoload :VERSION, 'looksee/version'
|
7
|
+
autoload :Adapter, 'looksee/adapter'
|
8
|
+
autoload :Columnizer, 'looksee/columnizer'
|
9
|
+
autoload :Editor, 'looksee/editor'
|
10
|
+
autoload :Help, 'looksee/help'
|
11
|
+
autoload :Inspector, 'looksee/inspector'
|
12
|
+
autoload :LookupPath, 'looksee/lookup_path'
|
13
|
+
autoload :WirbleCompatibility, 'looksee/wirble_compatibility'
|
14
|
+
|
15
|
+
class << self
|
16
|
+
#
|
17
|
+
# The default options passed to #ls.
|
18
|
+
#
|
19
|
+
# Default: <tt>[:public, :protected, :private, :undefined,
|
20
|
+
# :overridden]</tt>
|
21
|
+
#
|
22
|
+
attr_accessor :default_specifiers
|
23
|
+
|
24
|
+
#
|
25
|
+
# The width to use for displaying output, when not available in
|
26
|
+
# the COLUMNS environment variable.
|
27
|
+
#
|
28
|
+
# Default: 80
|
29
|
+
#
|
30
|
+
attr_accessor :default_width
|
31
|
+
|
32
|
+
#
|
33
|
+
# The default styles to use for the +inspect+ strings.
|
34
|
+
#
|
35
|
+
# This is a hash with keys:
|
36
|
+
#
|
37
|
+
# * :module
|
38
|
+
# * :public
|
39
|
+
# * :protected
|
40
|
+
# * :private
|
41
|
+
# * :undefined
|
42
|
+
# * :overridden
|
43
|
+
#
|
44
|
+
# The values are format strings. They should all contain a single
|
45
|
+
# "%s", which is where the name is inserted.
|
46
|
+
#
|
47
|
+
# Default:
|
48
|
+
#
|
49
|
+
# {
|
50
|
+
# :module => "\e[1;37m%s\e[0m", # white
|
51
|
+
# :public => "\e[1;32m%s\e[0m", # green
|
52
|
+
# :protected => "\e[1;33m%s\e[0m", # yellow
|
53
|
+
# :private => "\e[1;31m%s\e[0m", # red
|
54
|
+
# :undefined => "\e[1;34m%s\e[0m", # blue
|
55
|
+
# :overridden => "\e[1;30m%s\e[0m", # black
|
56
|
+
# }
|
57
|
+
#
|
58
|
+
attr_accessor :styles
|
59
|
+
|
60
|
+
#
|
61
|
+
# The editor command, used for Object#edit.
|
62
|
+
#
|
63
|
+
# This string should contain a "%f", which is replaced with the
|
64
|
+
# file name, and/or "%l" which is replaced with the line number. A
|
65
|
+
# "%%" is replaced with "%".
|
66
|
+
#
|
67
|
+
# If the LOOKSEE_EDITOR environment variable is set, it is used as
|
68
|
+
# the default. Otherwise, we use the following heuristic:
|
69
|
+
#
|
70
|
+
# If EDITOR is set, we use that. If it looks like vi, emacs, or
|
71
|
+
# textmate, we also append options to position the cursor on the
|
72
|
+
# appropriate line. If EDITOR is not set, we use "vi +%l %f".
|
73
|
+
#
|
74
|
+
attr_accessor :editor
|
75
|
+
|
76
|
+
#
|
77
|
+
# The interpreter adapter.
|
78
|
+
#
|
79
|
+
# Encapsulates the interpreter-specific functionality.
|
80
|
+
#
|
81
|
+
attr_accessor :adapter
|
82
|
+
|
83
|
+
#
|
84
|
+
# Wrapper around RUBY_ENGINE that's always defined.
|
85
|
+
#
|
86
|
+
attr_accessor :ruby_engine
|
87
|
+
|
88
|
+
#
|
89
|
+
# Show a quick reference.
|
90
|
+
#
|
91
|
+
def help
|
92
|
+
Help.new
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
self.default_specifiers = [:public, :protected, :private, :undefined, :overridden]
|
97
|
+
self.default_width = 80
|
98
|
+
self.styles = {
|
99
|
+
:module => "\e[1;37m%s\e[0m", # white
|
100
|
+
:public => "\e[1;32m%s\e[0m", # green
|
101
|
+
:protected => "\e[1;33m%s\e[0m", # yellow
|
102
|
+
:private => "\e[1;31m%s\e[0m", # red
|
103
|
+
:undefined => "\e[1;34m%s\e[0m", # blue
|
104
|
+
:overridden => "\e[1;30m%s\e[0m", # black
|
105
|
+
}
|
106
|
+
self.editor = ENV['LOOKSEE_EDITOR'] || ENV['EDITOR'] || 'vi'
|
107
|
+
|
108
|
+
if Object.const_defined?(:RUBY_ENGINE)
|
109
|
+
self.ruby_engine = RUBY_ENGINE
|
110
|
+
else
|
111
|
+
self.ruby_engine = 'ruby'
|
112
|
+
end
|
113
|
+
|
114
|
+
case ruby_engine
|
115
|
+
when 'jruby'
|
116
|
+
self.adapter = Adapter::JRuby.new
|
117
|
+
when 'rbx'
|
118
|
+
self.adapter = Adapter::Rubinius.new
|
119
|
+
else
|
120
|
+
self.adapter = Adapter::MRI.new
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Looksee
|
2
|
+
module Columnizer
|
3
|
+
class << self
|
4
|
+
#
|
5
|
+
# Arrange the given strings in columns, restricted to the given
|
6
|
+
# width. Smart enough to ignore content in terminal control
|
7
|
+
# sequences.
|
8
|
+
#
|
9
|
+
def columnize(strings, width)
|
10
|
+
return '' if strings.empty?
|
11
|
+
|
12
|
+
num_columns = 1
|
13
|
+
layout = [strings]
|
14
|
+
loop do
|
15
|
+
break if layout.first.length <= 1
|
16
|
+
next_layout = layout_in_columns(strings, num_columns + 1)
|
17
|
+
break if layout_width(next_layout) > width
|
18
|
+
layout = next_layout
|
19
|
+
num_columns += 1
|
20
|
+
end
|
21
|
+
|
22
|
+
pad_strings(layout)
|
23
|
+
rectangularize_layout(layout)
|
24
|
+
layout.transpose.map do |row|
|
25
|
+
' ' + row.compact.join(' ')
|
26
|
+
end.join("\n") << "\n"
|
27
|
+
end
|
28
|
+
|
29
|
+
private # -----------------------------------------------------
|
30
|
+
|
31
|
+
def layout_in_columns(strings, num_columns)
|
32
|
+
strings_per_column = (strings.length / num_columns.to_f).ceil
|
33
|
+
(0...num_columns).map{|i| strings[i*strings_per_column...(i+1)*strings_per_column] || []}
|
34
|
+
end
|
35
|
+
|
36
|
+
def layout_width(layout)
|
37
|
+
widths = layout_column_widths(layout)
|
38
|
+
widths.inject(0){|sum, w| sum + w} + 2*layout.length
|
39
|
+
end
|
40
|
+
|
41
|
+
def layout_column_widths(layout)
|
42
|
+
layout.map do |column|
|
43
|
+
column.map{|string| display_width(string)}.max || 0
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def display_width(string)
|
48
|
+
# remove terminal control sequences
|
49
|
+
string.gsub(/\e\[.*?m/, '').length
|
50
|
+
end
|
51
|
+
|
52
|
+
def pad_strings(layout)
|
53
|
+
widths = layout_column_widths(layout)
|
54
|
+
layout.each_with_index do |column, i|
|
55
|
+
column_width = widths[i]
|
56
|
+
column.each do |string|
|
57
|
+
padding = column_width - display_width(string)
|
58
|
+
string << ' '*padding
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def rectangularize_layout(layout)
|
64
|
+
return if layout.length == 1
|
65
|
+
height = layout[0].length
|
66
|
+
layout[1..-1].each do |column|
|
67
|
+
column.length == height or
|
68
|
+
column[height - 1] = nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Looksee
|
2
|
+
module ObjectMixin
|
3
|
+
#
|
4
|
+
# Return a Looksee::Inspector for this object.
|
5
|
+
#
|
6
|
+
# +args+ is an optional list of specifiers.
|
7
|
+
#
|
8
|
+
# * +:public+ - include public methods
|
9
|
+
# * +:protected+ - include public methods
|
10
|
+
# * +:private+ - include public methods
|
11
|
+
# * +:undefined+ - include public methods (see Module#undef_method)
|
12
|
+
# * +:overridden+ - include public methods
|
13
|
+
# * +:nopublic+ - include public methods
|
14
|
+
# * +:noprotected+ - include public methods
|
15
|
+
# * +:noprivate+ - include public methods
|
16
|
+
# * +:noundefined+ - include public methods (see Module#undef_method)
|
17
|
+
# * +:nooverridden+ - include public methods
|
18
|
+
# * a string - only include methods containing this string (may
|
19
|
+
# be used multiple times)
|
20
|
+
# * a regexp - only include methods matching this regexp (may
|
21
|
+
# be used multiple times)
|
22
|
+
#
|
23
|
+
# The default (if options is nil or omitted) is given by
|
24
|
+
# #default_lookup_path_options.
|
25
|
+
#
|
26
|
+
def ls(*args)
|
27
|
+
options = {:visibilities => Set[], :filters => Set[]}
|
28
|
+
(Looksee.default_specifiers + args).each do |arg|
|
29
|
+
case arg
|
30
|
+
when String, Regexp
|
31
|
+
options[:filters] << arg
|
32
|
+
when :public, :protected, :private, :undefined, :overridden
|
33
|
+
options[:visibilities].add(arg)
|
34
|
+
when :nopublic, :noprotected, :noprivate, :noundefined, :nooverridden
|
35
|
+
visibility = arg.to_s.sub(/\Ano/, '').to_sym
|
36
|
+
options[:visibilities].delete(visibility)
|
37
|
+
else
|
38
|
+
raise ArgumentError, "invalid specifier: #{arg.inspect}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
lookup_path = LookupPath.new(self)
|
42
|
+
Inspector.new(lookup_path, options)
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# Open an editor at the named method's definition.
|
47
|
+
#
|
48
|
+
# Uses Looksee.editor to determine the editor command to run.
|
49
|
+
#
|
50
|
+
# Only works for methods for which file and line numbers are
|
51
|
+
# accessible.
|
52
|
+
#
|
53
|
+
def edit(name)
|
54
|
+
Editor.new(Looksee.editor).edit(self, name)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
Object.send :include, ObjectMixin
|
59
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
3
|
+
module Looksee
|
4
|
+
class Editor
|
5
|
+
def initialize(command)
|
6
|
+
@command = command.dup
|
7
|
+
infer_arguments
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :command
|
11
|
+
|
12
|
+
#
|
13
|
+
# Run the editor command for the +method_name+ of +object+.
|
14
|
+
#
|
15
|
+
def edit(object, method_name)
|
16
|
+
method = LookupPath.new(object).find(method_name.to_s) or
|
17
|
+
return
|
18
|
+
file, line = Looksee.adapter.source_location(method)
|
19
|
+
run(file, line) unless line.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Run the editor command for the given file and line.
|
24
|
+
#
|
25
|
+
def run(file, line)
|
26
|
+
system *command_for(file, line)
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Return the editor command for the given file and line.
|
31
|
+
#
|
32
|
+
# This is an array of the command with its arguments.
|
33
|
+
#
|
34
|
+
def command_for(file, line)
|
35
|
+
line = line.to_s
|
36
|
+
words = Shellwords.shellwords(command)
|
37
|
+
words.map! do |word|
|
38
|
+
word.gsub!(/%f/, file)
|
39
|
+
word.gsub!(/%l/, line)
|
40
|
+
word.gsub!(/%%/, '%')
|
41
|
+
word
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def infer_arguments
|
48
|
+
return if command =~ /%[fl]/
|
49
|
+
|
50
|
+
case command[/\S+/]
|
51
|
+
when /\A(?:g?vim?|.*macs|pico|nano)\z/
|
52
|
+
command << " +%l %f"
|
53
|
+
when 'mate'
|
54
|
+
command << " -l%l %f"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|