pry 0.9.7.4 → 0.9.8pre2
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.
- 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
|