pry 0.9.8.4 → 0.9.9
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/CHANGELOG +26 -0
- data/README.markdown +3 -3
- data/lib/pry.rb +9 -1
- data/lib/pry/code.rb +93 -0
- data/lib/pry/command.rb +35 -22
- data/lib/pry/command_set.rb +97 -67
- data/lib/pry/config.rb +63 -10
- data/lib/pry/core_extensions.rb +24 -18
- data/lib/pry/default_commands/context.rb +72 -12
- data/lib/pry/default_commands/easter_eggs.rb +4 -0
- data/lib/pry/default_commands/editing.rb +43 -15
- data/lib/pry/default_commands/find_method.rb +171 -0
- data/lib/pry/default_commands/hist.rb +10 -6
- data/lib/pry/default_commands/introspection.rb +183 -30
- data/lib/pry/default_commands/ls.rb +77 -7
- data/lib/pry/default_commands/misc.rb +1 -0
- data/lib/pry/default_commands/navigating_pry.rb +1 -8
- data/lib/pry/helpers/base_helpers.rb +10 -2
- data/lib/pry/helpers/command_helpers.rb +23 -40
- data/lib/pry/helpers/documentation_helpers.rb +65 -0
- data/lib/pry/indent.rb +17 -4
- data/lib/pry/method.rb +61 -45
- data/lib/pry/pry_class.rb +9 -3
- data/lib/pry/pry_instance.rb +99 -65
- data/lib/pry/rbx_method.rb +2 -9
- data/lib/pry/version.rb +1 -1
- data/lib/pry/wrapped_module.rb +236 -1
- data/pry.gemspec +5 -5
- data/test/helper.rb +22 -0
- data/test/test_command.rb +29 -0
- data/test/test_command_integration.rb +193 -10
- data/test/test_command_set.rb +82 -17
- data/test/test_default_commands/test_cd.rb +16 -0
- data/test/test_default_commands/test_context.rb +61 -0
- data/test/test_default_commands/test_documentation.rb +163 -43
- data/test/test_default_commands/test_find_method.rb +42 -0
- data/test/test_default_commands/test_input.rb +32 -0
- data/test/test_default_commands/test_introspection.rb +50 -197
- data/test/test_default_commands/test_ls.rb +22 -0
- data/test/test_default_commands/test_show_source.rb +306 -0
- data/test/test_pry.rb +3 -3
- data/test/test_pry_defaults.rb +21 -0
- data/test/test_sticky_locals.rb +81 -1
- data/test/test_syntax_checking.rb +7 -6
- metadata +22 -14
@@ -32,21 +32,25 @@ class Pry
|
|
32
32
|
def process
|
33
33
|
@history = Pry::Code(Pry.history.to_a)
|
34
34
|
|
35
|
+
if opts.present?(:show)
|
36
|
+
@history = @history.between(opts[:show])
|
37
|
+
end
|
38
|
+
|
39
|
+
if opts.present?(:grep)
|
40
|
+
@history = @history.grep(opts[:grep])
|
41
|
+
end
|
42
|
+
|
35
43
|
@history = case
|
36
44
|
when opts.present?(:head)
|
37
|
-
@history.
|
45
|
+
@history.take_lines(1, opts[:head] || 10)
|
38
46
|
when opts.present?(:tail)
|
39
|
-
@history.
|
47
|
+
@history.take_lines(-(opts[:tail] || 10), opts[:tail] || 10)
|
40
48
|
when opts.present?(:show)
|
41
49
|
@history.between(opts[:show])
|
42
50
|
else
|
43
51
|
@history
|
44
52
|
end
|
45
53
|
|
46
|
-
if opts.present?(:grep)
|
47
|
-
@history = @history.grep(opts[:grep])
|
48
|
-
end
|
49
|
-
|
50
54
|
if opts.present?(:'exclude-pry')
|
51
55
|
@history = @history.select { |l, ln| !command_set.valid_command?(l) }
|
52
56
|
end
|
@@ -3,23 +3,127 @@ require 'tempfile'
|
|
3
3
|
class Pry
|
4
4
|
module DefaultCommands
|
5
5
|
|
6
|
+
# For show-doc and show-source
|
7
|
+
module ModuleIntrospectionHelpers
|
8
|
+
attr_accessor :module_object
|
9
|
+
|
10
|
+
def module?(name)
|
11
|
+
self.module_object = Pry::WrappedModule.from_str(name, target)
|
12
|
+
end
|
13
|
+
|
14
|
+
def method?
|
15
|
+
!!method_object
|
16
|
+
rescue CommandError
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
def process(name)
|
21
|
+
if module?(name)
|
22
|
+
code_or_doc = process_module
|
23
|
+
else method?
|
24
|
+
code_or_doc = process_method
|
25
|
+
end
|
26
|
+
|
27
|
+
render_output(code_or_doc, opts)
|
28
|
+
end
|
29
|
+
|
30
|
+
def module_start_line(mod, candidate=0)
|
31
|
+
if opts.present?(:'base-one')
|
32
|
+
1
|
33
|
+
else
|
34
|
+
mod.source_line_for_candidate(candidate)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def use_line_numbers?
|
39
|
+
opts.present?(:b) || opts.present?(:l)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
6
43
|
Introspection = Pry::CommandSet.new do
|
7
44
|
|
8
|
-
create_command "show-doc", "Show the comments above METH. Aliases: \?", :shellwords => false do
|
45
|
+
create_command "show-doc", "Show the comments above METH. Aliases: \?", :shellwords => false do
|
46
|
+
include ModuleIntrospectionHelpers
|
47
|
+
include Helpers::DocumentationHelpers
|
48
|
+
extend Helpers::BaseHelpers
|
49
|
+
|
9
50
|
banner <<-BANNER
|
10
51
|
Usage: show-doc [OPTIONS] [METH]
|
52
|
+
Aliases: ?
|
53
|
+
|
11
54
|
Show the comments above method METH. Tries instance methods first and then methods by default.
|
12
|
-
e.g show-doc hello_method
|
55
|
+
e.g show-doc hello_method # docs for hello_method
|
56
|
+
e.g show-doc Pry # docs for Pry class
|
57
|
+
e.g show-doc Pry -a # docs for all definitions of Pry class (all monkey patches)
|
13
58
|
BANNER
|
14
59
|
|
60
|
+
options :requires_gem => "ruby18_source_location" if mri_18?
|
61
|
+
|
62
|
+
def setup
|
63
|
+
require 'ruby18_source_location' if mri_18?
|
64
|
+
end
|
65
|
+
|
15
66
|
def options(opt)
|
16
67
|
method_options(opt)
|
17
68
|
opt.on :l, "line-numbers", "Show line numbers."
|
18
69
|
opt.on :b, "base-one", "Show line numbers but start numbering at 1 (useful for `amend-line` and `play` commands)."
|
19
70
|
opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
|
71
|
+
opt.on :a, :all, "Show docs for all definitions and monkeypatches of the module (modules only)"
|
20
72
|
end
|
21
73
|
|
22
|
-
def
|
74
|
+
def process_module
|
75
|
+
if opts.present?(:all)
|
76
|
+
all_modules
|
77
|
+
else
|
78
|
+
normal_module
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def normal_module
|
83
|
+
mod = module_object
|
84
|
+
|
85
|
+
# source_file reveals the underlying .c file in case of core
|
86
|
+
# classes on MRI. This is different to source_location, which
|
87
|
+
# will return nil.
|
88
|
+
if mod.yard_docs?
|
89
|
+
file_name, line = mod.source_file, nil
|
90
|
+
else
|
91
|
+
file_name, line = mod.source_location
|
92
|
+
end
|
93
|
+
|
94
|
+
if mod.doc.empty?
|
95
|
+
output.puts "No documentation found."
|
96
|
+
""
|
97
|
+
else
|
98
|
+
set_file_and_dir_locals(file_name) if !mod.yard_docs?
|
99
|
+
doc = ""
|
100
|
+
doc << mod.doc
|
101
|
+
|
102
|
+
doc = Code.new(doc, module_start_line(mod), :text).
|
103
|
+
with_line_numbers(use_line_numbers?).to_s
|
104
|
+
|
105
|
+
doc.insert(0, "\n#{Pry::Helpers::Text.bold('From:')} #{file_name} @ line #{line ? line : "N/A"}:\n\n")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def all_modules
|
110
|
+
mod = module_object
|
111
|
+
|
112
|
+
doc = ""
|
113
|
+
doc << "Found #{mod.number_of_candidates} candidates for `#{mod.name}` definition:\n"
|
114
|
+
mod.number_of_candidates.times do |v|
|
115
|
+
begin
|
116
|
+
doc << "\nCandidate #{v+1}/#{mod.number_of_candidates}: #{mod.source_file_for_candidate(v)} @ #{mod.source_line_for_candidate(v)}:\n\n"
|
117
|
+
dc = mod.doc_for_candidate(v)
|
118
|
+
doc << (dc.empty? ? "No documentation found.\n" : dc)
|
119
|
+
rescue Pry::RescuableException
|
120
|
+
next
|
121
|
+
end
|
122
|
+
end
|
123
|
+
doc
|
124
|
+
end
|
125
|
+
|
126
|
+
def process_method
|
23
127
|
meth = method_object
|
24
128
|
raise Pry::CommandError, "No documentation found." if meth.doc.nil? || meth.doc.empty?
|
25
129
|
|
@@ -30,12 +134,20 @@ class Pry
|
|
30
134
|
output.puts "#{text.bold("Signature:")} #{meth.signature}"
|
31
135
|
output.puts
|
32
136
|
|
33
|
-
if
|
137
|
+
if use_line_numbers?
|
34
138
|
doc = Code.new(doc, start_line, :text).
|
35
|
-
with_line_numbers(true)
|
139
|
+
with_line_numbers(true).to_s
|
36
140
|
end
|
37
141
|
|
38
|
-
|
142
|
+
doc
|
143
|
+
end
|
144
|
+
|
145
|
+
def module_start_line(mod, candidate=0)
|
146
|
+
if opts.present?(:'base-one')
|
147
|
+
1
|
148
|
+
else
|
149
|
+
mod.source_line_for_candidate(candidate) - mod.doc_for_candidate(candidate).lines.count
|
150
|
+
end
|
39
151
|
end
|
40
152
|
|
41
153
|
def start_line
|
@@ -45,12 +157,11 @@ class Pry
|
|
45
157
|
(method_object.source_line - method_object.doc.lines.count) || 1
|
46
158
|
end
|
47
159
|
end
|
48
|
-
|
49
160
|
end
|
50
161
|
|
51
162
|
alias_command "?", "show-doc"
|
52
163
|
|
53
|
-
create_command "stat", "View method information and set _file_ and _dir_ locals.", :shellwords => false do
|
164
|
+
create_command "stat", "View method information and set _file_ and _dir_ locals.", :shellwords => false do
|
54
165
|
banner <<-BANNER
|
55
166
|
Usage: stat [OPTIONS] [METH]
|
56
167
|
Show method information for method METH and set _file_ and _dir_ locals.
|
@@ -77,45 +188,87 @@ class Pry
|
|
77
188
|
end
|
78
189
|
end
|
79
190
|
|
80
|
-
create_command "show-
|
81
|
-
|
191
|
+
create_command "show-source" do
|
192
|
+
include ModuleIntrospectionHelpers
|
193
|
+
extend Helpers::BaseHelpers
|
194
|
+
|
195
|
+
description "Show the source for METH or CLASS. Aliases: $, show-method"
|
82
196
|
|
83
197
|
banner <<-BANNER
|
84
|
-
Usage: show-
|
85
|
-
Aliases: $, show-
|
198
|
+
Usage: show-source [OPTIONS] [METH|CLASS]
|
199
|
+
Aliases: $, show-method
|
86
200
|
|
87
|
-
Show the source for method METH. Tries instance methods first and then methods by default.
|
201
|
+
Show the source for method METH or CLASS. Tries instance methods first and then methods by default.
|
88
202
|
|
89
|
-
e.g: `show-
|
90
|
-
e.g: `show-
|
91
|
-
e.g: `show-
|
203
|
+
e.g: `show-source hello_method`
|
204
|
+
e.g: `show-source -m hello_method`
|
205
|
+
e.g: `show-source Pry#rep` # source for Pry#rep method
|
206
|
+
e.g: `show-source Pry` # source for Pry class
|
207
|
+
e.g: `show-source Pry -a` # source for all Pry class definitions (all monkey patches)
|
92
208
|
|
93
209
|
https://github.com/pry/pry/wiki/Source-browsing#wiki-Show_method
|
94
210
|
BANNER
|
95
211
|
|
96
|
-
|
97
|
-
|
98
|
-
|
212
|
+
options :shellwords => false
|
213
|
+
options :requires_gem => "ruby18_source_location" if mri_18?
|
214
|
+
|
215
|
+
def setup
|
216
|
+
require 'ruby18_source_location' if mri_18?
|
217
|
+
end
|
99
218
|
|
100
219
|
def options(opt)
|
101
220
|
method_options(opt)
|
102
221
|
opt.on :l, "line-numbers", "Show line numbers."
|
103
222
|
opt.on :b, "base-one", "Show line numbers but start numbering at 1 (useful for `amend-line` and `play` commands)."
|
104
223
|
opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
|
224
|
+
opt.on :a, :all, "Show source for all definitions and monkeypatches of the module (modules only)"
|
105
225
|
end
|
106
226
|
|
107
|
-
def
|
227
|
+
def process_method
|
108
228
|
raise CommandError, "Could not find method source" unless method_object.source
|
109
229
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
230
|
+
code = ""
|
231
|
+
code << make_header(method_object)
|
232
|
+
code << "#{text.bold("Owner:")} #{method_object.owner || "N/A"}\n"
|
233
|
+
code << "#{text.bold("Visibility:")} #{method_object.visibility}\n"
|
234
|
+
code << "\n"
|
114
235
|
|
115
|
-
code
|
116
|
-
with_line_numbers(use_line_numbers?)
|
236
|
+
code << Code.from_method(method_object, start_line).
|
237
|
+
with_line_numbers(use_line_numbers?).to_s
|
238
|
+
end
|
117
239
|
|
118
|
-
|
240
|
+
def process_module
|
241
|
+
if opts.present?(:all)
|
242
|
+
all_modules
|
243
|
+
else
|
244
|
+
normal_module
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def normal_module
|
249
|
+
mod = module_object
|
250
|
+
|
251
|
+
file_name, line = mod.source_location
|
252
|
+
set_file_and_dir_locals(file_name)
|
253
|
+
code = ""
|
254
|
+
code << "\n#{Pry::Helpers::Text.bold('From:')} #{file_name} @ line #{line}:\n\n"
|
255
|
+
code << Code.from_module(mod, module_start_line(mod)).with_line_numbers(use_line_numbers?).to_s
|
256
|
+
end
|
257
|
+
|
258
|
+
def all_modules
|
259
|
+
mod = module_object
|
260
|
+
|
261
|
+
code = ""
|
262
|
+
code << "Found #{mod.number_of_candidates} candidates for `#{mod.name}` definition:\n"
|
263
|
+
mod.number_of_candidates.times do |v|
|
264
|
+
begin
|
265
|
+
code << "\nCandidate #{v+1}/#{mod.number_of_candidates}: #{mod.source_file_for_candidate(v)} @ line #{mod.source_line_for_candidate(v)}:\n\n"
|
266
|
+
code << Code.new(mod.source_for_candidate(v), module_start_line(mod, v)).with_line_numbers(use_line_numbers?).to_s
|
267
|
+
rescue Pry::RescuableException
|
268
|
+
next
|
269
|
+
end
|
270
|
+
end
|
271
|
+
code
|
119
272
|
end
|
120
273
|
|
121
274
|
def use_line_numbers?
|
@@ -131,8 +284,8 @@ class Pry
|
|
131
284
|
end
|
132
285
|
end
|
133
286
|
|
134
|
-
alias_command "show-
|
135
|
-
alias_command "$", "show-
|
287
|
+
alias_command "show-method", "show-source"
|
288
|
+
alias_command "$", "show-source"
|
136
289
|
|
137
290
|
command "show-command", "Show the source for CMD." do |*args|
|
138
291
|
target = target()
|
@@ -167,7 +320,7 @@ class Pry
|
|
167
320
|
output.puts make_header(block)
|
168
321
|
output.puts
|
169
322
|
|
170
|
-
code = Code.from_method(block).with_line_numbers(opts.present?(:'line-numbers'))
|
323
|
+
code = Code.from_method(block).with_line_numbers(opts.present?(:'line-numbers')).to_s
|
171
324
|
|
172
325
|
render_output(code, opts)
|
173
326
|
else
|
@@ -30,11 +30,15 @@ class Pry
|
|
30
30
|
opt.on :g, "globals", "Show global variables, including those builtin to Ruby (in cyan)"
|
31
31
|
opt.on :l, "locals", "Show locals, including those provided by Pry (in red)"
|
32
32
|
|
33
|
-
opt.on :c, "constants", "Show constants, highlighting classes (in blue), and exceptions (in purple)"
|
33
|
+
opt.on :c, "constants", "Show constants, highlighting classes (in blue), and exceptions (in purple).\n" +
|
34
|
+
" " * 32 + "Constants that are pending autoload? are also shown (in yellow)."
|
34
35
|
|
35
36
|
opt.on :i, "ivars", "Show instance variables (in blue) and class variables (in bright blue)"
|
36
37
|
|
37
38
|
opt.on :G, "grep", "Filter output by regular expression", :optional => false
|
39
|
+
if jruby?
|
40
|
+
opt.on :J, "all-java", "Show all the aliases for methods from java (default is to show only prettiest)"
|
41
|
+
end
|
38
42
|
end
|
39
43
|
|
40
44
|
def process
|
@@ -46,6 +50,7 @@ class Pry
|
|
46
50
|
opts.present?(:ivars))
|
47
51
|
|
48
52
|
show_methods = opts.present?(:methods) || opts.present?(:'instance-methods') || opts.present?(:ppp) || !has_opts
|
53
|
+
show_self_methods = (!has_opts && Module === obj)
|
49
54
|
show_constants = opts.present?(:constants) || (!has_opts && Module === obj)
|
50
55
|
show_ivars = opts.present?(:ivars) || !has_opts
|
51
56
|
show_locals = opts.present?(:locals) || (!has_opts && args.empty?)
|
@@ -72,7 +77,7 @@ class Pry
|
|
72
77
|
|
73
78
|
if show_methods
|
74
79
|
# methods is a hash {Module/Class => [Pry::Methods]}
|
75
|
-
methods = all_methods(obj).
|
80
|
+
methods = all_methods(obj).group_by(&:owner)
|
76
81
|
|
77
82
|
# reverse the resolution order so that the most useful information appears right by the prompt
|
78
83
|
resolution_order(obj).take_while(&below_ceiling(obj)).reverse.each do |klass|
|
@@ -81,10 +86,17 @@ class Pry
|
|
81
86
|
end
|
82
87
|
end
|
83
88
|
|
89
|
+
if show_self_methods
|
90
|
+
methods = all_methods(obj, true).select{ |m| m.owner == obj && m.name =~ grep_regex }
|
91
|
+
output_section "#{Pry::WrappedModule.new(obj).method_prefix}methods", format_methods(methods)
|
92
|
+
end
|
93
|
+
|
84
94
|
if show_ivars
|
85
95
|
klass = (Module === obj ? obj : obj.class)
|
86
|
-
|
87
|
-
|
96
|
+
ivars = Pry::Method.safe_send(obj, :instance_variables)
|
97
|
+
kvars = Pry::Method.safe_send(klass, :class_variables)
|
98
|
+
output_section("instance variables", format_variables(:instance_var, ivars))
|
99
|
+
output_section("class variables", format_variables(:class_var, kvars))
|
88
100
|
end
|
89
101
|
|
90
102
|
if show_locals
|
@@ -109,8 +121,64 @@ class Pry
|
|
109
121
|
$LAST_PAREN_MATCH $LAST_READ_LINE $MATCH $POSTMATCH $PREMATCH)
|
110
122
|
|
111
123
|
# Get all the methods that we'll want to output
|
112
|
-
def all_methods(obj)
|
113
|
-
opts.present?(:'instance-methods')
|
124
|
+
def all_methods(obj, instance_methods=false)
|
125
|
+
methods = if instance_methods || opts.present?(:'instance-methods')
|
126
|
+
Pry::Method.all_from_class(obj)
|
127
|
+
else
|
128
|
+
Pry::Method.all_from_obj(obj)
|
129
|
+
end
|
130
|
+
|
131
|
+
if jruby? && !opts.present?(:J)
|
132
|
+
methods = trim_jruby_aliases(methods)
|
133
|
+
end
|
134
|
+
|
135
|
+
methods.select{ |method| opts.present?(:ppp) || method.visibility == :public }
|
136
|
+
end
|
137
|
+
|
138
|
+
# JRuby creates lots of aliases for methods imported from java in an attempt to
|
139
|
+
# make life easier for ruby programmers.
|
140
|
+
# (e.g. getFooBar becomes get_foo_bar and foo_bar, and maybe foo_bar? if it
|
141
|
+
# returns a Boolean).
|
142
|
+
# The full transformations are in the assignAliases method of:
|
143
|
+
# https://github.com/jruby/jruby/blob/master/src/org/jruby/javasupport/JavaClass.java
|
144
|
+
#
|
145
|
+
# This has the unfortunate side-effect of making the output of ls even more
|
146
|
+
# incredibly verbose than it normally would be for these objects; and so we filter
|
147
|
+
# out all but the nicest of these aliases here.
|
148
|
+
#
|
149
|
+
# TODO: This is a little bit vague, better heuristics could be used.
|
150
|
+
# JRuby also has a lot of scala-specific logic, which we don't copy.
|
151
|
+
#
|
152
|
+
def trim_jruby_aliases(methods)
|
153
|
+
grouped = methods.group_by do |m|
|
154
|
+
m.name.sub(/\A(is|get|set)(?=[A-Z_])/, '').gsub(/[_?=]/, '').downcase
|
155
|
+
end
|
156
|
+
|
157
|
+
grouped.map do |key, values|
|
158
|
+
values = values.sort_by do |m|
|
159
|
+
rubbishness(m.name)
|
160
|
+
end
|
161
|
+
|
162
|
+
found = []
|
163
|
+
values.select do |x|
|
164
|
+
(!found.any?{ |y| x == y }) && found << x
|
165
|
+
end
|
166
|
+
end.flatten(1)
|
167
|
+
end
|
168
|
+
|
169
|
+
# When removing jruby aliases, we want to keep the alias that is "least rubbish"
|
170
|
+
# according to this metric.
|
171
|
+
def rubbishness(name)
|
172
|
+
name.each_char.map{ |x|
|
173
|
+
case x
|
174
|
+
when /[A-Z]/
|
175
|
+
1
|
176
|
+
when '?', '=', '!'
|
177
|
+
-2
|
178
|
+
else
|
179
|
+
0
|
180
|
+
end
|
181
|
+
}.inject(&:+) + (name.size / 100.0)
|
114
182
|
end
|
115
183
|
|
116
184
|
def resolution_order(obj)
|
@@ -152,7 +220,7 @@ class Pry
|
|
152
220
|
|
153
221
|
def format_constants(mod, constants)
|
154
222
|
constants.sort_by(&:downcase).map do |name|
|
155
|
-
if const = (!mod.autoload?(name) && mod.const_get(name) rescue nil)
|
223
|
+
if const = (!mod.autoload?(name) && (mod.const_get(name) || true) rescue nil)
|
156
224
|
if (const < Exception rescue false)
|
157
225
|
color(:exception_constant, name)
|
158
226
|
elsif (Module === mod.const_get(name) rescue false)
|
@@ -160,6 +228,8 @@ class Pry
|
|
160
228
|
else
|
161
229
|
color(:constant, name)
|
162
230
|
end
|
231
|
+
else
|
232
|
+
color(:unloaded_constant, name)
|
163
233
|
end
|
164
234
|
end
|
165
235
|
end
|