pry 0.10.pre.1-i386-mswin32 → 0.10.0.pre3-i386-mswin32
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +702 -0
- data/LICENSE +2 -2
- data/{README.markdown → README.md} +41 -35
- data/lib/pry.rb +82 -139
- data/lib/pry/cli.rb +77 -30
- data/lib/pry/code.rb +122 -183
- 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 +184 -28
- data/lib/pry/command_set.rb +113 -59
- data/lib/pry/commands.rb +4 -27
- 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 +20 -229
- 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 +59 -38
- data/lib/pry/editor.rb +133 -0
- data/lib/pry/exceptions.rb +77 -0
- data/lib/pry/helpers.rb +1 -0
- data/lib/pry/helpers/base_helpers.rb +40 -154
- data/lib/pry/helpers/command_helpers.rb +19 -130
- data/lib/pry/helpers/documentation_helpers.rb +21 -11
- data/lib/pry/helpers/table.rb +109 -0
- data/lib/pry/helpers/text.rb +8 -9
- data/lib/pry/history.rb +61 -45
- data/lib/pry/history_array.rb +11 -1
- data/lib/pry/hooks.rb +10 -32
- data/lib/pry/indent.rb +110 -38
- 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 +199 -200
- 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 +39 -33
- 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 +4 -3
- data/lib/pry/prompt.rb +26 -0
- data/lib/pry/pry_class.rb +199 -227
- data/lib/pry/pry_instance.rb +344 -403
- data/lib/pry/rbx_path.rb +1 -1
- data/lib/pry/repl.rb +202 -0
- data/lib/pry/repl_file_loader.rb +20 -26
- 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 +1 -1
- data/lib/pry/wrapped_module.rb +133 -48
- metadata +132 -197
- data/.document +0 -2
- data/.gemtest +0 -0
- data/.gitignore +0 -16
- data/.travis.yml +0 -17
- data/.yardopts +0 -1
- data/CHANGELOG +0 -387
- data/CONTRIBUTORS +0 -36
- data/Gemfile +0 -2
- data/Rakefile +0 -137
- data/TODO +0 -117
- data/examples/example_basic.rb +0 -15
- data/examples/example_command_override.rb +0 -32
- data/examples/example_commands.rb +0 -36
- data/examples/example_hooks.rb +0 -9
- data/examples/example_image_edit.rb +0 -67
- data/examples/example_input.rb +0 -7
- data/examples/example_input2.rb +0 -29
- data/examples/example_output.rb +0 -11
- data/examples/example_print.rb +0 -6
- data/examples/example_prompt.rb +0 -9
- data/examples/helper.rb +0 -6
- data/lib/pry/completion.rb +0 -221
- data/lib/pry/custom_completions.rb +0 -6
- data/lib/pry/default_commands/cd.rb +0 -81
- data/lib/pry/default_commands/commands.rb +0 -62
- data/lib/pry/default_commands/context.rb +0 -98
- data/lib/pry/default_commands/easter_eggs.rb +0 -95
- data/lib/pry/default_commands/editing.rb +0 -420
- data/lib/pry/default_commands/find_method.rb +0 -169
- data/lib/pry/default_commands/gems.rb +0 -84
- data/lib/pry/default_commands/gist.rb +0 -187
- data/lib/pry/default_commands/help.rb +0 -127
- data/lib/pry/default_commands/hist.rb +0 -120
- data/lib/pry/default_commands/input_and_output.rb +0 -306
- data/lib/pry/default_commands/introspection.rb +0 -410
- data/lib/pry/default_commands/ls.rb +0 -272
- data/lib/pry/default_commands/misc.rb +0 -38
- data/lib/pry/default_commands/navigating_pry.rb +0 -110
- data/lib/pry/default_commands/whereami.rb +0 -92
- data/lib/pry/extended_commands/experimental.rb +0 -7
- data/lib/pry/rbx_method.rb +0 -13
- data/man/pry.1 +0 -195
- data/man/pry.1.html +0 -204
- data/man/pry.1.ronn +0 -141
- data/pry.gemspec +0 -46
- data/test/candidate_helper1.rb +0 -11
- data/test/candidate_helper2.rb +0 -8
- data/test/helper.rb +0 -223
- data/test/test_cli.rb +0 -78
- data/test/test_code.rb +0 -201
- data/test/test_command.rb +0 -712
- data/test/test_command_helpers.rb +0 -9
- data/test/test_command_integration.rb +0 -668
- data/test/test_command_set.rb +0 -610
- data/test/test_completion.rb +0 -62
- data/test/test_control_d_handler.rb +0 -45
- data/test/test_default_commands/example.erb +0 -5
- data/test/test_default_commands/test_cd.rb +0 -318
- data/test/test_default_commands/test_context.rb +0 -280
- data/test/test_default_commands/test_documentation.rb +0 -314
- data/test/test_default_commands/test_find_method.rb +0 -50
- data/test/test_default_commands/test_gems.rb +0 -18
- data/test/test_default_commands/test_help.rb +0 -57
- data/test/test_default_commands/test_input.rb +0 -428
- data/test/test_default_commands/test_introspection.rb +0 -511
- data/test/test_default_commands/test_ls.rb +0 -151
- data/test/test_default_commands/test_shell.rb +0 -343
- data/test/test_default_commands/test_show_source.rb +0 -432
- data/test/test_exception_whitelist.rb +0 -21
- data/test/test_history_array.rb +0 -65
- data/test/test_hooks.rb +0 -521
- data/test/test_indent.rb +0 -277
- data/test/test_input_stack.rb +0 -86
- data/test/test_method.rb +0 -401
- data/test/test_pry.rb +0 -463
- data/test/test_pry_defaults.rb +0 -419
- data/test/test_pry_history.rb +0 -84
- data/test/test_pry_output.rb +0 -41
- data/test/test_sticky_locals.rb +0 -155
- data/test/test_syntax_checking.rb +0 -65
- data/test/test_wrapped_module.rb +0 -174
- data/test/testrc +0 -2
- data/test/testrcbad +0 -2
- data/wiki/Customizing-pry.md +0 -397
- data/wiki/Home.md +0 -4
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
class Pry
|
4
|
+
# There is one InputLock per input (such as STDIN) as two REPLs on the same
|
5
|
+
# input makes things delirious. InputLock serializes accesses to the input so
|
6
|
+
# that threads to not conflict with each other. The latest thread to request
|
7
|
+
# ownership of the input wins.
|
8
|
+
class InputLock
|
9
|
+
class Interrupt < Exception; end
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :input_locks
|
13
|
+
attr_accessor :global_lock
|
14
|
+
end
|
15
|
+
|
16
|
+
self.input_locks = {}
|
17
|
+
self.global_lock = Mutex.new
|
18
|
+
|
19
|
+
def self.for(input)
|
20
|
+
# XXX This method leaks memory, as we never unregister an input once we
|
21
|
+
# are done with it. Fortunately, the leak is tiny (or so we hope). In
|
22
|
+
# usual scenarios, we would leak the StringIO that is passed to be
|
23
|
+
# evaluated from the command line.
|
24
|
+
global_lock.synchronize do
|
25
|
+
input_locks[input] ||= Pry::InputLock.new
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
@mutex = Mutex.new
|
31
|
+
@cond = ConditionVariable.new
|
32
|
+
@owners = []
|
33
|
+
@interruptible = false
|
34
|
+
end
|
35
|
+
|
36
|
+
# Adds ourselves to the ownership list. The last one in the list may access
|
37
|
+
# the input through interruptible_region().
|
38
|
+
def __with_ownership(&block)
|
39
|
+
@mutex.synchronize do
|
40
|
+
# Three cases:
|
41
|
+
# 1) There are no owners, in this case we are good to go.
|
42
|
+
# 2) The current owner of the input is not reading the input (it might
|
43
|
+
# just be evaluating some ruby that the user typed).
|
44
|
+
# The current owner will figure out that it cannot go back to reading
|
45
|
+
# the input since we are adding ourselves to the @owners list, which
|
46
|
+
# in turns makes us the current owner.
|
47
|
+
# 3) The owner of the input is in the interruptible region, reading from
|
48
|
+
# the input. It's safe to send an Interrupt exception to interrupt
|
49
|
+
# the owner. It will then proceed like in case 2).
|
50
|
+
# We wait until the owner sets the interruptible flag back
|
51
|
+
# to false, meaning that he's out of the interruptible region.
|
52
|
+
# Note that the owner may receive multiple interrupts since, but that
|
53
|
+
# should be okay (and trying to avoid it is futile anyway).
|
54
|
+
while @interruptible
|
55
|
+
@owners.last.raise Interrupt
|
56
|
+
@cond.wait(@mutex)
|
57
|
+
end
|
58
|
+
@owners << Thread.current
|
59
|
+
end
|
60
|
+
|
61
|
+
block.call
|
62
|
+
|
63
|
+
ensure
|
64
|
+
@mutex.synchronize do
|
65
|
+
# We are releasing any desire to have the input ownership by removing
|
66
|
+
# ourselves from the list.
|
67
|
+
@owners.delete(Thread.current)
|
68
|
+
|
69
|
+
# We need to wake up the thread at the end of the @owners list, but
|
70
|
+
# sadly Ruby doesn't allow us to choose which one we wake up, so we wake
|
71
|
+
# them all up.
|
72
|
+
@cond.broadcast
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def with_ownership(&block)
|
77
|
+
# If we are in a nested with_ownership() call (nested pry context), we do nothing.
|
78
|
+
nested = @mutex.synchronize { @owners.include?(Thread.current) }
|
79
|
+
nested ? block.call : __with_ownership(&block)
|
80
|
+
end
|
81
|
+
|
82
|
+
def enter_interruptible_region
|
83
|
+
@mutex.synchronize do
|
84
|
+
# We patiently wait until we are the owner. This may happen as another
|
85
|
+
# thread calls with_ownership() because of a binding.pry happening in
|
86
|
+
# another thread.
|
87
|
+
@cond.wait(@mutex) until @owners.last == Thread.current
|
88
|
+
|
89
|
+
# We are the legitimate owner of the input. We mark ourselves as
|
90
|
+
# interruptible, so other threads can send us an Interrupt exception
|
91
|
+
# while we are blocking from reading the input.
|
92
|
+
@interruptible = true
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def leave_interruptible_region
|
97
|
+
@mutex.synchronize do
|
98
|
+
# We check if we are still the owner, because we could have received an
|
99
|
+
# Interrupt right after the following @cond.broadcast, making us retry.
|
100
|
+
@interruptible = false if @owners.last == Thread.current
|
101
|
+
@cond.broadcast
|
102
|
+
end
|
103
|
+
rescue Interrupt
|
104
|
+
# We need to guard against a spurious interrupt delivered while we are
|
105
|
+
# trying to acquire the lock (the rescue block is no longer in our scope).
|
106
|
+
retry
|
107
|
+
end
|
108
|
+
|
109
|
+
def interruptible_region(&block)
|
110
|
+
enter_interruptible_region
|
111
|
+
|
112
|
+
# XXX Note that there is a chance that we get the interrupt right after
|
113
|
+
# the readline call succeeded, but we'll never know, and we will retry the
|
114
|
+
# call, discarding that piece of input.
|
115
|
+
block.call
|
116
|
+
|
117
|
+
rescue Interrupt
|
118
|
+
# We were asked to back off. The one requesting the interrupt will be
|
119
|
+
# waiting on the conditional for the interruptible flag to change to false.
|
120
|
+
# Note that there can be some inefficiency, as we could immediately
|
121
|
+
# succeed in enter_interruptible_region(), even before the one requesting
|
122
|
+
# the ownership has the chance to register itself as an owner.
|
123
|
+
# To mitigate the issue, we sleep a little bit.
|
124
|
+
leave_interruptible_region
|
125
|
+
sleep 0.01
|
126
|
+
retry
|
127
|
+
|
128
|
+
ensure
|
129
|
+
leave_interruptible_region
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Pry::Inspector
|
2
|
+
MAP = {
|
3
|
+
"default" => {
|
4
|
+
value: Pry::DEFAULT_PRINT,
|
5
|
+
description: <<-DESCRIPTION.each_line.map(&:lstrip!)
|
6
|
+
The default Pry inspector. It has paging and color support, and uses
|
7
|
+
pretty_inspect when printing an object.
|
8
|
+
DESCRIPTION
|
9
|
+
},
|
10
|
+
|
11
|
+
"simple" => {
|
12
|
+
value: Pry::SIMPLE_PRINT,
|
13
|
+
description: <<-DESCRIPTION.each_line.map(&:lstrip)
|
14
|
+
A simple inspector that uses #puts and #inspect when printing an
|
15
|
+
object. It has no pager, color, or pretty_inspect support.
|
16
|
+
DESCRIPTION
|
17
|
+
},
|
18
|
+
|
19
|
+
"clipped" => {
|
20
|
+
value: Pry::CLIPPED_PRINT,
|
21
|
+
description: <<-DESCRIPTION.each_line.map(&:lstrip)
|
22
|
+
The clipped inspector has the same features as the 'simple' inspector
|
23
|
+
but prints large objects as a smaller string.
|
24
|
+
DESCRIPTION
|
25
|
+
}
|
26
|
+
}
|
27
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
#
|
2
|
+
# {Pry::LastException} is a proxy class who wraps an Exception object for
|
3
|
+
# {Pry#last_exception}. it extends the exception object with methods that
|
4
|
+
# help pry commands be useful.
|
5
|
+
#
|
6
|
+
# the original exception object is not modified and method calls are forwarded
|
7
|
+
# to the wrapped exception object.
|
8
|
+
#
|
9
|
+
class Pry::LastException < BasicObject
|
10
|
+
attr_accessor :bt_index
|
11
|
+
|
12
|
+
def initialize(e)
|
13
|
+
@e = e
|
14
|
+
@bt_index = 0
|
15
|
+
@file, @line = bt_source_location_for(0)
|
16
|
+
end
|
17
|
+
|
18
|
+
def method_missing(name, *args, &block)
|
19
|
+
if @e.respond_to?(name)
|
20
|
+
@e.public_send(name, *args, &block)
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def respond_to_missing?(name, include_private = false)
|
27
|
+
@e.respond_to?(name)
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# @return [String]
|
32
|
+
# returns the path to a file for the current backtrace. see {#bt_index}.
|
33
|
+
#
|
34
|
+
def file
|
35
|
+
@file
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# @return [Fixnum]
|
40
|
+
# returns the line for the current backtrace. see {#bt_index}.
|
41
|
+
#
|
42
|
+
def line
|
43
|
+
@line
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return [Exception]
|
47
|
+
# returns the wrapped exception
|
48
|
+
#
|
49
|
+
def wrapped_exception
|
50
|
+
@e
|
51
|
+
end
|
52
|
+
|
53
|
+
def bt_source_location_for(index)
|
54
|
+
backtrace[index] =~ /(.*):(\d+)/
|
55
|
+
[$1, $2.to_i]
|
56
|
+
end
|
57
|
+
|
58
|
+
def inc_bt_index
|
59
|
+
@bt_index = (@bt_index + 1) % backtrace.size
|
60
|
+
end
|
61
|
+
end
|
data/lib/pry/method.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
1
|
require 'pry/helpers/documentation_helpers'
|
3
2
|
|
4
3
|
class Pry
|
@@ -17,16 +16,21 @@ class Pry
|
|
17
16
|
# This class wraps the normal `Method` and `UnboundMethod` classes
|
18
17
|
# to provide extra functionality useful to Pry.
|
19
18
|
class Method
|
20
|
-
|
19
|
+
require 'pry/method/weird_method_locator'
|
20
|
+
require 'pry/method/disowned'
|
21
|
+
require 'pry/method/patcher'
|
22
|
+
|
23
|
+
extend Helpers::BaseHelpers
|
24
|
+
include Helpers::BaseHelpers
|
21
25
|
include Helpers::DocumentationHelpers
|
26
|
+
include CodeObject::Helpers
|
22
27
|
|
23
28
|
class << self
|
24
29
|
# Given a string representing a method name and optionally a binding to
|
25
30
|
# search in, find and return the requested method wrapped in a `Pry::Method`
|
26
31
|
# instance.
|
27
32
|
#
|
28
|
-
# @param [String
|
29
|
-
# delegate to `from_binding` instead.
|
33
|
+
# @param [String] name The name of the method to retrieve.
|
30
34
|
# @param [Binding] target The context in which to search for the method.
|
31
35
|
# @param [Hash] options
|
32
36
|
# @option options [Boolean] :instance Look for an instance method if `name` doesn't
|
@@ -34,24 +38,30 @@ class Pry
|
|
34
38
|
# @option options [Boolean] :methods Look for a bound/singleton method if `name` doesn't
|
35
39
|
# contain any context.
|
36
40
|
# @return [Pry::Method, nil] A `Pry::Method` instance containing the requested
|
37
|
-
# method, or `nil` if no method could be located matching the parameters.
|
41
|
+
# method, or `nil` if name is `nil` or no method could be located matching the parameters.
|
38
42
|
def from_str(name, target=TOPLEVEL_BINDING, options={})
|
39
43
|
if name.nil?
|
40
|
-
|
44
|
+
nil
|
41
45
|
elsif name.to_s =~ /(.+)\#(\S+)\Z/
|
42
46
|
context, meth_name = $1, $2
|
43
|
-
from_module(target.eval(context), meth_name)
|
44
|
-
elsif name.to_s =~ /(.+)
|
47
|
+
from_module(target.eval(context), meth_name, target)
|
48
|
+
elsif name.to_s =~ /(.+)(\[\])\Z/
|
45
49
|
context, meth_name = $1, $2
|
46
|
-
from_obj(target.eval(context), meth_name)
|
50
|
+
from_obj(target.eval(context), meth_name, target)
|
51
|
+
elsif name.to_s =~ /(.+)(\.|::)(\S+)\Z/
|
52
|
+
context, meth_name = $1, $3
|
53
|
+
from_obj(target.eval(context), meth_name, target)
|
47
54
|
elsif options[:instance]
|
48
|
-
from_module(target.eval("self"), name)
|
55
|
+
from_module(target.eval("self"), name, target)
|
49
56
|
elsif options[:methods]
|
50
|
-
from_obj(target.eval("self"), name)
|
57
|
+
from_obj(target.eval("self"), name, target)
|
51
58
|
else
|
52
59
|
from_str(name, target, :instance => true) or
|
53
60
|
from_str(name, target, :methods => true)
|
54
61
|
end
|
62
|
+
|
63
|
+
rescue Pry::RescuableException
|
64
|
+
nil
|
55
65
|
end
|
56
66
|
|
57
67
|
# Given a `Binding`, try to extract the `::Method` it originated from and
|
@@ -62,59 +72,54 @@ class Pry
|
|
62
72
|
# @return [Pry::Method, nil]
|
63
73
|
#
|
64
74
|
def from_binding(b)
|
65
|
-
meth_name = b.eval('__method__')
|
75
|
+
meth_name = b.eval('::Kernel.__method__')
|
66
76
|
if [:__script__, nil].include?(meth_name)
|
67
77
|
nil
|
68
78
|
else
|
69
79
|
method = begin
|
70
|
-
|
80
|
+
if Object === b.eval('self')
|
81
|
+
new(Kernel.instance_method(:method).bind(b.eval("self")).call(meth_name))
|
82
|
+
else
|
83
|
+
new(b.eval('class << self; self; end.instance_method(::Kernel.__method__).bind(self)'))
|
84
|
+
end
|
71
85
|
rescue NameError, NoMethodError
|
72
86
|
Disowned.new(b.eval('self'), meth_name.to_s)
|
73
87
|
end
|
74
88
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
# class B < A; def b; super; end; end
|
80
|
-
#
|
81
|
-
# Given that we can normally find the source_range of methods, and that we know which
|
82
|
-
# __FILE__ and __LINE__ the binding is at, we can hope to disambiguate these cases.
|
83
|
-
#
|
84
|
-
# This obviously won't work if the source is unavaiable for some reason, or if both
|
85
|
-
# methods have the same __FILE__ and __LINE__, or if we're in rbx where b.eval('__LINE__')
|
86
|
-
# is broken.
|
87
|
-
#
|
88
|
-
guess = method
|
89
|
-
|
90
|
-
while guess
|
91
|
-
# needs rescue if this is a Disowned method or a C method or something...
|
92
|
-
# TODO: Fix up the exception handling so we don't need a bare rescue
|
93
|
-
if (guess.source_file && guess.source_range rescue false) &&
|
94
|
-
File.expand_path(guess.source_file) == File.expand_path(b.eval('__FILE__')) &&
|
95
|
-
guess.source_range.include?(b.eval('__LINE__'))
|
96
|
-
return guess
|
97
|
-
else
|
98
|
-
guess = guess.super
|
99
|
-
end
|
89
|
+
if WeirdMethodLocator.weird_method?(method, b)
|
90
|
+
WeirdMethodLocator.new(method, b).get_method || method
|
91
|
+
else
|
92
|
+
method
|
100
93
|
end
|
101
|
-
|
102
|
-
# Uhoh... none of the methods in the chain had the right __FILE__ and __LINE__
|
103
|
-
# This may be caused by rbx https://github.com/rubinius/rubinius/issues/953,
|
104
|
-
# or other unknown circumstances (TODO: we should warn the user when this happens)
|
105
|
-
method
|
106
94
|
end
|
107
95
|
end
|
108
96
|
|
97
|
+
# In order to support 2.0 Refinements we need to look up methods
|
98
|
+
# inside the relevant Binding.
|
99
|
+
# @param [Object] obj The owner/receiver of the method.
|
100
|
+
# @param [Symbol] method_name The name of the method.
|
101
|
+
# @param [Symbol] method_type The type of method: :method or :instance_method
|
102
|
+
# @param [Binding] target The binding where the method is looked up.
|
103
|
+
# @return [Method, UnboundMethod] The 'refined' method object.
|
104
|
+
def lookup_method_via_binding(obj, method_name, method_type, target=TOPLEVEL_BINDING)
|
105
|
+
Pry.current[:obj] = obj
|
106
|
+
Pry.current[:name] = method_name
|
107
|
+
receiver = obj.is_a?(Module) ? "Module" : "Kernel"
|
108
|
+
target.eval("::#{receiver}.instance_method(:#{method_type}).bind(Pry.current[:obj]).call(Pry.current[:name])")
|
109
|
+
ensure
|
110
|
+
Pry.current[:obj] = Pry.current[:name] = nil
|
111
|
+
end
|
112
|
+
|
109
113
|
# Given a `Class` or `Module` and the name of a method, try to
|
110
114
|
# instantiate a `Pry::Method` containing the instance method of
|
111
115
|
# that name. Return `nil` if no such method exists.
|
112
116
|
#
|
113
117
|
# @param [Class, Module] klass
|
114
118
|
# @param [String] name
|
119
|
+
# @param [Binding] target The binding where the method is looked up.
|
115
120
|
# @return [Pry::Method, nil]
|
116
|
-
def from_class(klass, name)
|
117
|
-
new(
|
121
|
+
def from_class(klass, name, target=TOPLEVEL_BINDING)
|
122
|
+
new(lookup_method_via_binding(klass, name, :instance_method, target)) rescue nil
|
118
123
|
end
|
119
124
|
alias from_module from_class
|
120
125
|
|
@@ -124,9 +129,10 @@ class Pry
|
|
124
129
|
#
|
125
130
|
# @param [Object] obj
|
126
131
|
# @param [String] name
|
132
|
+
# @param [Binding] target The binding where the method is looked up.
|
127
133
|
# @return [Pry::Method, nil]
|
128
|
-
def from_obj(obj, name)
|
129
|
-
new(
|
134
|
+
def from_obj(obj, name, target=TOPLEVEL_BINDING)
|
135
|
+
new(lookup_method_via_binding(obj, name, :method, target)) rescue nil
|
130
136
|
end
|
131
137
|
|
132
138
|
# Get all of the instance methods of a `Class` or `Module`
|
@@ -134,15 +140,34 @@ class Pry
|
|
134
140
|
# @param [Boolean] include_super Whether to include methods from ancestors.
|
135
141
|
# @return [Array[Pry::Method]]
|
136
142
|
def all_from_class(klass, include_super=true)
|
137
|
-
|
143
|
+
%w(public protected private).map do |visibility|
|
144
|
+
safe_send(klass, :"#{visibility}_instance_methods", include_super).map do |method_name|
|
145
|
+
new(safe_send(klass, :instance_method, method_name), :visibility => visibility.to_sym)
|
146
|
+
end
|
147
|
+
end.flatten(1)
|
138
148
|
end
|
139
149
|
|
150
|
+
#
|
140
151
|
# Get all of the methods on an `Object`
|
152
|
+
#
|
141
153
|
# @param [Object] obj
|
142
|
-
#
|
154
|
+
#
|
155
|
+
# @param [Boolean] include_super
|
156
|
+
# indicates whether or not to include methods from ancestors.
|
157
|
+
#
|
143
158
|
# @return [Array[Pry::Method]]
|
159
|
+
#
|
144
160
|
def all_from_obj(obj, include_super=true)
|
145
|
-
|
161
|
+
all_from_class(singleton_class_of(obj), include_super)
|
162
|
+
end
|
163
|
+
|
164
|
+
#
|
165
|
+
# @deprecated
|
166
|
+
# please use {#all_from_obj} instead.
|
167
|
+
# the `method_type` argument is ignored.
|
168
|
+
#
|
169
|
+
def all_from_common(obj, method_type = nil, include_super=true)
|
170
|
+
all_from_obj(obj, include_super)
|
146
171
|
end
|
147
172
|
|
148
173
|
# Get every `Class` and `Module`, in order, that will be checked when looking
|
@@ -153,7 +178,7 @@ class Pry
|
|
153
178
|
if Class === obj
|
154
179
|
singleton_class_resolution_order(obj) + instance_resolution_order(Class)
|
155
180
|
else
|
156
|
-
klass =
|
181
|
+
klass = singleton_class_of(obj) rescue obj.class
|
157
182
|
instance_resolution_order(klass)
|
158
183
|
end
|
159
184
|
end
|
@@ -165,46 +190,42 @@ class Pry
|
|
165
190
|
# @return [Array[Class, Module]]
|
166
191
|
def instance_resolution_order(klass)
|
167
192
|
# include klass in case it is a singleton class,
|
168
|
-
([klass] + klass
|
193
|
+
([klass] + Pry::Method.safe_send(klass, :ancestors)).uniq
|
169
194
|
end
|
170
195
|
|
171
|
-
|
196
|
+
def method_definition?(name, definition_line)
|
197
|
+
singleton_method_definition?(name, definition_line) ||
|
198
|
+
instance_method_definition?(name, definition_line)
|
199
|
+
end
|
172
200
|
|
173
|
-
|
174
|
-
|
175
|
-
# If method_type is :method, obj can be any `Object`
|
176
|
-
#
|
177
|
-
# N.B. we pre-cache the visibility here to avoid O(N²) behaviour in "ls".
|
178
|
-
def all_from_common(obj, method_type, include_super=true)
|
179
|
-
%w(public protected private).map do |visibility|
|
180
|
-
safe_send(obj, :"#{visibility}_#{method_type}s", include_super).map do |method_name|
|
181
|
-
new(safe_send(obj, method_type, method_name), :visibility => visibility.to_sym)
|
182
|
-
end
|
183
|
-
end.flatten(1)
|
201
|
+
def singleton_method_definition?(name, definition_line)
|
202
|
+
/^define_singleton_method\(?\s*[:\"\']#{Regexp.escape(name)}|^def\s*self\.#{Regexp.escape(name)}/ =~ definition_line.strip
|
184
203
|
end
|
185
204
|
|
186
|
-
|
187
|
-
|
188
|
-
# This is required to introspect methods on objects like Net::HTTP::Get that
|
189
|
-
# have overridden the `method` method.
|
190
|
-
def safe_send(obj, method, *args, &block)
|
191
|
-
(Module === obj ? Module : Object).instance_method(method).bind(obj).call(*args, &block)
|
205
|
+
def instance_method_definition?(name, definition_line)
|
206
|
+
/^define_method\(?\s*[:\"\']#{Regexp.escape(name)}|^def\s*#{Regexp.escape(name)}/ =~ definition_line.strip
|
192
207
|
end
|
193
|
-
public :safe_send
|
194
208
|
|
195
209
|
# Get the singleton classes of superclasses that could define methods on
|
196
210
|
# the given class object, and any modules they include.
|
197
211
|
# If a module is included at multiple points in the ancestry, only
|
198
212
|
# the lowest copy will be returned.
|
199
213
|
def singleton_class_resolution_order(klass)
|
200
|
-
|
201
|
-
|
202
|
-
|
214
|
+
ancestors = Pry::Method.safe_send(klass, :ancestors)
|
215
|
+
resolution_order = ancestors.grep(Class).map do |anc|
|
216
|
+
[singleton_class_of(anc), *singleton_class_of(anc).included_modules]
|
217
|
+
end.flatten(1)
|
203
218
|
|
204
219
|
resolution_order.reverse.uniq.reverse - Class.included_modules
|
205
220
|
end
|
206
221
|
|
207
|
-
def
|
222
|
+
def singleton_class_of(obj)
|
223
|
+
begin
|
224
|
+
class << obj; self; end
|
225
|
+
rescue TypeError # can't define singleton. Fixnum, Symbol, Float, ...
|
226
|
+
obj.class
|
227
|
+
end
|
228
|
+
end
|
208
229
|
end
|
209
230
|
|
210
231
|
# A new instance of `Pry::Method` wrapping the given `::Method`, `UnboundMethod`, or `Proc`.
|
@@ -229,6 +250,12 @@ class Pry
|
|
229
250
|
@wrapped_owner ||= Pry::WrappedModule.new(owner)
|
230
251
|
end
|
231
252
|
|
253
|
+
# Get underlying object wrapped by this Pry::Method instance
|
254
|
+
# @return [Method, UnboundMethod, Proc]
|
255
|
+
def wrapped
|
256
|
+
@method
|
257
|
+
end
|
258
|
+
|
232
259
|
# Is the method undefined? (aka `Disowned`)
|
233
260
|
# @return [Boolean] false
|
234
261
|
def undefined?
|
@@ -248,26 +275,18 @@ class Pry
|
|
248
275
|
def source
|
249
276
|
@source ||= case source_type
|
250
277
|
when :c
|
251
|
-
|
252
|
-
if info and info.source
|
253
|
-
code = strip_comments_from_c_code(info.source)
|
254
|
-
end
|
278
|
+
c_source
|
255
279
|
when :ruby
|
256
|
-
|
257
|
-
# hacked version of source_location for rbx core methods, and
|
258
|
-
# our input buffer for methods defined in (pry)
|
259
|
-
file, line = *source_location
|
260
|
-
raise SourceNotFoundError, "Could not locate source for #{name_with_owner}!" unless file
|
261
|
-
|
262
|
-
begin
|
263
|
-
code = Pry::Code.from_file(file).expression_at(line)
|
264
|
-
rescue SyntaxError => e
|
265
|
-
raise MethodSource::SourceNotFoundError.new(e.message)
|
266
|
-
end
|
267
|
-
strip_leading_whitespace(code)
|
280
|
+
ruby_source
|
268
281
|
end
|
269
282
|
end
|
270
283
|
|
284
|
+
# Update the live copy of the method's source.
|
285
|
+
def redefine(source)
|
286
|
+
Patcher.new(self).patch_in_ram source
|
287
|
+
Pry::Method(owner.instance_method(name))
|
288
|
+
end
|
289
|
+
|
271
290
|
# Can we get the source code for this method?
|
272
291
|
# @return [Boolean]
|
273
292
|
def source?
|
@@ -278,20 +297,13 @@ class Pry
|
|
278
297
|
|
279
298
|
# @return [String, nil] The documentation for the method, or `nil` if it's
|
280
299
|
# unavailable.
|
281
|
-
# @raise [CommandError] Raises when the method was defined in the REPL.
|
282
300
|
def doc
|
283
301
|
@doc ||= case source_type
|
284
302
|
when :c
|
285
303
|
info = pry_doc_info
|
286
304
|
info.docstring if info
|
287
305
|
when :ruby
|
288
|
-
|
289
|
-
strip_leading_hash_and_whitespace_from_ruby_comments(core_doc)
|
290
|
-
elsif pry_method?
|
291
|
-
strip_leading_hash_and_whitespace_from_ruby_comments(doc_for_pry_method)
|
292
|
-
else
|
293
|
-
strip_leading_hash_and_whitespace_from_ruby_comments(@method.comment)
|
294
|
-
end
|
306
|
+
get_comment_content(comment)
|
295
307
|
end
|
296
308
|
end
|
297
309
|
|
@@ -301,20 +313,11 @@ class Pry
|
|
301
313
|
source_location.nil? ? :c : :ruby
|
302
314
|
end
|
303
315
|
|
304
|
-
def source_location
|
305
|
-
if @method.source_location && Helpers::BaseHelpers.rbx?
|
306
|
-
file, line = @method.source_location
|
307
|
-
[RbxPath.convert_path_to_full(file), line]
|
308
|
-
else
|
309
|
-
@method.source_location
|
310
|
-
end
|
311
|
-
end
|
312
|
-
|
313
316
|
# @return [String, nil] The name of the file the method is defined in, or
|
314
317
|
# `nil` if the filename is unavailable.
|
315
318
|
def source_file
|
316
319
|
if source_location.nil?
|
317
|
-
if !
|
320
|
+
if !rbx? and source_type == :c
|
318
321
|
info = pry_doc_info
|
319
322
|
info.file if info
|
320
323
|
end
|
@@ -398,11 +401,43 @@ class Pry
|
|
398
401
|
!!(source_file and source_file =~ /(\(.*\))|<.*>/)
|
399
402
|
end
|
400
403
|
|
404
|
+
# @return [Boolean] Whether the method is unbound.
|
405
|
+
def unbound_method?
|
406
|
+
is_a?(::UnboundMethod)
|
407
|
+
end
|
408
|
+
|
409
|
+
# @return [Boolean] Whether the method is bound.
|
410
|
+
def bound_method?
|
411
|
+
is_a?(::Method)
|
412
|
+
end
|
413
|
+
|
414
|
+
# @return [Boolean] Whether the method is a singleton method.
|
415
|
+
def singleton_method?
|
416
|
+
wrapped_owner.singleton_class?
|
417
|
+
end
|
418
|
+
|
401
419
|
# @return [Boolean] Was the method defined within the Pry REPL?
|
402
420
|
def pry_method?
|
403
421
|
source_file == Pry.eval_path
|
404
422
|
end
|
405
423
|
|
424
|
+
# @return [Array<String>] All known aliases for the method.
|
425
|
+
def aliases
|
426
|
+
owner = @method.owner
|
427
|
+
# Avoid using `to_sym` on {Method#name}, which returns a `String`, because
|
428
|
+
# it won't be garbage collected.
|
429
|
+
name = @method.name
|
430
|
+
|
431
|
+
all_methods_to_compare = owner.instance_methods | owner.private_instance_methods
|
432
|
+
alias_list = all_methods_to_compare.combination(2).select do |pair|
|
433
|
+
pair.include?(name) &&
|
434
|
+
owner.instance_method(pair.first) == owner.instance_method(pair.last)
|
435
|
+
end.flatten
|
436
|
+
alias_list.delete(name)
|
437
|
+
|
438
|
+
alias_list.map(&:to_s)
|
439
|
+
end
|
440
|
+
|
406
441
|
# @return [Boolean] Is the method definitely an alias?
|
407
442
|
def alias?
|
408
443
|
name != original_name
|
@@ -435,113 +470,77 @@ class Pry
|
|
435
470
|
@method.send(method_name, *args, &block)
|
436
471
|
end
|
437
472
|
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
def pry_doc_info
|
442
|
-
if Pry.config.has_pry_doc
|
443
|
-
Pry::MethodInfo.info_for(@method) or raise CommandError, "Cannot locate this method: #{name}. (source_location returns nil)"
|
444
|
-
else
|
445
|
-
raise CommandError, "Cannot locate this method: #{name}. Try `gem install pry-doc` to get access to Ruby Core documentation."
|
446
|
-
end
|
447
|
-
end
|
448
|
-
|
449
|
-
# FIXME: a very similar method to this exists on WrappedModule: extract_doc_for_candidate
|
450
|
-
def doc_for_pry_method
|
451
|
-
_, line_num = source_location
|
452
|
-
|
453
|
-
buffer = ""
|
454
|
-
Pry.line_buffer[0..(line_num - 1)].each do |line|
|
455
|
-
# Add any line that is a valid ruby comment,
|
456
|
-
# but clear as soon as we hit a non comment line.
|
457
|
-
if (line =~ /^\s*#/) || (line =~ /^\s*$/)
|
458
|
-
buffer << line.lstrip
|
459
|
-
else
|
460
|
-
buffer.replace("")
|
461
|
-
end
|
462
|
-
end
|
473
|
+
def comment
|
474
|
+
Pry::Code.from_file(source_file).comment_describing(source_line)
|
475
|
+
end
|
463
476
|
|
464
|
-
|
465
|
-
end
|
477
|
+
private
|
466
478
|
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
next_owner = ancestors[i] or return nil
|
479
|
+
# @return [YARD::CodeObjects::MethodObject]
|
480
|
+
# @raise [CommandError] when the method can't be found or `pry-doc` isn't installed.
|
481
|
+
def pry_doc_info
|
482
|
+
if Pry.config.has_pry_doc
|
483
|
+
Pry::MethodInfo.info_for(@method) or raise CommandError, "Cannot locate this method: #{name}. (source_location returns nil)"
|
484
|
+
else
|
485
|
+
fail_msg = "Cannot locate this method: #{name}."
|
486
|
+
if mri?
|
487
|
+
fail_msg += ' Try `gem-install pry-doc` to get access to Ruby Core documentation.'
|
477
488
|
end
|
478
|
-
|
489
|
+
raise CommandError, fail_msg
|
479
490
|
end
|
491
|
+
end
|
480
492
|
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
if t2.last == :method || t2.last == :ident && t1 == [".", :operator]
|
490
|
-
return t2.first
|
491
|
-
end
|
493
|
+
# @param [Class, Module] ancestors The ancestors to investigate
|
494
|
+
# @return [Method] The unwrapped super-method
|
495
|
+
def super_using_ancestors(ancestors, times=1)
|
496
|
+
next_owner = self.owner
|
497
|
+
times.times do
|
498
|
+
i = ancestors.index(next_owner) + 1
|
499
|
+
while ancestors[i] && !(ancestors[i].method_defined?(name) || ancestors[i].private_method_defined?(name))
|
500
|
+
i += 1
|
492
501
|
end
|
493
|
-
|
494
|
-
nil
|
502
|
+
next_owner = ancestors[i] or return nil
|
495
503
|
end
|
496
504
|
|
497
|
-
|
498
|
-
|
499
|
-
# e.g.
|
500
|
-
# class C
|
501
|
-
# def foo
|
502
|
-
# C.send(:undefine_method, :foo)
|
503
|
-
# Pry::Method.from_binding(binding)
|
504
|
-
# end
|
505
|
-
# end
|
506
|
-
#
|
507
|
-
# In this case we assume that the "owner" is the singleton class of the receiver.
|
508
|
-
#
|
509
|
-
# This occurs mainly in Sinatra applications.
|
510
|
-
class Disowned < Method
|
511
|
-
attr_reader :receiver, :name
|
505
|
+
safe_send(next_owner, :instance_method, name) rescue nil
|
506
|
+
end
|
512
507
|
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
def initialize(receiver, method_name)
|
518
|
-
@receiver, @name = receiver, method_name
|
519
|
-
end
|
508
|
+
# @param [String] first_ln The first line of a method definition.
|
509
|
+
# @return [String, nil]
|
510
|
+
def method_name_from_first_line(first_ln)
|
511
|
+
return nil if first_ln.strip !~ /^def /
|
520
512
|
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
513
|
+
tokens = CodeRay.scan(first_ln, :ruby)
|
514
|
+
tokens = tokens.tokens.each_slice(2) if tokens.respond_to?(:tokens)
|
515
|
+
tokens.each_cons(2) do |t1, t2|
|
516
|
+
if t2.last == :method || t2.last == :ident && t1 == [".", :operator]
|
517
|
+
return t2.first
|
518
|
+
end
|
525
519
|
end
|
526
520
|
|
527
|
-
|
528
|
-
|
529
|
-
def source?
|
530
|
-
false
|
531
|
-
end
|
521
|
+
nil
|
522
|
+
end
|
532
523
|
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
class << receiver; self; end
|
524
|
+
def c_source
|
525
|
+
info = pry_doc_info
|
526
|
+
if info and info.source
|
527
|
+
strip_comments_from_c_code(info.source)
|
538
528
|
end
|
529
|
+
end
|
539
530
|
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
531
|
+
def ruby_source
|
532
|
+
# clone of MethodSource.source_helper that knows to use our
|
533
|
+
# hacked version of source_location for rbx core methods, and
|
534
|
+
# our input buffer for methods defined in (pry)
|
535
|
+
file, line = *source_location
|
536
|
+
raise SourceNotFoundError, "Could not locate source for #{name_with_owner}!" unless file
|
537
|
+
|
538
|
+
begin
|
539
|
+
code = Pry::Code.from_file(file).expression_at(line)
|
540
|
+
rescue SyntaxError => e
|
541
|
+
raise MethodSource::SourceNotFoundError.new(e.message)
|
544
542
|
end
|
543
|
+
strip_leading_whitespace(code)
|
545
544
|
end
|
546
545
|
end
|
547
546
|
end
|