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.
Files changed (49) hide show
  1. data/.gitignore +1 -3
  2. data/README.markdown +3 -1
  3. data/Rakefile +48 -31
  4. data/bin/pry +2 -80
  5. data/lib/pry.rb +17 -20
  6. data/lib/pry/cli.rb +152 -0
  7. data/lib/pry/command_processor.rb +13 -0
  8. data/lib/pry/command_set.rb +102 -9
  9. data/lib/pry/config.rb +28 -6
  10. data/lib/pry/default_commands/context.rb +9 -8
  11. data/lib/pry/default_commands/documentation.rb +55 -13
  12. data/lib/pry/default_commands/easter_eggs.rb +1 -1
  13. data/lib/pry/default_commands/input.rb +25 -25
  14. data/lib/pry/default_commands/introspection.rb +19 -18
  15. data/lib/pry/default_commands/ls.rb +23 -38
  16. data/lib/pry/default_commands/shell.rb +47 -15
  17. data/lib/pry/helpers/command_helpers.rb +28 -6
  18. data/lib/pry/helpers/options_helpers.rb +7 -4
  19. data/lib/pry/helpers/text.rb +23 -3
  20. data/lib/pry/history.rb +55 -17
  21. data/lib/pry/history_array.rb +2 -0
  22. data/lib/pry/hooks.rb +108 -0
  23. data/lib/pry/indent.rb +9 -5
  24. data/lib/pry/method.rb +99 -50
  25. data/lib/pry/plugins.rb +10 -2
  26. data/lib/pry/pry_class.rb +48 -20
  27. data/lib/pry/pry_instance.rb +106 -91
  28. data/lib/pry/version.rb +1 -1
  29. data/lib/pry/wrapped_module.rb +73 -0
  30. data/man/pry.1 +195 -0
  31. data/man/pry.1.html +204 -0
  32. data/man/pry.1.ronn +141 -0
  33. data/pry.gemspec +21 -24
  34. data/test/helper.rb +12 -3
  35. data/test/test_cli.rb +78 -0
  36. data/test/test_command_set.rb +193 -1
  37. data/test/test_default_commands/test_context.rb +19 -4
  38. data/test/test_default_commands/test_input.rb +2 -2
  39. data/test/test_default_commands/test_introspection.rb +63 -6
  40. data/test/test_default_commands/test_ls.rb +8 -35
  41. data/test/test_default_commands/test_shell.rb +36 -1
  42. data/test/test_hooks.rb +175 -0
  43. data/test/test_indent.rb +2 -0
  44. data/test/test_method.rb +10 -0
  45. data/test/test_pry.rb +35 -34
  46. data/test/test_pry_history.rb +24 -24
  47. data/test/test_syntax_checking.rb +47 -0
  48. data/test/test_wrapped_module.rb +71 -0
  49. 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 disabled)
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
- if initial_session?
86
- # note these have to be loaded here rather than in pry_instance as
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
- new(options).repl(target)
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(history_file) if File.exists?(history_file)
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(history_file)
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 => {}).rep(options[:context])
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
@@ -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 || target_self
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
- val = retrieve_line(eval_string, target)
263
-
264
- # eval_string may be mutated by this method
265
- process_line(val, eval_string, target)
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 valid_expression?(eval_string)
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
- # Read a line of input and check for ^d, also determine prompt to use.
298
- # This method should not need to be invoked directly. This method also
299
- # automatically indents the input value using Pry::Indent if auto
300
- # indenting is enabled.
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.empty?, target.eval('self'))
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 + indentation)
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
- else
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
- if !@command_processor.valid_command?(val, target) && Pry.config.auto_indent && !input.is_a?(StringIO)
327
- orig_val = "#{indentation}#{val}"
328
- val = @indent.indent(val)
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
- if orig_val != val && output.tty? && Pry::Helpers::BaseHelpers.use_ansi_codes? && Pry.config.correct_indent
331
- output.print @indent.correct_indentation(current_prompt + val, orig_val.length - val.length)
332
- end
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
- Pry.history << val.dup unless input.is_a?(StringIO)
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
- # Process the line received.
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
- def process_line(val, eval_string, target)
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? && !result.void_command?
355
-
356
- # the command that was invoked was non-void (had a return value) and so we make
357
- # the value of the current expression equal to the return value
358
- # of the command.
359
- eval_string.replace "Thread.current[:__pry_cmd_result__].retval\n"
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
- # only commands should have an empty `val`
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
- process_line(val, eval_string, target)
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 [Boolean] first_line Whether this is the first line of input
484
- # (and not multi-line input).
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(first_line, target_self)
496
+ def select_prompt(eval_string, target)
497
+ target_self = target.eval('self')
488
498
 
489
- if first_line
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 RUBY_VERSION =~ /1.9/ && RUBY_ENGINE == "ruby"
530
- require 'ripper'
531
-
532
- # Determine if a string of code is a valid Ruby expression.
533
- # Ruby 1.9 uses Ripper, Ruby 1.8 uses RubyParser.
534
- # @param [String] code The code to validate.
535
- # @return [Boolean] Whether or not the code is a valid Ruby expression.
536
- # @example
537
- # valid_expression?("class Hello") #=> false
538
- # valid_expression?("class Hello; end") #=> true
539
- def valid_expression?(code)
540
- !!Ripper::SexpBuilder.new(code).parse
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
- elsif RUBY_VERSION =~ /1.9/ && RUBY_ENGINE == 'jruby'
544
-
545
- # JRuby doesn't have Ripper, so use its native parser for 1.9 mode.
546
- def valid_expression?(code)
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
- else
554
- require 'ruby_parser'
555
-
556
- # Determine if a string of code is a valid Ruby expression.
557
- # Ruby 1.9 uses Ripper, Ruby 1.8 uses RubyParser.
558
- # @param [String] code The code to validate.
559
- # @return [Boolean] Whether or not the code is a valid Ruby expression.
560
- # @example
561
- # valid_expression?("class Hello") #=> false
562
- # valid_expression?("class Hello; end") #=> true
563
- def valid_expression?(code)
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
- rescue Racc::ParseError, SyntaxError
582
+ else
568
583
  false
569
584
  end
570
585
  end