pry 0.9.7.4 → 0.9.8pre2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -3
- data/README.markdown +3 -1
- data/Rakefile +48 -31
- data/bin/pry +2 -80
- data/lib/pry.rb +17 -20
- data/lib/pry/cli.rb +152 -0
- data/lib/pry/command_processor.rb +13 -0
- data/lib/pry/command_set.rb +102 -9
- data/lib/pry/config.rb +28 -6
- data/lib/pry/default_commands/context.rb +9 -8
- data/lib/pry/default_commands/documentation.rb +55 -13
- data/lib/pry/default_commands/easter_eggs.rb +1 -1
- data/lib/pry/default_commands/input.rb +25 -25
- data/lib/pry/default_commands/introspection.rb +19 -18
- data/lib/pry/default_commands/ls.rb +23 -38
- data/lib/pry/default_commands/shell.rb +47 -15
- data/lib/pry/helpers/command_helpers.rb +28 -6
- data/lib/pry/helpers/options_helpers.rb +7 -4
- data/lib/pry/helpers/text.rb +23 -3
- data/lib/pry/history.rb +55 -17
- data/lib/pry/history_array.rb +2 -0
- data/lib/pry/hooks.rb +108 -0
- data/lib/pry/indent.rb +9 -5
- data/lib/pry/method.rb +99 -50
- data/lib/pry/plugins.rb +10 -2
- data/lib/pry/pry_class.rb +48 -20
- data/lib/pry/pry_instance.rb +106 -91
- data/lib/pry/version.rb +1 -1
- data/lib/pry/wrapped_module.rb +73 -0
- data/man/pry.1 +195 -0
- data/man/pry.1.html +204 -0
- data/man/pry.1.ronn +141 -0
- data/pry.gemspec +21 -24
- data/test/helper.rb +12 -3
- data/test/test_cli.rb +78 -0
- data/test/test_command_set.rb +193 -1
- data/test/test_default_commands/test_context.rb +19 -4
- data/test/test_default_commands/test_input.rb +2 -2
- data/test/test_default_commands/test_introspection.rb +63 -6
- data/test/test_default_commands/test_ls.rb +8 -35
- data/test/test_default_commands/test_shell.rb +36 -1
- data/test/test_hooks.rb +175 -0
- data/test/test_indent.rb +2 -0
- data/test/test_method.rb +10 -0
- data/test/test_pry.rb +35 -34
- data/test/test_pry_history.rb +24 -24
- data/test/test_syntax_checking.rb +47 -0
- data/test/test_wrapped_module.rb +71 -0
- metadata +40 -34
data/lib/pry/plugins.rb
CHANGED
@@ -32,13 +32,21 @@ class Pry
|
|
32
32
|
self.enabled = true
|
33
33
|
end
|
34
34
|
|
35
|
+
# Load the Command line options defined by this plugin (if they exist)
|
36
|
+
def load_cli_options
|
37
|
+
cli_options_file = File.join(spec.full_gem_path, "lib/#{spec.name}/cli.rb")
|
38
|
+
require cli_options_file if File.exists?(cli_options_file)
|
39
|
+
end
|
35
40
|
# Activate the plugin (require the gem - enables/loads the
|
36
|
-
# plugin immediately at point of call, even if plugin is
|
41
|
+
# plugin immediately at point of call, even if plugin is
|
42
|
+
# disabled)
|
43
|
+
# Does not reload plugin if it's already active.
|
37
44
|
def activate!
|
38
45
|
begin
|
39
46
|
require gem_name if !active?
|
40
|
-
rescue LoadError
|
47
|
+
rescue LoadError => e
|
41
48
|
$stderr.puts "Warning: The plugin '#{gem_name}' was not found! (gem found but could not be loaded)"
|
49
|
+
$stderr.puts e
|
42
50
|
end
|
43
51
|
self.active = true
|
44
52
|
self.enabled = true
|
data/lib/pry/pry_class.rb
CHANGED
@@ -73,6 +73,30 @@ class Pry
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
+
# Trap interrupts on jruby, and make them behave like MRI so we can
|
77
|
+
# catch them.
|
78
|
+
def self.load_traps
|
79
|
+
trap('INT'){ raise Interrupt }
|
80
|
+
end
|
81
|
+
|
82
|
+
# Do basic setup for initial session.
|
83
|
+
# Including: loading .pryrc, loading plugins, loading requires, and
|
84
|
+
# loading history.
|
85
|
+
def self.initial_session_setup
|
86
|
+
|
87
|
+
return if !initial_session?
|
88
|
+
|
89
|
+
# note these have to be loaded here rather than in pry_instance as
|
90
|
+
# we only want them loaded once per entire Pry lifetime.
|
91
|
+
load_rc if Pry.config.should_load_rc
|
92
|
+
load_plugins if Pry.config.plugins.enabled
|
93
|
+
load_requires if Pry.config.should_load_requires
|
94
|
+
load_history if Pry.config.history.should_load
|
95
|
+
load_traps if Pry.config.should_trap_interrupts
|
96
|
+
|
97
|
+
@initial_session = false
|
98
|
+
end
|
99
|
+
|
76
100
|
# Start a Pry REPL.
|
77
101
|
# This method also loads the files specified in `Pry::RC_FILES` the
|
78
102
|
# first time it is invoked.
|
@@ -82,19 +106,23 @@ class Pry
|
|
82
106
|
# @example
|
83
107
|
# Pry.start(Object.new, :input => MyInput.new)
|
84
108
|
def self.start(target=TOPLEVEL_BINDING, options={})
|
85
|
-
|
86
|
-
|
87
|
-
# we only want them loaded once per entire Pry lifetime, not
|
88
|
-
# multiple times per each new session (i.e in debugging)
|
89
|
-
load_rc if Pry.config.should_load_rc
|
90
|
-
load_plugins if Pry.config.plugins.enabled
|
91
|
-
load_requires if Pry.config.should_load_requires
|
92
|
-
load_history if Pry.config.history.should_load
|
93
|
-
|
94
|
-
@initial_session = false
|
95
|
-
end
|
109
|
+
target = Pry.binding_for(target)
|
110
|
+
initial_session_setup
|
96
111
|
|
97
|
-
|
112
|
+
# create the Pry instance to manage the session
|
113
|
+
pry_instance = new(options)
|
114
|
+
|
115
|
+
# save backtrace
|
116
|
+
pry_instance.backtrace = caller.tap(&:shift)
|
117
|
+
|
118
|
+
# yield the binding_stack to the hook for modification
|
119
|
+
Pry.config.hooks.exec_hook(:when_started, binding_stack = [target], pry_instance)
|
120
|
+
|
121
|
+
head, *tail = binding_stack
|
122
|
+
pry_instance.binding_stack.push(*tail)
|
123
|
+
|
124
|
+
# Enter the matrix
|
125
|
+
pry_instance.repl(head)
|
98
126
|
end
|
99
127
|
|
100
128
|
# An inspector that clips the output to `max_length` chars.
|
@@ -120,17 +148,12 @@ class Pry
|
|
120
148
|
|
121
149
|
# Load Readline history if required.
|
122
150
|
def self.load_history
|
123
|
-
Pry.history.load
|
151
|
+
Pry.history.load
|
124
152
|
end
|
125
153
|
|
126
154
|
# Save new lines of Readline history if required.
|
127
155
|
def self.save_history
|
128
|
-
Pry.history.save
|
129
|
-
end
|
130
|
-
|
131
|
-
# Get the full path of the history_path for pry.
|
132
|
-
def self.history_file
|
133
|
-
File.expand_path(Pry.config.history.file)
|
156
|
+
Pry.history.save
|
134
157
|
end
|
135
158
|
|
136
159
|
# @return [Boolean] Whether this is the first time a Pry session has
|
@@ -165,7 +188,7 @@ class Pry
|
|
165
188
|
|
166
189
|
output = options[:show_output] ? options[:output] : StringIO.new
|
167
190
|
|
168
|
-
Pry.new(:output => output, :input => StringIO.new(command_string), :commands => options[:commands], :prompt => proc {""}, :hooks =>
|
191
|
+
Pry.new(:output => output, :input => StringIO.new(command_string), :commands => options[:commands], :prompt => proc {""}, :hooks => Pry::Hooks.new).rep(options[:context])
|
169
192
|
end
|
170
193
|
|
171
194
|
def self.default_editor_for_platform
|
@@ -192,10 +215,15 @@ class Pry
|
|
192
215
|
config.system = DEFAULT_SYSTEM
|
193
216
|
config.editor = default_editor_for_platform
|
194
217
|
config.should_load_rc = true
|
218
|
+
config.should_trap_interrupts = defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
|
195
219
|
config.disable_auto_reload = false
|
196
220
|
config.command_prefix = ""
|
197
221
|
config.auto_indent = true
|
198
222
|
config.correct_indent = true
|
223
|
+
config.collision_warning = false
|
224
|
+
|
225
|
+
config.gist ||= OpenStruct.new
|
226
|
+
config.gist.inspecter = proc &:pretty_inspect
|
199
227
|
|
200
228
|
config.plugins ||= OpenStruct.new
|
201
229
|
config.plugins.enabled = true
|
data/lib/pry/pry_instance.rb
CHANGED
@@ -23,6 +23,8 @@ class Pry
|
|
23
23
|
attr_reader :input_array
|
24
24
|
attr_reader :output_array
|
25
25
|
|
26
|
+
attr_accessor :backtrace
|
27
|
+
|
26
28
|
# Create a new `Pry` object.
|
27
29
|
# @param [Hash] options The optional configuration parameters.
|
28
30
|
# @option options [#readline] :input The object to use for input.
|
@@ -106,13 +108,6 @@ class Pry
|
|
106
108
|
@output_array = Pry::HistoryArray.new(size)
|
107
109
|
end
|
108
110
|
|
109
|
-
# Execute the hook `hook_name`, if it is defined.
|
110
|
-
# @param [Symbol] hook_name The hook to execute
|
111
|
-
# @param [Array] args The arguments to pass to the hook.
|
112
|
-
def exec_hook(hook_name, *args, &block)
|
113
|
-
hooks[hook_name].call(*args, &block) if hooks[hook_name]
|
114
|
-
end
|
115
|
-
|
116
111
|
# Make sure special locals exist at start of session
|
117
112
|
def initialize_special_locals(target)
|
118
113
|
inject_local("_in_", @input_array, target)
|
@@ -149,7 +144,7 @@ class Pry
|
|
149
144
|
# Initialize the repl session.
|
150
145
|
# @param [Binding] target The target binding for the session.
|
151
146
|
def repl_prologue(target)
|
152
|
-
exec_hook :before_session, output, target, self
|
147
|
+
hooks.exec_hook :before_session, output, target, self
|
153
148
|
initialize_special_locals(target)
|
154
149
|
|
155
150
|
@input_array << nil # add empty input so _in_ and _out_ match
|
@@ -161,7 +156,7 @@ class Pry
|
|
161
156
|
# Clean-up after the repl session.
|
162
157
|
# @param [Binding] target The target binding for the session.
|
163
158
|
def repl_epilogue(target)
|
164
|
-
exec_hook :after_session, output, target, self
|
159
|
+
hooks.exec_hook :after_session, output, target, self
|
165
160
|
|
166
161
|
Pry.active_sessions -= 1
|
167
162
|
binding_stack.pop
|
@@ -189,7 +184,7 @@ class Pry
|
|
189
184
|
end
|
190
185
|
|
191
186
|
repl_epilogue(target)
|
192
|
-
break_data ||
|
187
|
+
break_data || nil
|
193
188
|
end
|
194
189
|
|
195
190
|
# Perform a read-eval-print.
|
@@ -234,13 +229,11 @@ class Pry
|
|
234
229
|
|
235
230
|
result = set_last_result(target.eval(code, Pry.eval_path, Pry.current_line), target)
|
236
231
|
result
|
237
|
-
rescue CommandError, Slop::InvalidOptionError => e
|
238
|
-
output.puts "Error: #{e.message}"
|
239
|
-
@suppress_output = true
|
240
232
|
rescue RescuableException => e
|
241
|
-
set_last_exception(e, target)
|
233
|
+
result = set_last_exception(e, target)
|
242
234
|
ensure
|
243
235
|
update_input_history(code)
|
236
|
+
hooks.exec_hook :after_eval, result, self
|
244
237
|
end
|
245
238
|
|
246
239
|
# Perform a read.
|
@@ -259,16 +252,19 @@ class Pry
|
|
259
252
|
|
260
253
|
val = ""
|
261
254
|
loop do
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
255
|
+
begin
|
256
|
+
# eval_string will probably be mutated by this method
|
257
|
+
retrieve_line(eval_string, target)
|
258
|
+
rescue CommandError, Slop::InvalidOptionError => e
|
259
|
+
output.puts "Error: #{e.message}"
|
260
|
+
end
|
266
261
|
|
267
|
-
break if
|
262
|
+
break if complete_expression?(eval_string)
|
268
263
|
end
|
269
264
|
|
270
265
|
@suppress_output = true if eval_string =~ /;\Z/ || eval_string.empty?
|
271
266
|
|
267
|
+
hooks.exec_hook :after_read, eval_string, self
|
272
268
|
eval_string
|
273
269
|
end
|
274
270
|
|
@@ -294,10 +290,15 @@ class Pry
|
|
294
290
|
end
|
295
291
|
end
|
296
292
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
293
|
+
def should_force_encoding?(eval_string, val)
|
294
|
+
eval_string.empty? && val.respond_to?(:encoding) && val.encoding != eval_string.encoding
|
295
|
+
end
|
296
|
+
private :should_force_encoding?
|
297
|
+
|
298
|
+
# Read and process a line of input -- check for ^D, determine which prompt to
|
299
|
+
# use, rewrite the indentation if `Pry.config.auto_indent` is enabled, and,
|
300
|
+
# if the line is a command, process it and alter the eval_string accordingly.
|
301
|
+
# This method should not need to be invoked directly.
|
301
302
|
#
|
302
303
|
# @param [String] eval_string The cumulative lines of input.
|
303
304
|
# @param [Binding] target The target of the session.
|
@@ -305,44 +306,53 @@ class Pry
|
|
305
306
|
def retrieve_line(eval_string, target)
|
306
307
|
@indent.reset if eval_string.empty?
|
307
308
|
|
308
|
-
current_prompt = select_prompt(eval_string
|
309
|
+
current_prompt = select_prompt(eval_string, target)
|
309
310
|
indentation = Pry.config.auto_indent ? @indent.indent_level : ''
|
310
311
|
|
311
|
-
val = readline(current_prompt
|
312
|
+
val = readline("#{current_prompt}#{indentation}")
|
312
313
|
|
313
314
|
# invoke handler if we receive EOF character (^D)
|
314
315
|
if !val
|
315
316
|
output.puts ""
|
316
317
|
Pry.config.control_d_handler.call(eval_string, self)
|
317
|
-
|
318
|
-
|
319
|
-
# Change the eval_string into the input encoding (Issue 284)
|
320
|
-
# TODO: This wouldn't be necessary if the eval_string was constructed from
|
321
|
-
# input strings only.
|
322
|
-
if eval_string.empty? && val.respond_to?(:encoding) && val.encoding != eval_string.encoding
|
323
|
-
eval_string.force_encoding(val.encoding)
|
324
|
-
end
|
318
|
+
return
|
319
|
+
end
|
325
320
|
|
326
|
-
|
327
|
-
|
328
|
-
|
321
|
+
# Change the eval_string into the input encoding (Issue 284)
|
322
|
+
# TODO: This wouldn't be necessary if the eval_string was constructed from
|
323
|
+
# input strings only.
|
324
|
+
if should_force_encoding?(eval_string, val)
|
325
|
+
eval_string.force_encoding(val.encoding)
|
326
|
+
end
|
329
327
|
|
330
|
-
|
331
|
-
|
332
|
-
|
328
|
+
if Pry.config.auto_indent && !input.is_a?(StringIO)
|
329
|
+
original_val = "#{indentation}#{val}"
|
330
|
+
indented_val = @indent.indent(val)
|
331
|
+
|
332
|
+
if original_val != indented_val && output.tty? && Pry::Helpers::BaseHelpers.use_ansi_codes? && Pry.config.correct_indent
|
333
|
+
output.print @indent.correct_indentation(current_prompt + indented_val, original_val.length - indented_val.length)
|
333
334
|
end
|
335
|
+
else
|
336
|
+
indented_val = val
|
337
|
+
end
|
334
338
|
|
335
|
-
|
336
|
-
val
|
339
|
+
begin
|
340
|
+
if !process_command(val, eval_string, target)
|
341
|
+
eval_string << "#{indented_val.rstrip}\n" unless val.empty?
|
342
|
+
end
|
343
|
+
ensure
|
344
|
+
Pry.history << indented_val unless input.is_a?(StringIO)
|
337
345
|
end
|
338
346
|
end
|
339
347
|
|
340
|
-
#
|
348
|
+
# If the given line is a valid command, process it in the context of the
|
349
|
+
# current `eval_string` and context.
|
341
350
|
# This method should not need to be invoked directly.
|
342
351
|
# @param [String] val The line to process.
|
343
352
|
# @param [String] eval_string The cumulative lines of input.
|
344
353
|
# @param [Binding] target The target of the Pry session.
|
345
|
-
|
354
|
+
# @return [Boolean] `true` if `val` is a command, `false` otherwise
|
355
|
+
def process_command(val, eval_string, target)
|
346
356
|
result = @command_processor.process_commands(val, eval_string, target)
|
347
357
|
|
348
358
|
# set a temporary (just so we can inject the value we want into eval_string)
|
@@ -351,16 +361,16 @@ class Pry
|
|
351
361
|
# note that `result` wraps the result of command processing; if a
|
352
362
|
# command was matched and invoked then `result.command?` returns true,
|
353
363
|
# otherwise it returns false.
|
354
|
-
if result.command?
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
364
|
+
if result.command?
|
365
|
+
if !result.void_command?
|
366
|
+
# the command that was invoked was non-void (had a return value) and so we make
|
367
|
+
# the value of the current expression equal to the return value
|
368
|
+
# of the command.
|
369
|
+
eval_string.replace "Thread.current[:__pry_cmd_result__].retval\n"
|
370
|
+
end
|
371
|
+
true
|
360
372
|
else
|
361
|
-
|
362
|
-
# so this ignores their result
|
363
|
-
eval_string << "#{val.rstrip}\n" if !val.empty?
|
373
|
+
false
|
364
374
|
end
|
365
375
|
end
|
366
376
|
|
@@ -372,7 +382,7 @@ class Pry
|
|
372
382
|
# @example
|
373
383
|
# pry_instance.run_command("ls -m")
|
374
384
|
def run_command(val, eval_string = "", target = binding_stack.last)
|
375
|
-
|
385
|
+
@command_processor.process_commands(val, eval_string, target)
|
376
386
|
Pry::CommandContext::VOID_VALUE
|
377
387
|
end
|
378
388
|
|
@@ -480,14 +490,17 @@ class Pry
|
|
480
490
|
|
481
491
|
# Returns the appropriate prompt to use.
|
482
492
|
# This method should not need to be invoked directly.
|
483
|
-
# @param [
|
484
|
-
#
|
485
|
-
# @param [Object] target_self The receiver of the Pry session.
|
493
|
+
# @param [String] eval_string The current input buffer.
|
494
|
+
# @param [Binding] target The target Binding of the Pry session.
|
486
495
|
# @return [String] The prompt.
|
487
|
-
def select_prompt(
|
496
|
+
def select_prompt(eval_string, target)
|
497
|
+
target_self = target.eval('self')
|
488
498
|
|
489
|
-
|
499
|
+
# If input buffer is empty then use normal prompt
|
500
|
+
if eval_string.empty?
|
490
501
|
Array(prompt).first.call(target_self, binding_stack.size - 1, self)
|
502
|
+
|
503
|
+
# Otherwise use the wait prompt (indicating multi-line expression)
|
491
504
|
else
|
492
505
|
Array(prompt).last.call(target_self, binding_stack.size - 1, self)
|
493
506
|
end
|
@@ -526,45 +539,47 @@ class Pry
|
|
526
539
|
prompt_stack.size > 1 ? prompt_stack.pop : prompt
|
527
540
|
end
|
528
541
|
|
529
|
-
if
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
542
|
+
# Determine if a string of code is a complete Ruby expression.
|
543
|
+
# @param [String] code The code to validate.
|
544
|
+
# @return [Boolean] Whether or not the code is a complete Ruby expression.
|
545
|
+
# @raise [SyntaxError] Any SyntaxError that does not represent incompleteness.
|
546
|
+
# @example
|
547
|
+
# complete_expression?("class Hello") #=> false
|
548
|
+
# complete_expression?("class Hello; end") #=> true
|
549
|
+
def complete_expression?(str)
|
550
|
+
if defined?(Rubinius::Melbourne19) && RUBY_VERSION =~ /^1\.9/
|
551
|
+
Rubinius::Melbourne19.parse_string(str, Pry.eval_path)
|
552
|
+
elsif defined?(Rubinius::Melbourne)
|
553
|
+
Rubinius::Melbourne.parse_string(str, Pry.eval_path)
|
554
|
+
else
|
555
|
+
catch(:valid) {
|
556
|
+
eval("BEGIN{throw :valid}\n#{str}", binding, Pry.eval_path)
|
557
|
+
}
|
541
558
|
end
|
542
559
|
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
JRuby.parse(code)
|
548
|
-
true
|
549
|
-
rescue SyntaxError
|
560
|
+
# Assert that a line which ends with a , or a \ is incomplete.
|
561
|
+
str !~ /[,\\]$/
|
562
|
+
rescue SyntaxError => e
|
563
|
+
if incomplete_user_input_exception?(e)
|
550
564
|
false
|
565
|
+
else
|
566
|
+
raise e
|
551
567
|
end
|
568
|
+
end
|
552
569
|
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
# NOTE: we're using .dup because RubyParser mutates the input
|
565
|
-
RubyParser.new.parse(code.dup)
|
570
|
+
# Check whether the exception indicates that the user should input more.
|
571
|
+
#
|
572
|
+
# @param [SyntaxError] the exception object that was raised.
|
573
|
+
# @param [Array<String>] The stack frame of the function that executed eval.
|
574
|
+
# @return [Boolean]
|
575
|
+
#
|
576
|
+
def incomplete_user_input_exception?(ex)
|
577
|
+
case ex.message
|
578
|
+
when /unexpected (\$end|end-of-file|END_OF_FILE)/, # mri, jruby, ironruby
|
579
|
+
/unterminated (quoted string|string|regexp) meets end of file/, # "quoted string" is ironruby
|
580
|
+
/missing 'end' for/, /: expecting '[})\]]'$/, /can't find string ".*" anywhere before EOF/, /expecting keyword_end/ # rbx
|
566
581
|
true
|
567
|
-
|
582
|
+
else
|
568
583
|
false
|
569
584
|
end
|
570
585
|
end
|