pry 0.10.0.pre2-universal-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +702 -0
- data/LICENSE +25 -0
- data/README.md +406 -0
- data/bin/pry +16 -0
- data/lib/pry.rb +161 -0
- data/lib/pry/cli.rb +220 -0
- data/lib/pry/code.rb +346 -0
- data/lib/pry/code/code_file.rb +103 -0
- data/lib/pry/code/code_range.rb +71 -0
- data/lib/pry/code/loc.rb +92 -0
- data/lib/pry/code_object.rb +172 -0
- data/lib/pry/color_printer.rb +55 -0
- data/lib/pry/command.rb +692 -0
- data/lib/pry/command_set.rb +443 -0
- data/lib/pry/commands.rb +6 -0
- data/lib/pry/commands/amend_line.rb +99 -0
- data/lib/pry/commands/bang.rb +20 -0
- data/lib/pry/commands/bang_pry.rb +17 -0
- data/lib/pry/commands/cat.rb +62 -0
- data/lib/pry/commands/cat/abstract_formatter.rb +27 -0
- data/lib/pry/commands/cat/exception_formatter.rb +77 -0
- data/lib/pry/commands/cat/file_formatter.rb +67 -0
- data/lib/pry/commands/cat/input_expression_formatter.rb +43 -0
- data/lib/pry/commands/cd.rb +41 -0
- data/lib/pry/commands/change_inspector.rb +27 -0
- data/lib/pry/commands/change_prompt.rb +26 -0
- data/lib/pry/commands/code_collector.rb +165 -0
- data/lib/pry/commands/disable_pry.rb +27 -0
- data/lib/pry/commands/disabled_commands.rb +2 -0
- data/lib/pry/commands/easter_eggs.rb +112 -0
- data/lib/pry/commands/edit.rb +195 -0
- data/lib/pry/commands/edit/exception_patcher.rb +25 -0
- data/lib/pry/commands/edit/file_and_line_locator.rb +36 -0
- data/lib/pry/commands/exit.rb +42 -0
- data/lib/pry/commands/exit_all.rb +29 -0
- data/lib/pry/commands/exit_program.rb +23 -0
- data/lib/pry/commands/find_method.rb +193 -0
- data/lib/pry/commands/fix_indent.rb +19 -0
- data/lib/pry/commands/gem_cd.rb +26 -0
- data/lib/pry/commands/gem_install.rb +32 -0
- data/lib/pry/commands/gem_list.rb +33 -0
- data/lib/pry/commands/gem_open.rb +29 -0
- data/lib/pry/commands/gist.rb +101 -0
- data/lib/pry/commands/help.rb +164 -0
- data/lib/pry/commands/hist.rb +180 -0
- data/lib/pry/commands/import_set.rb +22 -0
- data/lib/pry/commands/install_command.rb +53 -0
- data/lib/pry/commands/jump_to.rb +29 -0
- data/lib/pry/commands/list_inspectors.rb +35 -0
- data/lib/pry/commands/list_prompts.rb +35 -0
- data/lib/pry/commands/ls.rb +114 -0
- data/lib/pry/commands/ls/constants.rb +47 -0
- data/lib/pry/commands/ls/formatter.rb +49 -0
- data/lib/pry/commands/ls/globals.rb +48 -0
- data/lib/pry/commands/ls/grep.rb +21 -0
- data/lib/pry/commands/ls/instance_vars.rb +39 -0
- data/lib/pry/commands/ls/interrogatable.rb +18 -0
- data/lib/pry/commands/ls/jruby_hacks.rb +49 -0
- data/lib/pry/commands/ls/local_names.rb +35 -0
- data/lib/pry/commands/ls/local_vars.rb +39 -0
- data/lib/pry/commands/ls/ls_entity.rb +70 -0
- data/lib/pry/commands/ls/methods.rb +57 -0
- data/lib/pry/commands/ls/methods_helper.rb +46 -0
- data/lib/pry/commands/ls/self_methods.rb +32 -0
- data/lib/pry/commands/nesting.rb +25 -0
- data/lib/pry/commands/play.rb +103 -0
- data/lib/pry/commands/pry_backtrace.rb +25 -0
- data/lib/pry/commands/pry_version.rb +17 -0
- data/lib/pry/commands/raise_up.rb +32 -0
- data/lib/pry/commands/reload_code.rb +62 -0
- data/lib/pry/commands/reset.rb +18 -0
- data/lib/pry/commands/ri.rb +60 -0
- data/lib/pry/commands/save_file.rb +61 -0
- data/lib/pry/commands/shell_command.rb +48 -0
- data/lib/pry/commands/shell_mode.rb +25 -0
- data/lib/pry/commands/show_doc.rb +83 -0
- data/lib/pry/commands/show_info.rb +195 -0
- data/lib/pry/commands/show_input.rb +17 -0
- data/lib/pry/commands/show_source.rb +50 -0
- data/lib/pry/commands/simple_prompt.rb +22 -0
- data/lib/pry/commands/stat.rb +40 -0
- data/lib/pry/commands/switch_to.rb +23 -0
- data/lib/pry/commands/toggle_color.rb +24 -0
- data/lib/pry/commands/watch_expression.rb +105 -0
- data/lib/pry/commands/watch_expression/expression.rb +38 -0
- data/lib/pry/commands/whereami.rb +190 -0
- data/lib/pry/commands/wtf.rb +57 -0
- data/lib/pry/config.rb +24 -0
- data/lib/pry/config/behavior.rb +139 -0
- data/lib/pry/config/convenience.rb +26 -0
- data/lib/pry/config/default.rb +165 -0
- data/lib/pry/core_extensions.rb +131 -0
- data/lib/pry/editor.rb +133 -0
- data/lib/pry/exceptions.rb +77 -0
- data/lib/pry/helpers.rb +5 -0
- data/lib/pry/helpers/base_helpers.rb +113 -0
- data/lib/pry/helpers/command_helpers.rb +156 -0
- data/lib/pry/helpers/documentation_helpers.rb +75 -0
- data/lib/pry/helpers/options_helpers.rb +27 -0
- data/lib/pry/helpers/table.rb +109 -0
- data/lib/pry/helpers/text.rb +107 -0
- data/lib/pry/history.rb +125 -0
- data/lib/pry/history_array.rb +121 -0
- data/lib/pry/hooks.rb +230 -0
- data/lib/pry/indent.rb +406 -0
- data/lib/pry/input_completer.rb +242 -0
- data/lib/pry/input_lock.rb +132 -0
- data/lib/pry/inspector.rb +27 -0
- data/lib/pry/last_exception.rb +61 -0
- data/lib/pry/method.rb +546 -0
- data/lib/pry/method/disowned.rb +53 -0
- data/lib/pry/method/patcher.rb +125 -0
- data/lib/pry/method/weird_method_locator.rb +186 -0
- data/lib/pry/module_candidate.rb +136 -0
- data/lib/pry/object_path.rb +82 -0
- data/lib/pry/output.rb +50 -0
- data/lib/pry/pager.rb +234 -0
- data/lib/pry/plugins.rb +103 -0
- data/lib/pry/prompt.rb +26 -0
- data/lib/pry/pry_class.rb +375 -0
- data/lib/pry/pry_instance.rb +654 -0
- data/lib/pry/rbx_path.rb +22 -0
- data/lib/pry/repl.rb +202 -0
- data/lib/pry/repl_file_loader.rb +74 -0
- data/lib/pry/rubygem.rb +82 -0
- data/lib/pry/terminal.rb +79 -0
- data/lib/pry/test/helper.rb +170 -0
- data/lib/pry/version.rb +3 -0
- data/lib/pry/wrapped_module.rb +373 -0
- metadata +248 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
class Pry
|
2
|
+
# N.B. using a regular expresion here so that "raise-up 'foo'" does the right thing.
|
3
|
+
class Command::RaiseUp < Pry::ClassCommand
|
4
|
+
match(/raise-up(!?\b.*)/)
|
5
|
+
group 'Context'
|
6
|
+
description 'Raise an exception out of the current pry instance.'
|
7
|
+
command_options :listing => 'raise-up'
|
8
|
+
|
9
|
+
banner <<-BANNER
|
10
|
+
Raise up, like exit, allows you to quit pry. Instead of returning a value
|
11
|
+
however, it raises an exception. If you don't provide the exception to be
|
12
|
+
raised, it will use the most recent exception (in pry `_ex_`).
|
13
|
+
|
14
|
+
When called as raise-up! (with an exclamation mark), this command raises the
|
15
|
+
exception through any nested prys you have created by "cd"ing into objects.
|
16
|
+
|
17
|
+
raise-up "get-me-out-of-here"
|
18
|
+
|
19
|
+
# This is equivalent to the command above.
|
20
|
+
raise "get-me-out-of-here"
|
21
|
+
raise-up
|
22
|
+
BANNER
|
23
|
+
|
24
|
+
def process
|
25
|
+
return _pry.pager.page help if captures[0] =~ /(-h|--help)\b/
|
26
|
+
# Handle 'raise-up', 'raise-up "foo"', 'raise-up RuntimeError, 'farble' in a rubyesque manner
|
27
|
+
target.eval("_pry_.raise_up#{captures[0]}")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Pry::Commands.add_command(Pry::Command::RaiseUp)
|
32
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
class Pry
|
2
|
+
class Command::ReloadCode < Pry::ClassCommand
|
3
|
+
match 'reload-code'
|
4
|
+
group 'Misc'
|
5
|
+
description 'Reload the source file that contains the specified code object.'
|
6
|
+
|
7
|
+
banner <<-'BANNER'
|
8
|
+
Reload the source file that contains the specified code object.
|
9
|
+
|
10
|
+
e.g reload-code MyClass#my_method #=> reload a method
|
11
|
+
reload-code MyClass #=> reload a class
|
12
|
+
reload-code my-command #=> reload a pry command
|
13
|
+
reload-code self #=> reload the current object
|
14
|
+
reload-code #=> reload the current file or object
|
15
|
+
BANNER
|
16
|
+
|
17
|
+
def process
|
18
|
+
if !args.empty?
|
19
|
+
reload_object(args.join(" "))
|
20
|
+
elsif internal_binding?(target)
|
21
|
+
reload_object("self")
|
22
|
+
else
|
23
|
+
reload_current_file
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def current_file
|
30
|
+
File.expand_path target.eval("__FILE__")
|
31
|
+
end
|
32
|
+
|
33
|
+
def reload_current_file
|
34
|
+
if !File.exists?(current_file)
|
35
|
+
raise CommandError, "Current file: #{current_file} cannot be found on disk!"
|
36
|
+
end
|
37
|
+
|
38
|
+
load current_file
|
39
|
+
output.puts "The current file: #{current_file} was reloaded!"
|
40
|
+
end
|
41
|
+
|
42
|
+
def reload_object(identifier)
|
43
|
+
code_object = Pry::CodeObject.lookup(identifier, _pry_)
|
44
|
+
check_for_reloadability(code_object, identifier)
|
45
|
+
load code_object.source_file
|
46
|
+
output.puts "#{identifier} was reloaded!"
|
47
|
+
end
|
48
|
+
|
49
|
+
def check_for_reloadability(code_object, identifier)
|
50
|
+
if !code_object || !code_object.source_file
|
51
|
+
raise CommandError, "Cannot locate #{identifier}!"
|
52
|
+
elsif !File.exists?(code_object.source_file)
|
53
|
+
raise CommandError,
|
54
|
+
"Cannot reload #{identifier} as it has no associated file on disk. " \
|
55
|
+
"File found was: #{code_object.source_file}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Pry::Commands.add_command(Pry::Command::ReloadCode)
|
61
|
+
Pry::Commands.alias_command 'reload-method', 'reload-code'
|
62
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Pry
|
2
|
+
class Command::Reset < Pry::ClassCommand
|
3
|
+
match 'reset'
|
4
|
+
group 'Context'
|
5
|
+
description 'Reset the REPL to a clean state.'
|
6
|
+
|
7
|
+
banner <<-'BANNER'
|
8
|
+
Reset the REPL to a clean state.
|
9
|
+
BANNER
|
10
|
+
|
11
|
+
def process
|
12
|
+
output.puts 'Pry reset.'
|
13
|
+
exec 'pry'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Pry::Commands.add_command(Pry::Command::Reset)
|
18
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class Pry
|
2
|
+
class Command::Ri < Pry::ClassCommand
|
3
|
+
match 'ri'
|
4
|
+
group 'Introspection'
|
5
|
+
description 'View ri documentation.'
|
6
|
+
|
7
|
+
banner <<-'BANNER'
|
8
|
+
Usage: ri [spec]
|
9
|
+
|
10
|
+
View ri documentation. Relies on the "rdoc" gem being installed.
|
11
|
+
See also "show-doc" command.
|
12
|
+
|
13
|
+
ri Array#each
|
14
|
+
BANNER
|
15
|
+
|
16
|
+
def process(spec)
|
17
|
+
# Lazily load RI
|
18
|
+
require 'rdoc/ri/driver'
|
19
|
+
|
20
|
+
unless defined? RDoc::RI::PryDriver
|
21
|
+
|
22
|
+
# Subclass RI so that it formats its output nicely, and uses `lesspipe`.
|
23
|
+
subclass = Class.new(RDoc::RI::Driver) # the hard way.
|
24
|
+
|
25
|
+
subclass.class_eval do
|
26
|
+
def initialize(pager, opts)
|
27
|
+
@pager = pager
|
28
|
+
super opts
|
29
|
+
end
|
30
|
+
def page
|
31
|
+
paging_text = StringIO.new
|
32
|
+
yield paging_text
|
33
|
+
@pager.page(paging_text.string)
|
34
|
+
end
|
35
|
+
|
36
|
+
def formatter(io)
|
37
|
+
if @formatter_klass
|
38
|
+
@formatter_klass.new
|
39
|
+
else
|
40
|
+
RDoc::Markup::ToAnsi.new
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
RDoc::RI.const_set :PryDriver, subclass # hook it up!
|
46
|
+
end
|
47
|
+
|
48
|
+
# Spin-up an RI insance.
|
49
|
+
ri = RDoc::RI::PryDriver.new _pry_.pager, :use_stdout => true, :interactive => false
|
50
|
+
|
51
|
+
begin
|
52
|
+
ri.display_names [spec] # Get the documentation (finally!)
|
53
|
+
rescue RDoc::RI::Driver::NotFoundError => e
|
54
|
+
output.puts "error: '#{e.name}' not found"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
Pry::Commands.add_command(Pry::Command::Ri)
|
60
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'pry/commands/code_collector'
|
2
|
+
|
3
|
+
class Pry
|
4
|
+
class Command::SaveFile < Pry::ClassCommand
|
5
|
+
match 'save-file'
|
6
|
+
group 'Input and Output'
|
7
|
+
description 'Export to a file using content from the REPL.'
|
8
|
+
|
9
|
+
banner <<-'BANNER'
|
10
|
+
Usage: save-file [OPTIONS] --to [FILE]
|
11
|
+
|
12
|
+
Export to a file using content from the REPL.
|
13
|
+
|
14
|
+
save-file my_method --to hello.rb
|
15
|
+
save-file -i 1..10 --to hello.rb --append
|
16
|
+
save-file show-method --to my_command.rb
|
17
|
+
save-file sample_file.rb --lines 2..10 --to output_file.rb
|
18
|
+
BANNER
|
19
|
+
|
20
|
+
def options(opt)
|
21
|
+
CodeCollector.inject_options(opt)
|
22
|
+
|
23
|
+
opt.on :to=, "Specify the output file path"
|
24
|
+
opt.on :a, :append, "Append output to file"
|
25
|
+
end
|
26
|
+
|
27
|
+
def process
|
28
|
+
@cc = CodeCollector.new(args, opts, _pry_)
|
29
|
+
raise CommandError, "Found no code to save." if @cc.content.empty?
|
30
|
+
|
31
|
+
if !file_name
|
32
|
+
display_content
|
33
|
+
else
|
34
|
+
save_file
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def file_name
|
39
|
+
opts[:to] || nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def save_file
|
43
|
+
File.open(file_name, mode) do |f|
|
44
|
+
f.puts @cc.content
|
45
|
+
end
|
46
|
+
output.puts "#{file_name} successfully saved"
|
47
|
+
end
|
48
|
+
|
49
|
+
def display_content
|
50
|
+
output.puts @cc.content
|
51
|
+
output.puts "\n\n--\nPlease use `--to FILE` to export to a file."
|
52
|
+
output.puts "No file saved!\n--"
|
53
|
+
end
|
54
|
+
|
55
|
+
def mode
|
56
|
+
opts.present?(:append) ? "a" : "w"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Pry::Commands.add_command(Pry::Command::SaveFile)
|
61
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class Pry
|
2
|
+
class Command::ShellCommand < Pry::ClassCommand
|
3
|
+
match(/\.(.*)/)
|
4
|
+
group 'Input and Output'
|
5
|
+
description "All text following a '.' is forwarded to the shell."
|
6
|
+
command_options :listing => '.<shell command>', :use_prefix => false,
|
7
|
+
:takes_block => true
|
8
|
+
|
9
|
+
banner <<-'BANNER'
|
10
|
+
Usage: .COMMAND_NAME
|
11
|
+
|
12
|
+
All text following a "." is forwarded to the shell.
|
13
|
+
|
14
|
+
.ls -aF
|
15
|
+
.uname
|
16
|
+
BANNER
|
17
|
+
|
18
|
+
def process(cmd)
|
19
|
+
if cmd =~ /^cd\s*(.*)/i
|
20
|
+
process_cd parse_destination($1)
|
21
|
+
else
|
22
|
+
pass_block(cmd)
|
23
|
+
if command_block
|
24
|
+
command_block.call `#{cmd}`
|
25
|
+
else
|
26
|
+
_pry_.config.system.call(output, cmd, _pry_)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def parse_destination(dest)
|
34
|
+
return "~" if dest.empty?
|
35
|
+
return dest unless dest == "-"
|
36
|
+
state.old_pwd || raise(CommandError, "No prior directory available")
|
37
|
+
end
|
38
|
+
|
39
|
+
def process_cd(dest)
|
40
|
+
state.old_pwd = Dir.pwd
|
41
|
+
Dir.chdir File.expand_path(dest)
|
42
|
+
rescue Errno::ENOENT
|
43
|
+
raise CommandError, "No such directory: #{dest}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
Pry::Commands.add_command(Pry::Command::ShellCommand)
|
48
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Pry
|
2
|
+
class Command::ShellMode < Pry::ClassCommand
|
3
|
+
match 'shell-mode'
|
4
|
+
group 'Input and Output'
|
5
|
+
description 'Toggle shell mode. Bring in pwd prompt and file completion.'
|
6
|
+
|
7
|
+
banner <<-'BANNER'
|
8
|
+
Toggle shell mode. Bring in pwd prompt and file completion.
|
9
|
+
BANNER
|
10
|
+
|
11
|
+
def process
|
12
|
+
case _pry_.prompt
|
13
|
+
when Pry::SHELL_PROMPT
|
14
|
+
_pry_.pop_prompt
|
15
|
+
_pry_.custom_completions = _pry_.config.file_completions
|
16
|
+
else
|
17
|
+
_pry_.push_prompt Pry::SHELL_PROMPT
|
18
|
+
_pry_.custom_completions = _pry_.config.command_completions
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Pry::Commands.add_command(Pry::Command::ShellMode)
|
24
|
+
Pry::Commands.alias_command 'file-mode', 'shell-mode'
|
25
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'pry/commands/show_info'
|
2
|
+
|
3
|
+
class Pry
|
4
|
+
class Command::ShowDoc < Command::ShowInfo
|
5
|
+
include Pry::Helpers::DocumentationHelpers
|
6
|
+
|
7
|
+
match 'show-doc'
|
8
|
+
group 'Introspection'
|
9
|
+
description 'Show the documentation for a method or class.'
|
10
|
+
|
11
|
+
banner <<-BANNER
|
12
|
+
Usage: show-doc [OPTIONS] [METH]
|
13
|
+
Aliases: ?
|
14
|
+
|
15
|
+
Show the documentation for a method or class. Tries instance methods first and
|
16
|
+
then methods by default.
|
17
|
+
|
18
|
+
show-doc hi_method # docs for hi_method
|
19
|
+
show-doc Pry # for Pry class
|
20
|
+
show-doc Pry -a # for all definitions of Pry class (all monkey patches)
|
21
|
+
BANNER
|
22
|
+
|
23
|
+
# The docs for code_object prepared for display.
|
24
|
+
def content_for(code_object)
|
25
|
+
Code.new(render_doc_markup_for(code_object),
|
26
|
+
start_line_for(code_object), :text).
|
27
|
+
with_line_numbers(use_line_numbers?).to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
# process the markup (if necessary) and apply colors
|
31
|
+
def render_doc_markup_for(code_object)
|
32
|
+
docs = docs_for(code_object)
|
33
|
+
|
34
|
+
if code_object.command?
|
35
|
+
# command '--help' shouldn't use markup highlighting
|
36
|
+
docs
|
37
|
+
else
|
38
|
+
if docs.empty?
|
39
|
+
raise CommandError, "No docs found for: #{
|
40
|
+
obj_name ? obj_name : 'current context'
|
41
|
+
}"
|
42
|
+
end
|
43
|
+
process_comment_markup(docs)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Return docs for the code_object, adjusting for whether the code_object
|
48
|
+
# has yard docs available, in which case it returns those.
|
49
|
+
# (note we only have to check yard docs for modules since they can
|
50
|
+
# have multiple docs, but methods can only be doc'd once so we
|
51
|
+
# dont need to check them)
|
52
|
+
def docs_for(code_object)
|
53
|
+
if code_object.module_with_yard_docs?
|
54
|
+
# yard docs
|
55
|
+
code_object.yard_doc
|
56
|
+
else
|
57
|
+
# normal docs (i.e comments above method/module/command)
|
58
|
+
code_object.doc
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Which sections to include in the 'header', can toggle: :owner,
|
63
|
+
# :signature and visibility.
|
64
|
+
def header_options
|
65
|
+
super.merge :signature => true
|
66
|
+
end
|
67
|
+
|
68
|
+
# figure out start line of docs by back-calculating based on
|
69
|
+
# number of lines in the comment and the start line of the code_object
|
70
|
+
# @return [Fixnum] start line of docs
|
71
|
+
def start_line_for(code_object)
|
72
|
+
if code_object.command? || opts.present?(:'base-one')
|
73
|
+
1
|
74
|
+
else
|
75
|
+
code_object.source_line.nil? ? 1 :
|
76
|
+
(code_object.source_line - code_object.doc.lines.count)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
Pry::Commands.add_command(Pry::Command::ShowDoc)
|
82
|
+
Pry::Commands.alias_command '?', 'show-doc'
|
83
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
class Pry
|
2
|
+
class Command::ShowInfo < Pry::ClassCommand
|
3
|
+
extend Pry::Helpers::BaseHelpers
|
4
|
+
|
5
|
+
command_options :shellwords => false, :interpolate => false
|
6
|
+
|
7
|
+
def options(opt)
|
8
|
+
opt.on :s, :super, "Select the 'super' method. Can be repeated to traverse the ancestors", :as => :count
|
9
|
+
opt.on :l, "line-numbers", "Show line numbers"
|
10
|
+
opt.on :b, "base-one", "Show line numbers but start numbering at 1 (useful for `amend-line` and `play` commands)"
|
11
|
+
opt.on :a, :all, "Show all definitions and monkeypatches of the module/class"
|
12
|
+
end
|
13
|
+
|
14
|
+
def process
|
15
|
+
code_object = Pry::CodeObject.lookup(obj_name, _pry_, :super => opts[:super])
|
16
|
+
raise CommandError, no_definition_message if !code_object
|
17
|
+
@original_code_object = code_object
|
18
|
+
|
19
|
+
if show_all_modules?(code_object)
|
20
|
+
# show all monkey patches for a module
|
21
|
+
|
22
|
+
result = content_and_headers_for_all_module_candidates(code_object)
|
23
|
+
else
|
24
|
+
# show a specific code object
|
25
|
+
co = code_object_with_accessible_source(code_object)
|
26
|
+
result = content_and_header_for_code_object(co)
|
27
|
+
end
|
28
|
+
|
29
|
+
set_file_and_dir_locals(code_object.source_file)
|
30
|
+
_pry_.pager.page result
|
31
|
+
end
|
32
|
+
|
33
|
+
# This method checks whether the `code_object` is a WrappedModule,
|
34
|
+
# if it is, then it returns the first candidate (monkeypatch) with
|
35
|
+
# accessible source (or docs). If `code_object` is not a WrappedModule (i.e a
|
36
|
+
# method or a command) then the `code_object` itself is just
|
37
|
+
# returned.
|
38
|
+
#
|
39
|
+
# @return [Pry::WrappedModule, Pry::Method, Pry::Command]
|
40
|
+
def code_object_with_accessible_source(code_object)
|
41
|
+
if code_object.is_a?(WrappedModule)
|
42
|
+
candidate = code_object.candidates.find(&:source)
|
43
|
+
if candidate
|
44
|
+
return candidate
|
45
|
+
else
|
46
|
+
raise CommandError, no_definition_message if !valid_superclass?(code_object)
|
47
|
+
|
48
|
+
@used_super = true
|
49
|
+
code_object_with_accessible_source(code_object.super)
|
50
|
+
end
|
51
|
+
else
|
52
|
+
code_object
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def valid_superclass?(code_object)
|
57
|
+
code_object.super && code_object.super.wrapped != Object
|
58
|
+
end
|
59
|
+
|
60
|
+
def content_and_header_for_code_object(code_object)
|
61
|
+
header(code_object) << content_for(code_object)
|
62
|
+
end
|
63
|
+
|
64
|
+
def content_and_headers_for_all_module_candidates(mod)
|
65
|
+
result = "Found #{mod.number_of_candidates} candidates for `#{mod.name}` definition:\n"
|
66
|
+
mod.number_of_candidates.times do |v|
|
67
|
+
candidate = mod.candidate(v)
|
68
|
+
begin
|
69
|
+
result << "\nCandidate #{v+1}/#{mod.number_of_candidates}: #{candidate.source_file} @ line #{candidate.source_line}:\n"
|
70
|
+
content = content_for(candidate)
|
71
|
+
|
72
|
+
result << "Number of lines: #{content.lines.count}\n\n" << content
|
73
|
+
rescue Pry::RescuableException
|
74
|
+
result << "\nNo content found.\n"
|
75
|
+
next
|
76
|
+
end
|
77
|
+
end
|
78
|
+
result
|
79
|
+
end
|
80
|
+
|
81
|
+
def no_definition_message
|
82
|
+
"Couldn't locate a definition for #{obj_name}!"
|
83
|
+
end
|
84
|
+
|
85
|
+
# Generate a header (meta-data information) for all the code
|
86
|
+
# object types: methods, modules, commands, procs...
|
87
|
+
def header(code_object)
|
88
|
+
file_name, line_num = file_and_line_for(code_object)
|
89
|
+
h = "\n#{Pry::Helpers::Text.bold('From:')} #{file_name} "
|
90
|
+
h << code_object_header(code_object, line_num)
|
91
|
+
h << "\n#{Pry::Helpers::Text.bold('Number of lines:')} " <<
|
92
|
+
"#{content_for(code_object).lines.count}\n\n"
|
93
|
+
h << Helpers::Text.bold('** Warning:') << " Cannot find code for #{@original_code_object.nonblank_name}. Showing superclass #{code_object.nonblank_name} instead. **\n\n" if @used_super
|
94
|
+
h
|
95
|
+
end
|
96
|
+
|
97
|
+
def code_object_header(code_object, line_num)
|
98
|
+
if code_object.real_method_object?
|
99
|
+
method_header(code_object, line_num)
|
100
|
+
|
101
|
+
# It sucks we have to test for both Pry::WrappedModule and WrappedModule::Candidate,
|
102
|
+
# probably indicates a deep refactor needs to happen in those classes.
|
103
|
+
elsif code_object.is_a?(Pry::WrappedModule) || code_object.is_a?(Pry::WrappedModule::Candidate)
|
104
|
+
module_header(code_object, line_num)
|
105
|
+
else
|
106
|
+
""
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def method_header(code_object, line_num)
|
111
|
+
h = ""
|
112
|
+
h << (code_object.c_method? ? "(C Method):" : "@ line #{line_num}:")
|
113
|
+
h << method_sections(code_object)[:owner]
|
114
|
+
h << method_sections(code_object)[:visibility]
|
115
|
+
h << method_sections(code_object)[:signature]
|
116
|
+
h
|
117
|
+
end
|
118
|
+
|
119
|
+
def module_header(code_object, line_num)
|
120
|
+
h = ""
|
121
|
+
h << "@ line #{line_num}:\n"
|
122
|
+
h << text.bold(code_object.module? ? "Module" : "Class")
|
123
|
+
h << " #{text.bold('name:')} #{code_object.nonblank_name}"
|
124
|
+
|
125
|
+
if code_object.number_of_candidates > 1
|
126
|
+
h << (text.bold("\nNumber of monkeypatches: ") << code_object.number_of_candidates.to_s)
|
127
|
+
h << ". Use the `-a` option to display all available monkeypatches"
|
128
|
+
end
|
129
|
+
h
|
130
|
+
end
|
131
|
+
|
132
|
+
def method_sections(code_object)
|
133
|
+
{
|
134
|
+
:owner => "\n#{text.bold("Owner:")} #{code_object.owner || "N/A"}\n",
|
135
|
+
:visibility => "#{text.bold("Visibility:")} #{code_object.visibility}",
|
136
|
+
:signature => "\n#{text.bold("Signature:")} #{code_object.signature}"
|
137
|
+
}.merge(header_options) { |key, old, new| (new && old).to_s }
|
138
|
+
end
|
139
|
+
|
140
|
+
def header_options
|
141
|
+
{
|
142
|
+
:owner => true,
|
143
|
+
:visibility => true,
|
144
|
+
:signature => nil
|
145
|
+
}
|
146
|
+
end
|
147
|
+
|
148
|
+
def show_all_modules?(code_object)
|
149
|
+
code_object.is_a?(Pry::WrappedModule) && opts.present?(:all)
|
150
|
+
end
|
151
|
+
|
152
|
+
def obj_name
|
153
|
+
@obj_name ||= args.empty? ? nil : args.join(' ')
|
154
|
+
end
|
155
|
+
|
156
|
+
def use_line_numbers?
|
157
|
+
opts.present?(:b) || opts.present?(:l)
|
158
|
+
end
|
159
|
+
|
160
|
+
def start_line_for(code_object)
|
161
|
+
if opts.present?(:'base-one')
|
162
|
+
1
|
163
|
+
else
|
164
|
+
code_object.source_line || 1
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# takes into account possible yard docs, and returns yard_file / yard_line
|
169
|
+
# Also adjusts for start line of comments (using start_line_for), which it has to infer
|
170
|
+
# by subtracting number of lines of comment from start line of code_object
|
171
|
+
def file_and_line_for(code_object)
|
172
|
+
if code_object.module_with_yard_docs?
|
173
|
+
[code_object.yard_file, code_object.yard_line]
|
174
|
+
else
|
175
|
+
[code_object.source_file, start_line_for(code_object)]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def complete(input)
|
180
|
+
if input =~ /([^ ]*)#([a-z0-9_]*)\z/
|
181
|
+
prefix, search = [$1, $2]
|
182
|
+
methods = begin
|
183
|
+
Pry::Method.all_from_class(binding.eval(prefix))
|
184
|
+
rescue RescuableException
|
185
|
+
return super
|
186
|
+
end
|
187
|
+
methods.map do |method|
|
188
|
+
[prefix, method.name].join('#') if method.name.start_with?(search)
|
189
|
+
end.compact
|
190
|
+
else
|
191
|
+
super
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|