pry 0.9.12.6-i386-mingw32 → 0.10.0-i386-mingw32
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 +4 -4
- data/CHANGELOG.md +702 -0
- data/LICENSE +2 -2
- data/{README.markdown → README.md} +37 -31
- data/lib/pry.rb +38 -151
- data/lib/pry/cli.rb +35 -17
- data/lib/pry/code.rb +19 -63
- data/lib/pry/code/code_file.rb +103 -0
- data/lib/pry/code/code_range.rb +2 -1
- data/lib/pry/code/loc.rb +2 -2
- data/lib/pry/code_object.rb +40 -21
- data/lib/pry/color_printer.rb +55 -0
- data/lib/pry/command.rb +12 -9
- data/lib/pry/command_set.rb +81 -38
- data/lib/pry/commands.rb +1 -1
- data/lib/pry/commands/amend_line.rb +2 -2
- data/lib/pry/commands/bang.rb +1 -1
- data/lib/pry/commands/cat.rb +11 -2
- data/lib/pry/commands/cat/exception_formatter.rb +6 -7
- data/lib/pry/commands/cat/file_formatter.rb +15 -32
- data/lib/pry/commands/cat/input_expression_formatter.rb +1 -1
- data/lib/pry/commands/cd.rb +14 -3
- 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 +4 -4
- data/lib/pry/commands/easter_eggs.rb +3 -3
- data/lib/pry/commands/edit.rb +10 -22
- data/lib/pry/commands/edit/exception_patcher.rb +2 -2
- data/lib/pry/commands/edit/file_and_line_locator.rb +0 -2
- data/lib/pry/commands/exit_program.rb +0 -1
- data/lib/pry/commands/find_method.rb +16 -22
- data/lib/pry/commands/gem_install.rb +5 -2
- data/lib/pry/commands/gem_open.rb +1 -1
- data/lib/pry/commands/gist.rb +10 -11
- data/lib/pry/commands/help.rb +14 -14
- data/lib/pry/commands/hist.rb +27 -8
- data/lib/pry/commands/install_command.rb +14 -12
- data/lib/pry/commands/list_inspectors.rb +35 -0
- data/lib/pry/commands/list_prompts.rb +35 -0
- data/lib/pry/commands/ls.rb +72 -296
- 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/play.rb +44 -10
- data/lib/pry/commands/pry_backtrace.rb +1 -2
- data/lib/pry/commands/raise_up.rb +2 -2
- data/lib/pry/commands/reload_code.rb +16 -19
- data/lib/pry/commands/ri.rb +7 -3
- data/lib/pry/commands/shell_command.rb +18 -13
- data/lib/pry/commands/shell_mode.rb +2 -4
- data/lib/pry/commands/show_doc.rb +5 -0
- data/lib/pry/commands/show_info.rb +8 -13
- data/lib/pry/commands/show_source.rb +15 -3
- data/lib/pry/commands/simple_prompt.rb +1 -1
- data/lib/pry/commands/toggle_color.rb +8 -4
- 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 +18 -10
- data/lib/pry/commands/wtf.rb +3 -3
- data/lib/pry/config.rb +20 -254
- 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 +31 -21
- data/lib/pry/editor.rb +107 -103
- data/lib/pry/exceptions.rb +77 -0
- data/lib/pry/helpers/base_helpers.rb +22 -109
- data/lib/pry/helpers/command_helpers.rb +10 -8
- data/lib/pry/helpers/documentation_helpers.rb +1 -2
- data/lib/pry/helpers/text.rb +4 -5
- data/lib/pry/history.rb +46 -45
- data/lib/pry/history_array.rb +6 -1
- data/lib/pry/hooks.rb +9 -29
- data/lib/pry/indent.rb +6 -6
- 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 +82 -87
- data/lib/pry/{commands/edit/method_patcher.rb → method/patcher.rb} +41 -38
- data/lib/pry/module_candidate.rb +4 -14
- data/lib/pry/object_path.rb +82 -0
- data/lib/pry/output.rb +50 -0
- data/lib/pry/pager.rb +193 -48
- data/lib/pry/plugins.rb +1 -1
- data/lib/pry/prompt.rb +26 -0
- data/lib/pry/pry_class.rb +149 -230
- data/lib/pry/pry_instance.rb +302 -413
- 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 +13 -5
- data/lib/pry/terminal.rb +2 -1
- data/lib/pry/test/helper.rb +26 -41
- data/lib/pry/version.rb +1 -1
- data/lib/pry/wrapped_module.rb +45 -59
- metadata +62 -225
- data/.document +0 -2
- data/.gitignore +0 -16
- data/.travis.yml +0 -25
- data/.yardopts +0 -1
- data/CHANGELOG +0 -534
- data/CONTRIBUTORS +0 -55
- data/Gemfile +0 -12
- data/Rakefile +0 -140
- data/TODO +0 -117
- data/lib/pry/completion.rb +0 -321
- data/lib/pry/custom_completions.rb +0 -6
- 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 -29
- data/spec/Procfile +0 -3
- data/spec/cli_spec.rb +0 -78
- data/spec/code_object_spec.rb +0 -277
- data/spec/code_spec.rb +0 -219
- data/spec/command_helpers_spec.rb +0 -29
- data/spec/command_integration_spec.rb +0 -644
- data/spec/command_set_spec.rb +0 -627
- data/spec/command_spec.rb +0 -821
- data/spec/commands/amend_line_spec.rb +0 -247
- data/spec/commands/bang_spec.rb +0 -19
- data/spec/commands/cat_spec.rb +0 -164
- data/spec/commands/cd_spec.rb +0 -250
- data/spec/commands/disable_pry_spec.rb +0 -25
- data/spec/commands/edit_spec.rb +0 -727
- data/spec/commands/exit_all_spec.rb +0 -34
- data/spec/commands/exit_program_spec.rb +0 -19
- data/spec/commands/exit_spec.rb +0 -34
- data/spec/commands/find_method_spec.rb +0 -70
- data/spec/commands/gem_list_spec.rb +0 -26
- data/spec/commands/gist_spec.rb +0 -79
- data/spec/commands/help_spec.rb +0 -56
- data/spec/commands/hist_spec.rb +0 -181
- data/spec/commands/jump_to_spec.rb +0 -15
- data/spec/commands/ls_spec.rb +0 -181
- data/spec/commands/play_spec.rb +0 -140
- data/spec/commands/raise_up_spec.rb +0 -56
- data/spec/commands/save_file_spec.rb +0 -177
- data/spec/commands/show_doc_spec.rb +0 -510
- data/spec/commands/show_input_spec.rb +0 -17
- data/spec/commands/show_source_spec.rb +0 -782
- data/spec/commands/whereami_spec.rb +0 -203
- data/spec/completion_spec.rb +0 -241
- data/spec/control_d_handler_spec.rb +0 -58
- data/spec/documentation_helper_spec.rb +0 -73
- data/spec/editor_spec.rb +0 -79
- data/spec/exception_whitelist_spec.rb +0 -21
- data/spec/fixtures/candidate_helper1.rb +0 -11
- data/spec/fixtures/candidate_helper2.rb +0 -8
- data/spec/fixtures/example.erb +0 -5
- data/spec/fixtures/example_nesting.rb +0 -33
- data/spec/fixtures/show_source_doc_examples.rb +0 -15
- data/spec/fixtures/testrc +0 -2
- data/spec/fixtures/testrcbad +0 -2
- data/spec/fixtures/whereami_helper.rb +0 -6
- data/spec/helper.rb +0 -34
- data/spec/helpers/bacon.rb +0 -86
- data/spec/helpers/mock_pry.rb +0 -43
- data/spec/helpers/table_spec.rb +0 -105
- data/spec/history_array_spec.rb +0 -67
- data/spec/hooks_spec.rb +0 -522
- data/spec/indent_spec.rb +0 -301
- data/spec/input_stack_spec.rb +0 -90
- data/spec/method_spec.rb +0 -482
- data/spec/prompt_spec.rb +0 -60
- data/spec/pry_defaults_spec.rb +0 -419
- data/spec/pry_history_spec.rb +0 -99
- data/spec/pry_output_spec.rb +0 -95
- data/spec/pry_spec.rb +0 -515
- data/spec/run_command_spec.rb +0 -25
- data/spec/sticky_locals_spec.rb +0 -157
- data/spec/syntax_checking_spec.rb +0 -81
- data/spec/wrapped_module_spec.rb +0 -261
- data/wiki/Customizing-pry.md +0 -397
- data/wiki/Home.md +0 -4
data/lib/pry/history_array.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class Pry
|
2
2
|
# A history array is an array to which you can only add elements. Older
|
3
|
-
# entries are removed progressively, so that the
|
3
|
+
# entries are removed progressively, so that the array never contains more than
|
4
4
|
# N elements.
|
5
5
|
#
|
6
6
|
# History arrays are used by Pry to store the output of the last commands.
|
@@ -89,6 +89,11 @@ class Pry
|
|
89
89
|
((@count - size)...@count).map { |n| @hash[n] }
|
90
90
|
end
|
91
91
|
|
92
|
+
# Returns [Hash] copy of the internal @hash history
|
93
|
+
def to_h
|
94
|
+
@hash.dup
|
95
|
+
end
|
96
|
+
|
92
97
|
def pop!
|
93
98
|
@hash.delete @count - 1
|
94
99
|
@count -= 1
|
data/lib/pry/hooks.rb
CHANGED
@@ -18,11 +18,11 @@ class Pry
|
|
18
18
|
# @param [Hash] hash The hash to convert to `Pry::Hooks`.
|
19
19
|
# @return [Pry::Hooks] The resulting `Pry::Hooks` instance.
|
20
20
|
def self.from_hash(hash)
|
21
|
+
return hash if hash.instance_of?(self)
|
21
22
|
instance = new
|
22
23
|
hash.each do |k, v|
|
23
24
|
instance.add_hook(k, nil, v)
|
24
25
|
end
|
25
|
-
|
26
26
|
instance
|
27
27
|
end
|
28
28
|
|
@@ -49,22 +49,6 @@ class Pry
|
|
49
49
|
@errors ||= []
|
50
50
|
end
|
51
51
|
|
52
|
-
# FIXME:
|
53
|
-
# This is a hack to alert people of the new API.
|
54
|
-
def [](event_name)
|
55
|
-
warn "`Pry.hooks[]` is deprecated! Please use the new `Pry::Hooks` API! http://rubydoc.info/github/pry/pry/master/Pry/Hooks"
|
56
|
-
|
57
|
-
get_hook(event_name, nil)
|
58
|
-
end
|
59
|
-
|
60
|
-
# FIXME:
|
61
|
-
# This is a hack to alert people of the new API.
|
62
|
-
def []=(event_name, callable)
|
63
|
-
warn "`Pry.hooks[]=` is deprecated! Please use the new `Pry::Hooks` API! http://rubydoc.info/github/pry/pry/master/Pry/Hooks"
|
64
|
-
|
65
|
-
add_hook(event_name, nil, callable)
|
66
|
-
end
|
67
|
-
|
68
52
|
# Destructively merge the contents of two `Pry:Hooks` instances.
|
69
53
|
# @param [Pry::Hooks] other The `Pry::Hooks` instance to merge
|
70
54
|
# @return [Pry:Hooks] Returns the receiver.
|
@@ -146,18 +130,14 @@ class Pry
|
|
146
130
|
def exec_hook(event_name, *args, &block)
|
147
131
|
@hooks[event_name] ||= []
|
148
132
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
e
|
158
|
-
end
|
159
|
-
end.last
|
160
|
-
end
|
133
|
+
@hooks[event_name].map do |hook_name, callable|
|
134
|
+
begin
|
135
|
+
callable.call(*args, &block)
|
136
|
+
rescue RescuableException => e
|
137
|
+
errors << e
|
138
|
+
e
|
139
|
+
end
|
140
|
+
end.last
|
161
141
|
end
|
162
142
|
|
163
143
|
# Return the number of hook functions registered for the `event_name` event.
|
data/lib/pry/indent.rb
CHANGED
@@ -94,8 +94,8 @@ class Pry
|
|
94
94
|
indent = new
|
95
95
|
lines = str.split("\n")
|
96
96
|
n = line_number - 1
|
97
|
-
to_indent = lines[0...n]
|
98
|
-
indent.indent(to_indent.join("\n")
|
97
|
+
to_indent = lines[0...n] << (lines[n] || "").split("def").first(1)
|
98
|
+
indent.indent(to_indent.join("\n") << "\n")
|
99
99
|
indent.module_nesting
|
100
100
|
end
|
101
101
|
|
@@ -320,7 +320,7 @@ class Pry
|
|
320
320
|
# [ ["class", "Foo"], ["module", "Bar::Baz"], ["class <<", "self"] ]
|
321
321
|
#
|
322
322
|
# A nil value in the @module_nesting array happens in two places: either
|
323
|
-
# when @
|
323
|
+
# when @awaiting_class is true and we're still waiting for the string to
|
324
324
|
# fill that space, or when a parse was rejected.
|
325
325
|
#
|
326
326
|
# At the moment this function is quite restricted about what formats it will
|
@@ -341,7 +341,7 @@ class Pry
|
|
341
341
|
@module_nesting.last[1] = token if kind == :class
|
342
342
|
@awaiting_class = false
|
343
343
|
else
|
344
|
-
# leave @
|
344
|
+
# leave @module_nesting[-1]
|
345
345
|
@awaiting_class = false
|
346
346
|
end
|
347
347
|
end
|
@@ -384,13 +384,13 @@ class Pry
|
|
384
384
|
# @return [String]
|
385
385
|
def correct_indentation(prompt, code, overhang=0)
|
386
386
|
prompt = prompt.delete("\001\002")
|
387
|
-
|
387
|
+
line_to_measure = Pry::Helpers::Text.strip_color(prompt) << code
|
388
388
|
whitespace = ' ' * overhang
|
389
389
|
|
390
390
|
_, cols = Terminal.screen_size
|
391
391
|
|
392
392
|
cols = cols.to_i
|
393
|
-
lines = cols != 0 ? (
|
393
|
+
lines = (cols != 0 ? (line_to_measure.length / cols + 1) : 1).to_i
|
394
394
|
|
395
395
|
if Pry::Helpers::BaseHelpers.windows_ansi?
|
396
396
|
move_up = "\e[#{lines}F"
|
@@ -0,0 +1,242 @@
|
|
1
|
+
# taken from irb
|
2
|
+
# Implements tab completion for Readline in Pry
|
3
|
+
class Pry::InputCompleter
|
4
|
+
NUMERIC_REGEXP = /^(-?(0[dbo])?[0-9_]+(\.[0-9_]+)?([eE]-?[0-9]+)?)\.([^.]*)$/
|
5
|
+
ARRAY_REGEXP = /^([^\]]*\])\.([^.]*)$/
|
6
|
+
SYMBOL_REGEXP = /^(:[^:.]*)$/
|
7
|
+
SYMBOL_METHOD_CALL_REGEXP = /^(:[^:.]+)\.([^.]*)$/
|
8
|
+
REGEX_REGEXP = /^(\/[^\/]*\/)\.([^.]*)$/
|
9
|
+
PROC_OR_HASH_REGEXP = /^([^\}]*\})\.([^.]*)$/
|
10
|
+
TOPLEVEL_LOOKUP_REGEXP = /^::([A-Z][^:\.\(]*)$/
|
11
|
+
CONSTANT_REGEXP = /^([A-Z][A-Za-z0-9]*)$/
|
12
|
+
CONSTANT_OR_METHOD_REGEXP = /^([A-Z].*)::([^:.]*)$/
|
13
|
+
HEX_REGEXP = /^(-?0x[0-9a-fA-F_]+)\.([^.]*)$/
|
14
|
+
GLOBALVARIABLE_REGEXP = /^(\$[^.]*)$/
|
15
|
+
VARIABLE_REGEXP = /^([^."].*)\.([^.]*)$/
|
16
|
+
|
17
|
+
ReservedWords = [
|
18
|
+
"BEGIN", "END",
|
19
|
+
"alias", "and",
|
20
|
+
"begin", "break",
|
21
|
+
"case", "class",
|
22
|
+
"def", "defined", "do",
|
23
|
+
"else", "elsif", "end", "ensure",
|
24
|
+
"false", "for",
|
25
|
+
"if", "in",
|
26
|
+
"module",
|
27
|
+
"next", "nil", "not",
|
28
|
+
"or",
|
29
|
+
"redo", "rescue", "retry", "return",
|
30
|
+
"self", "super",
|
31
|
+
"then", "true",
|
32
|
+
"undef", "unless", "until",
|
33
|
+
"when", "while",
|
34
|
+
"yield" ]
|
35
|
+
|
36
|
+
Operators = [
|
37
|
+
"%", "&", "*", "**", "+", "-", "/",
|
38
|
+
"<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
|
39
|
+
"[]", "[]=", "^", "!", "!=", "!~"
|
40
|
+
]
|
41
|
+
|
42
|
+
WORD_ESCAPE_STR = " \t\n\"\\'`><=;|&{("
|
43
|
+
|
44
|
+
def initialize(input, pry = nil)
|
45
|
+
@pry = pry
|
46
|
+
@input = input
|
47
|
+
@input.basic_word_break_characters = WORD_ESCAPE_STR if @input.respond_to?(:basic_word_break_characters=)
|
48
|
+
@input.completion_append_character = nil if @input.respond_to?(:completion_append_character=)
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# Return a new completion proc for use by Readline.
|
53
|
+
#
|
54
|
+
def call(str, options = {})
|
55
|
+
custom_completions = options[:custom_completions] || []
|
56
|
+
# if there are multiple contexts e.g. cd 1/2/3
|
57
|
+
# get new target for 1/2 and find candidates for 3
|
58
|
+
path, input = build_path(str)
|
59
|
+
|
60
|
+
if path.call.empty?
|
61
|
+
target = options[:target]
|
62
|
+
else
|
63
|
+
# Assume the user is tab-completing the 'cd' command
|
64
|
+
begin
|
65
|
+
target = Pry::ObjectPath.new(path.call, @pry.binding_stack).resolve.last
|
66
|
+
# but if that doesn't work, assume they're doing division with no spaces
|
67
|
+
rescue Pry::CommandError
|
68
|
+
target = options[:target]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
begin
|
73
|
+
bind = target
|
74
|
+
# Complete stdlib symbols
|
75
|
+
case input
|
76
|
+
when REGEX_REGEXP # Regexp
|
77
|
+
receiver = $1
|
78
|
+
message = Regexp.quote($2)
|
79
|
+
candidates = Regexp.instance_methods.collect(&:to_s)
|
80
|
+
select_message(path, receiver, message, candidates)
|
81
|
+
when ARRAY_REGEXP # Array
|
82
|
+
receiver = $1
|
83
|
+
message = Regexp.quote($2)
|
84
|
+
candidates = Array.instance_methods.collect(&:to_s)
|
85
|
+
select_message(path, receiver, message, candidates)
|
86
|
+
when PROC_OR_HASH_REGEXP # Proc or Hash
|
87
|
+
receiver = $1
|
88
|
+
message = Regexp.quote($2)
|
89
|
+
candidates = Proc.instance_methods.collect(&:to_s)
|
90
|
+
candidates |= Hash.instance_methods.collect(&:to_s)
|
91
|
+
select_message(path, receiver, message, candidates)
|
92
|
+
when SYMBOL_REGEXP # Symbol
|
93
|
+
if Symbol.respond_to?(:all_symbols)
|
94
|
+
sym = Regexp.quote($1)
|
95
|
+
candidates = Symbol.all_symbols.collect{|s| ":" << s.id2name}
|
96
|
+
candidates.grep(/^#{sym}/)
|
97
|
+
else
|
98
|
+
[]
|
99
|
+
end
|
100
|
+
when TOPLEVEL_LOOKUP_REGEXP # Absolute Constant or class methods
|
101
|
+
receiver = $1
|
102
|
+
candidates = Object.constants.collect(&:to_s)
|
103
|
+
candidates.grep(/^#{receiver}/).collect{|e| "::" << e}
|
104
|
+
when CONSTANT_REGEXP # Constant
|
105
|
+
message = $1
|
106
|
+
begin
|
107
|
+
context = target.eval("self")
|
108
|
+
context = context.class unless context.respond_to? :constants
|
109
|
+
candidates = context.constants.collect(&:to_s)
|
110
|
+
rescue
|
111
|
+
candidates = []
|
112
|
+
end
|
113
|
+
candidates = candidates.grep(/^#{message}/).collect(&path)
|
114
|
+
when CONSTANT_OR_METHOD_REGEXP # Constant or class methods
|
115
|
+
receiver = $1
|
116
|
+
message = Regexp.quote($2)
|
117
|
+
begin
|
118
|
+
candidates = eval("#{receiver}.constants.collect(&:to_s)", bind)
|
119
|
+
candidates |= eval("#{receiver}.methods.collect(&:to_s)", bind)
|
120
|
+
rescue Pry::RescuableException
|
121
|
+
candidates = []
|
122
|
+
end
|
123
|
+
candidates.grep(/^#{message}/).collect{|e| receiver + "::" + e}
|
124
|
+
when SYMBOL_METHOD_CALL_REGEXP # method call on a Symbol
|
125
|
+
receiver = $1
|
126
|
+
message = Regexp.quote($2)
|
127
|
+
candidates = Symbol.instance_methods.collect(&:to_s)
|
128
|
+
select_message(path, receiver, message, candidates)
|
129
|
+
when NUMERIC_REGEXP
|
130
|
+
# Numeric
|
131
|
+
receiver = $1
|
132
|
+
message = Regexp.quote($5)
|
133
|
+
begin
|
134
|
+
candidates = eval(receiver, bind).methods.collect(&:to_s)
|
135
|
+
rescue Pry::RescuableException
|
136
|
+
candidates = []
|
137
|
+
end
|
138
|
+
select_message(path, receiver, message, candidates)
|
139
|
+
when HEX_REGEXP
|
140
|
+
# Numeric(0xFFFF)
|
141
|
+
receiver = $1
|
142
|
+
message = Regexp.quote($2)
|
143
|
+
begin
|
144
|
+
candidates = eval(receiver, bind).methods.collect(&:to_s)
|
145
|
+
rescue Pry::RescuableException
|
146
|
+
candidates = []
|
147
|
+
end
|
148
|
+
select_message(path, receiver, message, candidates)
|
149
|
+
when GLOBALVARIABLE_REGEXP # global
|
150
|
+
regmessage = Regexp.new(Regexp.quote($1))
|
151
|
+
candidates = global_variables.collect(&:to_s).grep(regmessage)
|
152
|
+
when VARIABLE_REGEXP # variable
|
153
|
+
receiver = $1
|
154
|
+
message = Regexp.quote($2)
|
155
|
+
|
156
|
+
gv = eval("global_variables", bind).collect(&:to_s)
|
157
|
+
lv = eval("local_variables", bind).collect(&:to_s)
|
158
|
+
cv = eval("self.class.constants", bind).collect(&:to_s)
|
159
|
+
|
160
|
+
if (gv | lv | cv).include?(receiver) or /^[A-Z]/ =~ receiver && /\./ !~ receiver
|
161
|
+
# foo.func and foo is local var. OR
|
162
|
+
# Foo::Bar.func
|
163
|
+
begin
|
164
|
+
candidates = eval("#{receiver}.methods", bind).collect(&:to_s)
|
165
|
+
rescue Pry::RescuableException
|
166
|
+
candidates = []
|
167
|
+
end
|
168
|
+
else
|
169
|
+
# func1.func2
|
170
|
+
candidates = []
|
171
|
+
ObjectSpace.each_object(Module){|m|
|
172
|
+
begin
|
173
|
+
name = m.name.to_s
|
174
|
+
rescue Pry::RescuableException
|
175
|
+
name = ""
|
176
|
+
end
|
177
|
+
next if name != "IRB::Context" and
|
178
|
+
/^(IRB|SLex|RubyLex|RubyToken)/ =~ name
|
179
|
+
|
180
|
+
# jruby doesn't always provide #instance_methods() on each
|
181
|
+
# object.
|
182
|
+
if m.respond_to?(:instance_methods)
|
183
|
+
candidates.concat m.instance_methods(false).collect(&:to_s)
|
184
|
+
end
|
185
|
+
}
|
186
|
+
candidates.sort!
|
187
|
+
candidates.uniq!
|
188
|
+
end
|
189
|
+
select_message(path, receiver, message, candidates)
|
190
|
+
when /^\.([^.]*)$/
|
191
|
+
# Unknown(maybe String)
|
192
|
+
receiver = ""
|
193
|
+
message = Regexp.quote($1)
|
194
|
+
candidates = String.instance_methods(true).collect(&:to_s)
|
195
|
+
select_message(path, receiver, message, candidates)
|
196
|
+
else
|
197
|
+
candidates = eval(
|
198
|
+
"methods | private_methods | local_variables | " \
|
199
|
+
"self.class.constants | instance_variables",
|
200
|
+
bind
|
201
|
+
).collect(&:to_s)
|
202
|
+
|
203
|
+
if eval("respond_to?(:class_variables)", bind)
|
204
|
+
candidates += eval("class_variables", bind).collect(&:to_s)
|
205
|
+
end
|
206
|
+
candidates = (candidates|ReservedWords|custom_completions).grep(/^#{Regexp.quote(input)}/)
|
207
|
+
candidates.collect(&path)
|
208
|
+
end
|
209
|
+
rescue Pry::RescuableException
|
210
|
+
[]
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def select_message(path, receiver, message, candidates)
|
215
|
+
candidates.grep(/^#{message}/).collect { |e|
|
216
|
+
case e
|
217
|
+
when /^[a-zA-Z_]/
|
218
|
+
path.call(receiver + "." << e)
|
219
|
+
when /^[0-9]/
|
220
|
+
when *Operators
|
221
|
+
#receiver + " " << e
|
222
|
+
end
|
223
|
+
}.compact
|
224
|
+
end
|
225
|
+
|
226
|
+
# build_path seperates the input into two parts: path and input.
|
227
|
+
# input is the partial string that should be completed
|
228
|
+
# path is a proc that takes an input and builds a full path.
|
229
|
+
def build_path(input)
|
230
|
+
# check to see if the input is a regex
|
231
|
+
return proc {|i| i.to_s }, input if input[/\/\./]
|
232
|
+
trailing_slash = input.end_with?('/')
|
233
|
+
contexts = input.chomp('/').split(/\//)
|
234
|
+
input = contexts[-1]
|
235
|
+
path = proc do |i|
|
236
|
+
p = contexts[0..-2].push(i).join('/')
|
237
|
+
p += '/' if trailing_slash && !i.nil?
|
238
|
+
p
|
239
|
+
end
|
240
|
+
return path, input
|
241
|
+
end
|
242
|
+
end
|
@@ -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
|