pry 0.10.pre.1-i386-mswin32 → 0.10.0.pre3-i386-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +702 -0
- data/LICENSE +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
data/lib/pry/indent.rb
CHANGED
@@ -1,12 +1,6 @@
|
|
1
1
|
require 'coderay'
|
2
2
|
|
3
3
|
class Pry
|
4
|
-
# Load io-console if possible, so that we can use $stdout.winsize.
|
5
|
-
begin
|
6
|
-
require 'io/console'
|
7
|
-
rescue LoadError
|
8
|
-
end
|
9
|
-
|
10
4
|
##
|
11
5
|
# Pry::Indent is a class that can be used to indent a number of lines
|
12
6
|
# containing Ruby code similar as to how IRB does it (but better). The class
|
@@ -17,9 +11,15 @@ class Pry
|
|
17
11
|
class Indent
|
18
12
|
include Helpers::BaseHelpers
|
19
13
|
|
20
|
-
#
|
14
|
+
# Raised if {#module_nesting} would not work.
|
15
|
+
class UnparseableNestingError < StandardError; end
|
16
|
+
|
17
|
+
# @return [String] String containing the spaces to be inserted before the next line.
|
21
18
|
attr_reader :indent_level
|
22
19
|
|
20
|
+
# @return [Array<String>] The stack of open tokens.
|
21
|
+
attr_reader :stack
|
22
|
+
|
23
23
|
# The amount of spaces to insert for each indent level.
|
24
24
|
SPACES = ' '
|
25
25
|
|
@@ -48,6 +48,9 @@ class Pry
|
|
48
48
|
# a single-line.
|
49
49
|
SINGLELINE_TOKENS = %w(if while until unless rescue)
|
50
50
|
|
51
|
+
# Which tokens can be followed by an optional "do" keyword.
|
52
|
+
OPTIONAL_DO_TOKENS = %w(for while until)
|
53
|
+
|
51
54
|
# Collection of token types that should be ignored. Without this list
|
52
55
|
# keywords such as "class" inside strings would cause the code to be
|
53
56
|
# indented incorrectly.
|
@@ -70,6 +73,32 @@ class Pry
|
|
70
73
|
# don't affect the surrounding code.
|
71
74
|
MIDWAY_TOKENS = %w(when else elsif ensure rescue)
|
72
75
|
|
76
|
+
# Clean the indentation of a fragment of ruby.
|
77
|
+
#
|
78
|
+
# @param [String] str
|
79
|
+
# @return [String]
|
80
|
+
def self.indent(str)
|
81
|
+
new.indent(str)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Get the module nesting at the given point in the given string.
|
85
|
+
#
|
86
|
+
# NOTE If the line specified contains a method definition, then the nesting
|
87
|
+
# at the start of the method definition is used. Otherwise the nesting from
|
88
|
+
# the end of the line is used.
|
89
|
+
#
|
90
|
+
# @param [String] str The ruby code to analyze
|
91
|
+
# @param [Fixnum] line_number The line number (starting from 1)
|
92
|
+
# @return [Array<String>]
|
93
|
+
def self.nesting_at(str, line_number)
|
94
|
+
indent = new
|
95
|
+
lines = str.split("\n")
|
96
|
+
n = line_number - 1
|
97
|
+
to_indent = lines[0...n] << (lines[n] || "").split("def").first(1)
|
98
|
+
indent.indent(to_indent.join("\n") << "\n")
|
99
|
+
indent.module_nesting
|
100
|
+
end
|
101
|
+
|
73
102
|
def initialize
|
74
103
|
reset
|
75
104
|
end
|
@@ -81,6 +110,8 @@ class Pry
|
|
81
110
|
@heredoc_queue = []
|
82
111
|
@close_heredocs = {}
|
83
112
|
@string_start = nil
|
113
|
+
@awaiting_class = false
|
114
|
+
@module_nesting = []
|
84
115
|
self
|
85
116
|
end
|
86
117
|
|
@@ -126,7 +157,6 @@ class Pry
|
|
126
157
|
new_prefix = prefix + SPACES * after
|
127
158
|
|
128
159
|
line = prefix + line.lstrip unless previously_in_string
|
129
|
-
line = line.rstrip + "\n" unless in_string?
|
130
160
|
|
131
161
|
output += line
|
132
162
|
|
@@ -135,7 +165,7 @@ class Pry
|
|
135
165
|
|
136
166
|
@indent_level = prefix
|
137
167
|
|
138
|
-
return output
|
168
|
+
return output
|
139
169
|
end
|
140
170
|
|
141
171
|
# Get the indentation for the start of the next line.
|
@@ -189,7 +219,9 @@ class Pry
|
|
189
219
|
last_token, last_kind = token, kind unless kind == :space
|
190
220
|
next if IGNORE_TOKENS.include?(kind)
|
191
221
|
|
192
|
-
|
222
|
+
track_module_nesting(token, kind)
|
223
|
+
|
224
|
+
seen_for_at << add_after if OPTIONAL_DO_TOKENS.include?(token)
|
193
225
|
|
194
226
|
if kind == :delimiter
|
195
227
|
track_delimiter(token)
|
@@ -197,7 +229,8 @@ class Pry
|
|
197
229
|
@stack << token
|
198
230
|
add_after += 1
|
199
231
|
elsif token == OPEN_TOKENS[@stack.last]
|
200
|
-
@stack.pop
|
232
|
+
popped = @stack.pop
|
233
|
+
track_module_nesting_end(popped)
|
201
234
|
if add_after == 0
|
202
235
|
remove_before += 1
|
203
236
|
else
|
@@ -279,6 +312,68 @@ class Pry
|
|
279
312
|
"puts #{open_delimiters.join(", ")}"
|
280
313
|
end
|
281
314
|
|
315
|
+
# Update the internal state relating to module nesting.
|
316
|
+
#
|
317
|
+
# It's responsible for adding to the @module_nesting array, which looks
|
318
|
+
# something like:
|
319
|
+
#
|
320
|
+
# [ ["class", "Foo"], ["module", "Bar::Baz"], ["class <<", "self"] ]
|
321
|
+
#
|
322
|
+
# A nil value in the @module_nesting array happens in two places: either
|
323
|
+
# when @awaiting_class is true and we're still waiting for the string to
|
324
|
+
# fill that space, or when a parse was rejected.
|
325
|
+
#
|
326
|
+
# At the moment this function is quite restricted about what formats it will
|
327
|
+
# parse, for example we disallow expressions after the class keyword. This
|
328
|
+
# could maybe be improved in the future.
|
329
|
+
#
|
330
|
+
# @param [String] token a token from Coderay
|
331
|
+
# @param [Symbol] kind the kind of that token
|
332
|
+
def track_module_nesting(token, kind)
|
333
|
+
if kind == :keyword && (token == "class" || token == "module")
|
334
|
+
@module_nesting << [token, nil]
|
335
|
+
@awaiting_class = true
|
336
|
+
elsif @awaiting_class
|
337
|
+
if kind == :operator && token == "<<" && @module_nesting.last[0] == "class"
|
338
|
+
@module_nesting.last[0] = "class <<"
|
339
|
+
@awaiting_class = true
|
340
|
+
elsif kind == :class && token =~ /\A(self|[A-Z:][A-Za-z0-9_:]*)\z/
|
341
|
+
@module_nesting.last[1] = token if kind == :class
|
342
|
+
@awaiting_class = false
|
343
|
+
else
|
344
|
+
# leave @module_nesting[-1]
|
345
|
+
@awaiting_class = false
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
# Update the internal state relating to module nesting on 'end'.
|
351
|
+
#
|
352
|
+
# If the current 'end' pairs up with a class or a module then we should
|
353
|
+
# pop an array off of @module_nesting
|
354
|
+
#
|
355
|
+
# @param [String] token a token from Coderay
|
356
|
+
# @param [Symbol] kind the kind of that token
|
357
|
+
def track_module_nesting_end(token, kind=:keyword)
|
358
|
+
if kind == :keyword && (token == "class" || token == "module")
|
359
|
+
@module_nesting.pop
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
# Return a list of strings which can be used to re-construct the Module.nesting at
|
364
|
+
# the current point in the file.
|
365
|
+
#
|
366
|
+
# Returns nil if the syntax of the file was not recognizable.
|
367
|
+
#
|
368
|
+
# @return [Array<String>]
|
369
|
+
def module_nesting
|
370
|
+
@module_nesting.map do |(kind, token)|
|
371
|
+
raise UnparseableNestingError, @module_nesting.inspect if token.nil?
|
372
|
+
|
373
|
+
"#{kind} #{token}"
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
282
377
|
# Return a string which, when printed, will rewrite the previous line with
|
283
378
|
# the correct indentation. Mostly useful for fixing 'end'.
|
284
379
|
#
|
@@ -288,13 +383,14 @@ class Pry
|
|
288
383
|
# the difference in length between the old line and the new one).
|
289
384
|
# @return [String]
|
290
385
|
def correct_indentation(prompt, code, overhang=0)
|
291
|
-
|
386
|
+
prompt = prompt.delete("\001\002")
|
387
|
+
line_to_measure = Pry::Helpers::Text.strip_color(prompt) << code
|
292
388
|
whitespace = ' ' * overhang
|
293
389
|
|
294
|
-
_, cols = screen_size
|
390
|
+
_, cols = Terminal.screen_size
|
295
391
|
|
296
392
|
cols = cols.to_i
|
297
|
-
lines = cols != 0 ? (
|
393
|
+
lines = (cols != 0 ? (line_to_measure.length / cols + 1) : 1).to_i
|
298
394
|
|
299
395
|
if Pry::Helpers::BaseHelpers.windows_ansi?
|
300
396
|
move_up = "\e[#{lines}F"
|
@@ -306,29 +402,5 @@ class Pry
|
|
306
402
|
|
307
403
|
"#{move_up}#{prompt}#{colorize_code(code)}#{whitespace}#{move_down}"
|
308
404
|
end
|
309
|
-
|
310
|
-
# Return a pair of [rows, columns] which gives the size of the window.
|
311
|
-
#
|
312
|
-
# If the window size cannot be determined, return nil.
|
313
|
-
def screen_size
|
314
|
-
[
|
315
|
-
# io/console adds a winsize method to IO streams.
|
316
|
-
$stdout.tty? && $stdout.respond_to?(:winsize) && $stdout.winsize,
|
317
|
-
|
318
|
-
# Some readlines also provides get_screen_size.
|
319
|
-
Readline.respond_to?(:get_screen_size) && Readline.get_screen_size,
|
320
|
-
|
321
|
-
# Otherwise try to use the environment (this may be out of date due
|
322
|
-
# to window resizing, but it's better than nothing).
|
323
|
-
[ENV["ROWS"], ENV["COLUMNS"],
|
324
|
-
|
325
|
-
# If the user is running within ansicon, then use the screen size
|
326
|
-
# that it reports (same caveats apply as with ROWS and COLUMNS)
|
327
|
-
ENV['ANSICON'] =~ /\((.*)x(.*)\)/ && [$2, $1]
|
328
|
-
]
|
329
|
-
].detect do |(_, cols)|
|
330
|
-
cols.to_i > 0
|
331
|
-
end
|
332
|
-
end
|
333
405
|
end
|
334
406
|
end
|
@@ -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
|