pry 0.9.11.4-i386-mswin32 → 0.9.12-i386-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +2 -0
- data/CHANGELOG +19 -0
- data/Rakefile +4 -0
- data/lib/pry.rb +1 -1
- data/lib/pry/cli.rb +14 -8
- data/lib/pry/code.rb +3 -3
- data/lib/pry/command.rb +20 -5
- data/lib/pry/command_set.rb +3 -3
- data/lib/pry/commands.rb +1 -1
- data/lib/pry/commands/disabled_commands.rb +2 -0
- data/lib/pry/commands/ls.rb +1 -2
- data/lib/pry/commands/reload_code.rb +8 -1
- data/lib/pry/commands/show_info.rb +66 -5
- data/lib/pry/commands/show_source.rb +2 -1
- data/lib/pry/commands/whereami.rb +87 -19
- data/lib/pry/completion.rb +13 -4
- data/lib/pry/helpers/base_helpers.rb +5 -2
- data/lib/pry/helpers/command_helpers.rb +3 -1
- data/lib/pry/helpers/documentation_helpers.rb +18 -7
- data/lib/pry/helpers/table.rb +4 -4
- data/lib/pry/indent.rb +2 -7
- data/lib/pry/method.rb +89 -129
- data/lib/pry/method/disowned.rb +53 -0
- data/lib/pry/method/weird_method_locator.rb +186 -0
- data/lib/pry/module_candidate.rb +13 -8
- data/lib/pry/pager.rb +12 -11
- data/lib/pry/plugins.rb +2 -0
- data/lib/pry/pry_class.rb +19 -3
- data/lib/pry/pry_instance.rb +3 -0
- data/lib/pry/terminal.rb +78 -0
- data/lib/pry/version.rb +1 -1
- data/lib/pry/wrapped_module.rb +63 -1
- data/spec/Procfile +3 -0
- data/spec/command_helpers_spec.rb +21 -1
- data/spec/commands/ls_spec.rb +4 -0
- data/spec/commands/show_doc_spec.rb +255 -123
- data/spec/commands/show_source_spec.rb +421 -236
- data/spec/commands/whereami_spec.rb +60 -11
- data/spec/completion_spec.rb +6 -0
- data/spec/documentation_helper_spec.rb +73 -0
- data/spec/fixtures/whereami_helper.rb +6 -0
- data/spec/helpers/table_spec.rb +19 -0
- data/spec/method_spec.rb +24 -7
- metadata +12 -5
- data/.gemtest +0 -0
- data/lib/pry/commands/deprecated_commands.rb +0 -2
- data/lib/pry/terminal_info.rb +0 -48
@@ -0,0 +1,53 @@
|
|
1
|
+
class Pry
|
2
|
+
class Method
|
3
|
+
# A Disowned Method is one that's been removed from the class on which it was defined.
|
4
|
+
#
|
5
|
+
# e.g.
|
6
|
+
# class C
|
7
|
+
# def foo
|
8
|
+
# C.send(:undefine_method, :foo)
|
9
|
+
# Pry::Method.from_binding(binding)
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# In this case we assume that the "owner" is the singleton class of the receiver.
|
14
|
+
#
|
15
|
+
# This occurs mainly in Sinatra applications.
|
16
|
+
class Disowned < Method
|
17
|
+
attr_reader :receiver, :name
|
18
|
+
|
19
|
+
# Create a new Disowned method.
|
20
|
+
#
|
21
|
+
# @param [Object] receiver
|
22
|
+
# @param [String] method_name
|
23
|
+
def initialize(receiver, method_name, binding=nil)
|
24
|
+
@receiver, @name = receiver, method_name
|
25
|
+
end
|
26
|
+
|
27
|
+
# Is the method undefined? (aka `Disowned`)
|
28
|
+
# @return [Boolean] true
|
29
|
+
def undefined?
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
# Can we get the source for this method?
|
34
|
+
# @return [Boolean] false
|
35
|
+
def source?
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
# Get the hypothesized owner of the method.
|
40
|
+
#
|
41
|
+
# @return [Object]
|
42
|
+
def owner
|
43
|
+
class << receiver; self; end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Raise a more useful error message instead of trying to forward to nil.
|
47
|
+
def method_missing(meth_name, *args, &block)
|
48
|
+
raise "Cannot call '#{meth_name}' on an undef'd method." if method(:name).respond_to?(meth_name)
|
49
|
+
Object.instance_method(:method_missing).bind(self).call(meth_name, *args, &block)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
class Pry
|
2
|
+
class Method
|
3
|
+
|
4
|
+
# This class is responsible for locating the *real* `Pry::Method`
|
5
|
+
# object captured by a binding.
|
6
|
+
#
|
7
|
+
# Given a `Binding` from inside a method and a 'seed' Pry::Method object,
|
8
|
+
# there are primarily two situations where the seed method doesn't match
|
9
|
+
# the Binding:
|
10
|
+
# 1. The Pry::Method is from a subclass 2. The Pry::Method represents a method of the same name
|
11
|
+
# while the original was renamed to something else. For 1. we
|
12
|
+
# search vertically up the inheritance chain,
|
13
|
+
# and for 2. we search laterally along the object's method table.
|
14
|
+
#
|
15
|
+
# When we locate the method that matches the Binding we wrap it in
|
16
|
+
# Pry::Method and return it, or return nil if we fail.
|
17
|
+
class WeirdMethodLocator
|
18
|
+
class << self
|
19
|
+
|
20
|
+
# Whether the given method object matches the associated binding.
|
21
|
+
# If the method object does not match the binding, then it's
|
22
|
+
# most likely not the method captured by the binding, and we
|
23
|
+
# must commence a search.
|
24
|
+
#
|
25
|
+
# @param [Pry::Method] method
|
26
|
+
# @param [Binding] b
|
27
|
+
# @return [Boolean]
|
28
|
+
def normal_method?(method, b)
|
29
|
+
method && (method.source_file && method.source_range rescue false) &&
|
30
|
+
File.expand_path(method.source_file) == File.expand_path(b.eval('__FILE__')) &&
|
31
|
+
method.source_range.include?(b.eval('__LINE__'))
|
32
|
+
end
|
33
|
+
|
34
|
+
def weird_method?(method, b)
|
35
|
+
!normal_method?(method, b)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_accessor :method
|
40
|
+
attr_accessor :target
|
41
|
+
|
42
|
+
# @param [Pry::Method] method The seed method.
|
43
|
+
# @param [Binding] target The Binding that captures the method
|
44
|
+
# we want to locate.
|
45
|
+
def initialize(method, target)
|
46
|
+
@method, @target = method, target
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Pry::Method, nil] The Pry::Method that matches the
|
50
|
+
# given binding.
|
51
|
+
def get_method
|
52
|
+
find_method_in_superclass || find_renamed_method
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Boolean] Whether the Pry::Method is unrecoverable
|
56
|
+
# This usually happens when the method captured by the Binding
|
57
|
+
# has been subsequently deleted.
|
58
|
+
def lost_method?
|
59
|
+
!!(get_method.nil? && renamed_method_source_location)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def normal_method?(method)
|
65
|
+
self.class.normal_method?(method, target)
|
66
|
+
end
|
67
|
+
|
68
|
+
def target_self
|
69
|
+
target.eval('self')
|
70
|
+
end
|
71
|
+
|
72
|
+
def target_file
|
73
|
+
pry_file? ? target.eval('__FILE__') : File.expand_path(target.eval('__FILE__'))
|
74
|
+
end
|
75
|
+
|
76
|
+
def target_line
|
77
|
+
target.eval('__LINE__')
|
78
|
+
end
|
79
|
+
|
80
|
+
def pry_file?
|
81
|
+
Pry.eval_path == target.eval('__FILE__')
|
82
|
+
end
|
83
|
+
|
84
|
+
# it's possible in some cases that the method we find by this approach is a sub-method of
|
85
|
+
# the one we're currently in, consider:
|
86
|
+
#
|
87
|
+
# class A; def b; binding.pry; end; end
|
88
|
+
# class B < A; def b; super; end; end
|
89
|
+
#
|
90
|
+
# Given that we can normally find the source_range of methods, and that we know which
|
91
|
+
# __FILE__ and __LINE__ the binding is at, we can hope to disambiguate these cases.
|
92
|
+
#
|
93
|
+
# This obviously won't work if the source is unavaiable for some reason, or if both
|
94
|
+
# methods have the same __FILE__ and __LINE__, or if we're in rbx where b.eval('__LINE__')
|
95
|
+
# is broken.
|
96
|
+
#
|
97
|
+
# @return [Pry::Method, nil] The Pry::Method representing the
|
98
|
+
# superclass method.
|
99
|
+
def find_method_in_superclass
|
100
|
+
guess = method
|
101
|
+
|
102
|
+
while guess
|
103
|
+
# needs rescue if this is a Disowned method or a C method or something...
|
104
|
+
# TODO: Fix up the exception handling so we don't need a bare rescue
|
105
|
+
if normal_method?(guess)
|
106
|
+
return guess
|
107
|
+
else
|
108
|
+
guess = guess.super
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Uhoh... none of the methods in the chain had the right __FILE__ and __LINE__
|
113
|
+
# This may be caused by rbx https://github.com/rubinius/rubinius/issues/953,
|
114
|
+
# or other unknown circumstances (TODO: we should warn the user when this happens)
|
115
|
+
nil
|
116
|
+
end
|
117
|
+
|
118
|
+
# This is the case where the name of a method has changed
|
119
|
+
# (via alias_method) so we locate the Method object for the
|
120
|
+
# renamed method.
|
121
|
+
#
|
122
|
+
# @return [Pry::Method, nil] The Pry::Method representing the
|
123
|
+
# renamed method
|
124
|
+
def find_renamed_method
|
125
|
+
return if !valid_file?(target_file)
|
126
|
+
alias_name = all_methods_for(target_self).find do |v|
|
127
|
+
expanded_source_location(target_self.method(v).source_location) == renamed_method_source_location
|
128
|
+
end
|
129
|
+
|
130
|
+
alias_name && Pry::Method(target_self.method(alias_name))
|
131
|
+
end
|
132
|
+
|
133
|
+
def expanded_source_location(sl)
|
134
|
+
return if !sl
|
135
|
+
|
136
|
+
if pry_file?
|
137
|
+
sl
|
138
|
+
else
|
139
|
+
[File.expand_path(sl.first), sl.last]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Use static analysis to locate the start of the method definition.
|
144
|
+
# We have the `__FILE__` and `__LINE__` from the binding and the
|
145
|
+
# original name of the method so we search up until we find a
|
146
|
+
# def/define_method, etc defining a method of the appropriate name.
|
147
|
+
#
|
148
|
+
# @return [Array<String, Fixnum>] The `source_location` of the
|
149
|
+
# renamed method
|
150
|
+
def renamed_method_source_location
|
151
|
+
return @original_method_source_location if defined?(@original_method_source_location)
|
152
|
+
|
153
|
+
source_index = lines_for_file(target_file)[0..(target_line - 1)].rindex do |v|
|
154
|
+
Pry::Method.method_definition?(method.name, v)
|
155
|
+
end
|
156
|
+
|
157
|
+
@original_method_source_location = source_index &&
|
158
|
+
[target_file, index_to_line_number(source_index)]
|
159
|
+
end
|
160
|
+
|
161
|
+
def index_to_line_number(index)
|
162
|
+
# Pry.line_buffer is 0-indexed
|
163
|
+
pry_file? ? index : index + 1
|
164
|
+
end
|
165
|
+
|
166
|
+
def valid_file?(file)
|
167
|
+
File.exists?(file) || Pry.eval_path == file
|
168
|
+
end
|
169
|
+
|
170
|
+
def lines_for_file(file)
|
171
|
+
@lines_for_file ||= {}
|
172
|
+
@lines_for_file[file] ||= if Pry.eval_path == file
|
173
|
+
Pry.line_buffer
|
174
|
+
else
|
175
|
+
File.readlines(file)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def all_methods_for(obj)
|
180
|
+
obj.public_methods(false) +
|
181
|
+
obj.private_methods(false) +
|
182
|
+
obj.protected_methods(false)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
data/lib/pry/module_candidate.rb
CHANGED
@@ -20,12 +20,17 @@ class Pry
|
|
20
20
|
attr_reader :line
|
21
21
|
alias_method :source_line, :line
|
22
22
|
|
23
|
-
# Methods to delegate to associated `Pry::WrappedModule
|
24
|
-
|
25
|
-
|
23
|
+
# Methods to delegate to associated `Pry::WrappedModule
|
24
|
+
# instance`.
|
25
|
+
private_delegates = [:lines_for_file, :method_candidates,
|
26
|
+
:yard_docs?]
|
26
27
|
|
27
|
-
|
28
|
-
|
28
|
+
public_delegates = [:wrapped, :module?, :class?, :name, :nonblank_name,
|
29
|
+
:number_of_candidates]
|
30
|
+
|
31
|
+
def_delegators :@wrapper, *(private_delegates + public_delegates)
|
32
|
+
private *private_delegates
|
33
|
+
public *public_delegates
|
29
34
|
|
30
35
|
# @raise [Pry::CommandError] If `rank` is out of bounds.
|
31
36
|
# @param [Pry::WrappedModule] wrapper The associated
|
@@ -52,8 +57,8 @@ class Pry
|
|
52
57
|
# @return [String] The source for the candidate, i.e the
|
53
58
|
# complete module/class definition.
|
54
59
|
def source
|
60
|
+
return nil if file.nil?
|
55
61
|
return @source if @source
|
56
|
-
raise CommandError, "Could not locate source for #{wrapped}!" if file.nil?
|
57
62
|
|
58
63
|
@source = strip_leading_whitespace(Pry::Code.from_file(file).expression_at(line, number_of_lines_in_first_chunk))
|
59
64
|
end
|
@@ -61,10 +66,10 @@ class Pry
|
|
61
66
|
# @raise [Pry::CommandError] If documentation cannot be found.
|
62
67
|
# @return [String] The documentation for the candidate.
|
63
68
|
def doc
|
69
|
+
return nil if file.nil?
|
64
70
|
return @doc if @doc
|
65
|
-
raise CommandError, "Could not locate doc for #{wrapped}!" if file.nil?
|
66
71
|
|
67
|
-
@doc =
|
72
|
+
@doc = get_comment_content(Pry::Code.from_file(file).comment_describing(line))
|
68
73
|
end
|
69
74
|
|
70
75
|
# @return [Array, nil] A `[String, Fixnum]` pair representing the
|
data/lib/pry/pager.rb
CHANGED
@@ -12,8 +12,11 @@ class Pry::Pager
|
|
12
12
|
case pager
|
13
13
|
when nil
|
14
14
|
no_pager = !SystemPager.available?
|
15
|
-
|
16
|
-
|
15
|
+
if no_pager || Pry::Helpers::BaseHelpers.jruby?
|
16
|
+
SimplePager.new(text).page
|
17
|
+
else
|
18
|
+
SystemPager.new(text).page
|
19
|
+
end
|
17
20
|
when :simple
|
18
21
|
SimplePager.new(text).page
|
19
22
|
when :system
|
@@ -24,12 +27,7 @@ class Pry::Pager
|
|
24
27
|
end
|
25
28
|
|
26
29
|
def self.page_size
|
27
|
-
@page_size ||=
|
28
|
-
require 'io/console'
|
29
|
-
$stdout.winsize.first
|
30
|
-
rescue LoadError
|
31
|
-
27
|
32
|
-
end
|
30
|
+
@page_size ||= Pry::Terminal.height!
|
33
31
|
end
|
34
32
|
|
35
33
|
def initialize(text)
|
@@ -38,11 +36,14 @@ class Pry::Pager
|
|
38
36
|
|
39
37
|
class SimplePager < Pry::Pager
|
40
38
|
def page
|
39
|
+
# The pager size minus the number of lines used by the simple pager info bar.
|
40
|
+
page_size = Pry::Pager.page_size - 3
|
41
41
|
text_array = @text.lines.to_a
|
42
|
-
|
42
|
+
|
43
|
+
text_array.each_slice(page_size) do |chunk|
|
43
44
|
puts chunk.join
|
44
|
-
break if chunk.size <
|
45
|
-
if text_array.size >
|
45
|
+
break if chunk.size < page_size
|
46
|
+
if text_array.size > page_size
|
46
47
|
puts "\n<page break> --- Press enter to continue ( q<enter> to break ) --- <page break>"
|
47
48
|
break if $stdin.gets.chomp == "q"
|
48
49
|
end
|
data/lib/pry/plugins.rb
CHANGED
data/lib/pry/pry_class.rb
CHANGED
@@ -262,10 +262,26 @@ class Pry
|
|
262
262
|
end
|
263
263
|
|
264
264
|
def self.auto_resize!
|
265
|
+
ver = Readline::VERSION
|
266
|
+
if ver[/edit/i]
|
267
|
+
warn <<-EOT
|
268
|
+
Readline version #{ver} detected - will not auto_resize! correctly.
|
269
|
+
For the fix, use GNU Readline instead:
|
270
|
+
https://github.com/guard/guard/wiki/Add-proper-Readline-support-to-Ruby-on-Mac-OS-X
|
271
|
+
EOT
|
272
|
+
return
|
273
|
+
end
|
265
274
|
trap :WINCH do
|
266
|
-
|
267
|
-
|
268
|
-
|
275
|
+
begin
|
276
|
+
Readline.set_screen_size *Terminal.size!
|
277
|
+
rescue => e
|
278
|
+
warn "\nPry.auto_resize!'s Readline.set_screen_size failed: #{e}"
|
279
|
+
end
|
280
|
+
begin
|
281
|
+
Readline.refresh_line
|
282
|
+
rescue => e
|
283
|
+
warn "\nPry.auto_resize!'s Readline.refresh_line failed: #{e}"
|
284
|
+
end
|
269
285
|
end
|
270
286
|
end
|
271
287
|
|
data/lib/pry/pry_instance.rb
CHANGED
@@ -618,6 +618,9 @@ class Pry
|
|
618
618
|
end
|
619
619
|
|
620
620
|
if input == Readline
|
621
|
+
if !$stdout.tty? && $stdin.tty? && !Pry::Helpers::BaseHelpers.windows?
|
622
|
+
Readline.output = File.open('/dev/tty', 'w')
|
623
|
+
end
|
621
624
|
input.readline(current_prompt, false) # false since we'll add it manually
|
622
625
|
elsif defined? Coolline and input.is_a? Coolline
|
623
626
|
input.readline(current_prompt)
|
data/lib/pry/terminal.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
class Pry::Terminal
|
2
|
+
class << self
|
3
|
+
# Return a pair of [rows, columns] which gives the size of the window.
|
4
|
+
#
|
5
|
+
# If the window size cannot be determined, return nil.
|
6
|
+
def screen_size
|
7
|
+
rows, cols = actual_screen_size
|
8
|
+
if rows && cols
|
9
|
+
[rows.to_i, cols.to_i]
|
10
|
+
else
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Return a screen size or a default if that fails.
|
16
|
+
def size! default = [27, 80]
|
17
|
+
screen_size || default
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return a screen width or the default if that fails.
|
21
|
+
def width!
|
22
|
+
size![1]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return a screen height or the default if that fails.
|
26
|
+
def height!
|
27
|
+
size![0]
|
28
|
+
end
|
29
|
+
|
30
|
+
def actual_screen_size
|
31
|
+
# The best way, if possible (requires non-jruby ≥1.9 or io-console gem)
|
32
|
+
screen_size_according_to_io_console or
|
33
|
+
# Fall back to the old standby, though it might be stale:
|
34
|
+
screen_size_according_to_env or
|
35
|
+
# Fall further back, though this one is also out of date without something
|
36
|
+
# calling Readline.set_screen_size
|
37
|
+
screen_size_according_to_readline or
|
38
|
+
# Windows users can otherwise run ansicon and get a decent answer:
|
39
|
+
screen_size_according_to_ansicon_env
|
40
|
+
end
|
41
|
+
|
42
|
+
def screen_size_according_to_io_console
|
43
|
+
return if Pry::Helpers::BaseHelpers.jruby?
|
44
|
+
require 'io/console'
|
45
|
+
$stdout.winsize if $stdout.tty? and $stdout.respond_to?(:winsize)
|
46
|
+
rescue LoadError
|
47
|
+
# They're probably on 1.8 without the io-console gem. We'll keep trying.
|
48
|
+
end
|
49
|
+
|
50
|
+
def screen_size_according_to_env
|
51
|
+
size = [ENV['LINES'] || ENV['ROWS'], ENV['COLUMNS']]
|
52
|
+
size if nonzero_column?(size)
|
53
|
+
end
|
54
|
+
|
55
|
+
def screen_size_according_to_readline
|
56
|
+
if Readline.respond_to?(:get_screen_size)
|
57
|
+
size = Readline.get_screen_size
|
58
|
+
size if nonzero_column?(size)
|
59
|
+
end
|
60
|
+
rescue Java::JavaLang::NullPointerException
|
61
|
+
# This rescue won't happen on jrubies later than:
|
62
|
+
# https://github.com/jruby/jruby/pull/436
|
63
|
+
nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def screen_size_according_to_ansicon_env
|
67
|
+
return unless ENV['ANSICON'] =~ /\((.*)x(.*)\)/
|
68
|
+
size = [$2, $1]
|
69
|
+
size if nonzero_column?(size)
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def nonzero_column?(size)
|
75
|
+
size[1].to_i > 0
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|