pry 0.10.pre.1-java → 0.10.0.pre2-java
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 +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 +126 -182
- 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
|