pry 0.9.9.6 → 0.9.10pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/CHANGELOG +35 -0
  2. data/CONTRIBUTORS +27 -26
  3. data/README.markdown +4 -4
  4. data/Rakefile +2 -2
  5. data/lib/pry.rb +25 -19
  6. data/lib/pry/cli.rb +31 -10
  7. data/lib/pry/code.rb +41 -83
  8. data/lib/pry/command.rb +87 -76
  9. data/lib/pry/command_set.rb +13 -20
  10. data/lib/pry/completion.rb +139 -121
  11. data/lib/pry/config.rb +4 -0
  12. data/lib/pry/core_extensions.rb +87 -30
  13. data/lib/pry/default_commands/cd.rb +31 -8
  14. data/lib/pry/default_commands/context.rb +4 -58
  15. data/lib/pry/default_commands/easter_eggs.rb +1 -1
  16. data/lib/pry/default_commands/editing.rb +21 -14
  17. data/lib/pry/default_commands/find_method.rb +5 -7
  18. data/lib/pry/default_commands/gist.rb +187 -0
  19. data/lib/pry/default_commands/hist.rb +6 -6
  20. data/lib/pry/default_commands/input_and_output.rb +73 -129
  21. data/lib/pry/default_commands/introspection.rb +107 -52
  22. data/lib/pry/default_commands/ls.rb +1 -1
  23. data/lib/pry/default_commands/misc.rb +0 -5
  24. data/lib/pry/default_commands/whereami.rb +92 -0
  25. data/lib/pry/helpers/base_helpers.rb +6 -1
  26. data/lib/pry/helpers/command_helpers.rb +30 -9
  27. data/lib/pry/helpers/documentation_helpers.rb +7 -7
  28. data/lib/pry/helpers/options_helpers.rb +1 -1
  29. data/lib/pry/helpers/text.rb +7 -9
  30. data/lib/pry/history.rb +15 -2
  31. data/lib/pry/hooks.rb +1 -1
  32. data/lib/pry/indent.rb +17 -10
  33. data/lib/pry/method.rb +35 -19
  34. data/lib/pry/module_candidate.rb +130 -0
  35. data/lib/pry/pry_class.rb +54 -22
  36. data/lib/pry/pry_instance.rb +71 -14
  37. data/lib/pry/repl_file_loader.rb +80 -0
  38. data/lib/pry/version.rb +1 -1
  39. data/lib/pry/wrapped_module.rb +121 -142
  40. data/pry.gemspec +12 -12
  41. data/test/candidate_helper1.rb +11 -0
  42. data/test/candidate_helper2.rb +8 -0
  43. data/test/helper.rb +16 -0
  44. data/test/test_code.rb +1 -1
  45. data/test/test_command.rb +364 -270
  46. data/test/test_command_integration.rb +235 -267
  47. data/test/test_completion.rb +36 -0
  48. data/test/test_control_d_handler.rb +45 -0
  49. data/test/test_default_commands/example.erb +5 -0
  50. data/test/test_default_commands/test_cd.rb +316 -11
  51. data/test/test_default_commands/test_context.rb +143 -192
  52. data/test/test_default_commands/test_documentation.rb +81 -14
  53. data/test/test_default_commands/test_find_method.rb +10 -2
  54. data/test/test_default_commands/test_input.rb +102 -111
  55. data/test/test_default_commands/test_introspection.rb +17 -12
  56. data/test/test_default_commands/test_ls.rb +8 -6
  57. data/test/test_default_commands/test_shell.rb +18 -15
  58. data/test/test_default_commands/test_show_source.rb +170 -44
  59. data/test/test_exception_whitelist.rb +6 -2
  60. data/test/test_hooks.rb +32 -0
  61. data/test/test_input_stack.rb +19 -16
  62. data/test/test_method.rb +0 -4
  63. data/test/test_prompt.rb +60 -0
  64. data/test/test_pry.rb +23 -31
  65. data/test/test_pry_defaults.rb +75 -57
  66. data/test/test_syntax_checking.rb +12 -11
  67. data/test/test_wrapped_module.rb +103 -0
  68. metadata +65 -24
@@ -5,7 +5,8 @@ require 'pry/config'
5
5
  class Pry
6
6
 
7
7
  # The RC Files to load.
8
- RC_FILES = ["~/.pryrc", "./.pryrc"]
8
+ RC_FILES = ["~/.pryrc"]
9
+ LOCAL_RC_FILE = "./.pryrc"
9
10
 
10
11
  # class accessors
11
12
  class << self
@@ -43,12 +44,12 @@ class Pry
43
44
  # @return [Boolean] Whether Pry was activated from the command line.
44
45
  attr_accessor :cli
45
46
 
46
- # @return [Fixnum] The number of active Pry sessions.
47
- attr_accessor :active_sessions
48
-
49
47
  # @return [Boolean] Whether Pry sessions are quiet by default.
50
48
  attr_accessor :quiet
51
49
 
50
+ # @return [Binding] A top level binding with no local variables
51
+ attr_accessor :toplevel_binding
52
+
52
53
  # plugin forwardables
53
54
  def_delegators :@plugin_manager, :plugins, :load_plugins, :locate_plugins
54
55
 
@@ -56,19 +57,31 @@ class Pry
56
57
  :hooks, :color, :pager, :editor, :memory_size, :input_stack, :extra_sticky_locals
57
58
  end
58
59
 
60
+
61
+ # Load the given file in the context of `Pry.toplevel_binding`
62
+ # @param [String] file_name The unexpanded file path.
63
+ def self.load_file_at_toplevel(file_name)
64
+ full_name = File.expand_path(file_name)
65
+ begin
66
+ toplevel_binding.eval(File.read(full_name)) if File.exists?(full_name)
67
+ rescue RescuableException => e
68
+ puts "Error loading #{file_name}: #{e}"
69
+ end
70
+ end
71
+
59
72
  # Load the rc files given in the `Pry::RC_FILES` array.
60
73
  # This method can also be used to reload the files if they have changed.
61
74
  def self.load_rc
62
- files = RC_FILES.collect { |file_name| File.expand_path(file_name) }.uniq
63
- files.each do |file_name|
64
- begin
65
- load(file_name) if File.exists?(file_name)
66
- rescue RescuableException => e
67
- puts "Error loading #{file_name}: #{e}"
68
- end
75
+ RC_FILES.uniq.each do |file_name|
76
+ load_file_at_toplevel(file_name)
69
77
  end
70
78
  end
71
79
 
80
+ # Load the local RC file (./.pryrc)
81
+ def self.load_local_rc
82
+ load_file_at_toplevel(LOCAL_RC_FILE)
83
+ end
84
+
72
85
  # Load any Ruby files specified with the -r flag on the command line.
73
86
  def self.load_requires
74
87
  Pry.config.requires.each do |file|
@@ -92,6 +105,7 @@ class Pry
92
105
  # note these have to be loaded here rather than in pry_instance as
93
106
  # we only want them loaded once per entire Pry lifetime.
94
107
  load_rc if Pry.config.should_load_rc
108
+ load_local_rc if Pry.config.should_load_local_rc
95
109
  load_plugins if Pry.config.should_load_plugins
96
110
  load_requires if Pry.config.should_load_requires
97
111
  load_history if Pry.config.history.should_load
@@ -108,7 +122,7 @@ class Pry
108
122
  # @option options (see Pry#initialize)
109
123
  # @example
110
124
  # Pry.start(Object.new, :input => MyInput.new)
111
- def self.start(target=TOPLEVEL_BINDING, options={})
125
+ def self.start(target=toplevel_binding, options={})
112
126
  target = Pry.binding_for(target)
113
127
  initial_session_setup
114
128
 
@@ -122,12 +136,7 @@ class Pry
122
136
  pry_instance.backtrace.shift if pry_instance.backtrace.first =~ /pry.*core_extensions.*pry/
123
137
 
124
138
  # yield the binding_stack to the hook for modification
125
- pry_instance.exec_hook(
126
- :when_started,
127
- target,
128
- options,
129
- pry_instance
130
- )
139
+ pry_instance.exec_hook(:when_started, target, options, pry_instance)
131
140
 
132
141
  if !pry_instance.binding_stack.empty?
133
142
  head = pry_instance.binding_stack.pop
@@ -135,10 +144,23 @@ class Pry
135
144
  head = target
136
145
  end
137
146
 
147
+ # Clear the line before starting Pry. This fixes the issue discussed here:
148
+ # https://github.com/pry/pry/issues/566
149
+ if Pry.config.auto_indent
150
+ Kernel.print Pry::Helpers::BaseHelpers.windows_ansi? ? "\e[0F" : "\e[0G"
151
+ end
152
+
138
153
  # Enter the matrix
139
154
  pry_instance.repl(head)
140
155
  end
141
156
 
157
+ # Execute the file through the REPL loop, non-interactively.
158
+ # @param [String] file_name File name to load through the REPL.
159
+ def self.load_file_through_repl(file_name)
160
+ require "pry/repl_file_loader"
161
+ REPLFileLoader.new(file_name).load
162
+ end
163
+
142
164
  # An inspector that clips the output to `max_length` chars.
143
165
  # In case of > `max_length` chars the `#<Object...> notation is used.
144
166
  # @param obj The object to view.
@@ -178,7 +200,7 @@ class Pry
178
200
 
179
201
  # Run a Pry command from outside a session. The commands available are
180
202
  # those referenced by `Pry.commands` (the default command set).
181
- # @param [String] arg_string The Pry command (including arguments,
203
+ # @param [String] command_string The Pry command (including arguments,
182
204
  # if any).
183
205
  # @param [Hash] options Optional named parameters.
184
206
  # @return [Object] The return value of the Pry command.
@@ -234,10 +256,11 @@ class Pry
234
256
  config.system = DEFAULT_SYSTEM
235
257
  config.editor = default_editor_for_platform
236
258
  config.should_load_rc = true
259
+ config.should_load_local_rc = true
237
260
  config.should_trap_interrupts = Helpers::BaseHelpers.jruby?
238
261
  config.disable_auto_reload = false
239
262
  config.command_prefix = ""
240
- config.auto_indent = true
263
+ config.auto_indent = Helpers::BaseHelpers.use_ansi_codes?
241
264
  config.correct_indent = true
242
265
  config.collision_warning = false
243
266
 
@@ -312,7 +335,6 @@ class Pry
312
335
  self.current_line = 1
313
336
  self.line_buffer = [""]
314
337
  self.eval_path = "(pry)"
315
- self.active_sessions = 0
316
338
 
317
339
  fix_coderay_colors
318
340
  end
@@ -328,7 +350,7 @@ class Pry
328
350
  begin
329
351
  require 'coderay/encoders/term'
330
352
  CodeRay::Encoders::Term::TOKEN_COLORS
331
- rescue => e
353
+ rescue
332
354
  end
333
355
  end
334
356
 
@@ -363,4 +385,14 @@ class Pry
363
385
  end
364
386
  end
365
387
 
388
+ # Grab a copy of the TOPLEVEL_BINDING without any local variables.
389
+ # This binding has a default definee of Object, and new methods are
390
+ # private (just as in TOPLEVEL_BINDING).
391
+ def self.__binding_impl__
392
+ binding
393
+ end
394
+ Pry.toplevel_binding = __binding_impl__
395
+ Pry.toplevel_binding.eval("private")
396
+ class << self; undef __binding_impl__; end
397
+
366
398
  Pry.init
@@ -1,5 +1,26 @@
1
1
  require "pry/indent"
2
2
 
3
+ ##
4
+ # Pry is a powerful alternative to the standard IRB shell for Ruby. It
5
+ # features syntax highlighting, a flexible plugin architecture, runtime
6
+ # invocation and source and documentation browsing.
7
+ #
8
+ # Pry can be started similar to other command line utilities by simply running
9
+ # the following command:
10
+ #
11
+ # pry
12
+ #
13
+ # Once inside Pry you can invoke the help message:
14
+ #
15
+ # help
16
+ #
17
+ # This will show a list of available commands and their usage. For more
18
+ # information about Pry you can refer to the following resources:
19
+ #
20
+ # * http://pry.github.com/
21
+ # * https://github.com/pry/pry
22
+ # * the IRC channel, which is #pry on the Freenode network
23
+ #
3
24
  class Pry
4
25
 
5
26
  attr_accessor :input
@@ -28,6 +49,11 @@ class Pry
28
49
 
29
50
  attr_accessor :extra_sticky_locals
30
51
 
52
+ attr_accessor :suppress_output
53
+
54
+ # This is exposed via Pry::Command#state.
55
+ attr_reader :command_state
56
+
31
57
  # Special treatment for hooks as we want to alert people of the
32
58
  # changed API
33
59
  attr_reader :hooks
@@ -57,8 +83,9 @@ class Pry
57
83
  def initialize(options={})
58
84
  refresh(options)
59
85
 
60
- @binding_stack = []
61
- @indent = Pry::Indent.new
86
+ @binding_stack = []
87
+ @indent = Pry::Indent.new
88
+ @command_state = {}
62
89
  end
63
90
 
64
91
  # Refresh the Pry instance settings from the Pry class.
@@ -117,7 +144,7 @@ class Pry
117
144
  # @return [Object] The value the local was set to.
118
145
  def inject_local(name, value, b)
119
146
  Thread.current[:__pry_local__] = value.is_a?(Proc) ? value.call : value
120
- b.eval("#{name} = Thread.current[:__pry_local__]")
147
+ b.eval("#{name} = ::Thread.current[:__pry_local__]")
121
148
  ensure
122
149
  Thread.current[:__pry_local__] = nil
123
150
  end
@@ -172,7 +199,6 @@ class Pry
172
199
 
173
200
  @input_array << nil # add empty input so _in_ and _out_ match
174
201
 
175
- Pry.active_sessions += 1
176
202
  binding_stack.push target
177
203
  end
178
204
 
@@ -181,9 +207,8 @@ class Pry
181
207
  def repl_epilogue(target)
182
208
  exec_hook :after_session, output, target, self
183
209
 
184
- Pry.active_sessions -= 1
185
210
  binding_stack.pop
186
- Pry.save_history if Pry.config.history.should_save && Pry.active_sessions == 0
211
+ Pry.save_history if Pry.config.history.should_save
187
212
  end
188
213
 
189
214
  # Start a read-eval-print-loop.
@@ -196,7 +221,6 @@ class Pry
196
221
  # Pry.new.repl(Object.new)
197
222
  def repl(target=TOPLEVEL_BINDING)
198
223
  target = Pry.binding_for(target)
199
- target_self = target.eval('self')
200
224
 
201
225
  repl_prologue(target)
202
226
 
@@ -246,6 +270,8 @@ class Pry
246
270
 
247
271
  code = r(target)
248
272
 
273
+ exec_hook :before_eval, code, self
274
+
249
275
  result = target.eval(code, Pry.eval_path, Pry.current_line)
250
276
  set_last_result(result, target, code)
251
277
 
@@ -272,12 +298,11 @@ class Pry
272
298
  target = Pry.binding_for(target)
273
299
  @suppress_output = false
274
300
 
275
- val = ""
276
301
  loop do
277
302
  begin
278
303
  # eval_string will probably be mutated by this method
279
304
  retrieve_line(eval_string, target)
280
- rescue CommandError, Slop::InvalidOptionError => e
305
+ rescue CommandError, Slop::InvalidOptionError, MethodSource::SourceNotFoundError => e
281
306
  output.puts "Error: #{e.message}"
282
307
  end
283
308
 
@@ -298,9 +323,9 @@ class Pry
298
323
  # Output the result or pass to an exception handler (if result is an exception).
299
324
  def show_result(result)
300
325
  if last_result_is_exception?
301
- exception_handler.call output, result, self
326
+ exception_handler.call(output, result, self)
302
327
  else
303
- print.call output, result
328
+ print.call(output, result)
304
329
  end
305
330
  rescue RescuableException => e
306
331
  # Being uber-paranoid here, given that this exception arose because we couldn't
@@ -346,7 +371,7 @@ class Pry
346
371
  # Handle <Ctrl+C> like Bash, empty the current input buffer but do not quit.
347
372
  # This is only for ruby-1.9; other versions of ruby do not let you send Interrupt
348
373
  # from within Readline.
349
- rescue Interrupt => e
374
+ rescue Interrupt
350
375
  output.puts ""
351
376
  eval_string.replace("")
352
377
  return
@@ -514,6 +539,7 @@ class Pry
514
539
  # Manage switching of input objects on encountering EOFErrors
515
540
  def handle_read_errors
516
541
  should_retry = true
542
+ exception_count = 0
517
543
  begin
518
544
  yield
519
545
  rescue EOFError
@@ -527,6 +553,7 @@ class Pry
527
553
  else
528
554
  self.input = input_stack.pop
529
555
  end
556
+
530
557
  retry
531
558
 
532
559
  # Interrupts are handled in r() because they need to tweak eval_string
@@ -539,6 +566,11 @@ class Pry
539
566
  # anything about it.
540
567
  rescue RescuableException => e
541
568
  puts "Error: #{e.message}"
569
+ output.puts e.backtrace
570
+ exception_count += 1
571
+ if exception_count < 5
572
+ retry
573
+ end
542
574
  puts "FATAL: Pry failed to get user input using `#{input}`."
543
575
  puts "To fix this you may be able to pass input and output file descriptors to pry directly. e.g."
544
576
  puts " Pry.config.input = STDIN"
@@ -594,15 +626,40 @@ class Pry
594
626
  def select_prompt(eval_string, target)
595
627
  target_self = target.eval('self')
596
628
 
629
+ open_token = @indent.open_delimiters.any? ? @indent.open_delimiters.last :
630
+ @indent.stack.last
631
+
632
+ c = OpenStruct.new(
633
+ :object => target_self,
634
+ :nesting_level => binding_stack.size - 1,
635
+ :open_token => open_token,
636
+ :session_line => Pry.history.session_line_count + 1,
637
+ :history_line => Pry.history.history_line_count + 1,
638
+ :expr_number => input_array.count,
639
+ :_pry_ => self,
640
+ :binding_stack => binding_stack,
641
+ :input_array => input_array,
642
+ :eval_string => eval_string,
643
+ :cont => !eval_string.empty?)
644
+
597
645
  # If input buffer is empty then use normal prompt
598
646
  if eval_string.empty?
599
- Array(prompt).first.call(target_self, binding_stack.size - 1, self)
647
+ generate_prompt(Array(prompt).first, c)
600
648
 
601
649
  # Otherwise use the wait prompt (indicating multi-line expression)
602
650
  else
603
- Array(prompt).last.call(target_self, binding_stack.size - 1, self)
651
+ generate_prompt(Array(prompt).last, c)
652
+ end
653
+ end
654
+
655
+ def generate_prompt(prompt_proc, conf)
656
+ if prompt_proc.arity == 1
657
+ prompt_proc.call(conf)
658
+ else
659
+ prompt_proc.call(conf.object, conf.nesting_level, conf._pry_)
604
660
  end
605
661
  end
662
+ private :generate_prompt
606
663
 
607
664
  # the array that the prompt stack is stored in
608
665
  def prompt_stack
@@ -0,0 +1,80 @@
1
+ class Pry
2
+
3
+ # A class to manage the loading of files through the REPL loop.
4
+ # This is an interesting trick as it processes your file as if it
5
+ # was user input in an interactive session. As a result, all Pry
6
+ # commands are available, and they are executed non-interactively. Furthermore
7
+ # the session becomes interactive when the repl loop processes a
8
+ # 'make-interactive' command in the file. The session also becomes
9
+ # interactive when an exception is encountered, enabling you to fix
10
+ # the error before returning to non-interactive processing with the
11
+ # 'make-non-interactive' command.
12
+
13
+ class REPLFileLoader
14
+ def initialize(file_name)
15
+ full_name = File.expand_path(file_name)
16
+ raise RuntimeError, "No such file: #{full_name}" if !File.exists?(full_name)
17
+
18
+ @content = StringIO.new(File.read(full_name))
19
+ end
20
+
21
+ # Switch to interactive mode, i.e take input from the user
22
+ # and use the regular print and exception handlers.
23
+ # @param [Pry] _pry_ the Pry instance to make interactive.
24
+ def interactive_mode(_pry_)
25
+ _pry_.input = Pry.config.input
26
+ _pry_.print = Pry.config.print
27
+ _pry_.exception_handler = Pry.config.exception_handler
28
+ end
29
+
30
+ # Switch to non-interactive mode. Essentially
31
+ # this means there is no result output
32
+ # and that the session becomes interactive when an exception is encountered.
33
+ # @param [Pry] _pry_ the Pry instance to make non-interactive.
34
+ def non_interactive_mode(_pry_)
35
+ _pry_.print = proc {}
36
+ _pry_.exception_handler = proc do |o, e, _pry_|
37
+ _pry_.run_command "cat --ex"
38
+ o.puts "...exception encountered, going interactive!"
39
+ interactive_mode(_pry_)
40
+ end
41
+ end
42
+
43
+ # Define a few extra commands useful for flipping back & forth
44
+ # between interactive/non-interactive modes
45
+ def define_additional_commands
46
+ s = self
47
+
48
+ Pry::Commands.command "make-interactive", "Make the session interactive" do
49
+ _pry_.input_stack.push _pry_.input
50
+ s.interactive_mode(_pry_)
51
+ end
52
+
53
+ Pry::Commands.command "make-non-interactive", "Make the session non-interactive" do
54
+ _pry_.input = _pry_.input_stack.pop
55
+ s.non_interactive_mode(_pry_)
56
+ end
57
+
58
+ Pry::Commands.command "load-file", "Load another file through the repl" do |file_name|
59
+ content = StringIO.new(File.read(File.expand_path(file_name)))
60
+ _pry_.input_stack.push(_pry_.input)
61
+ _pry_.input = content
62
+ end
63
+ end
64
+
65
+ # Actually load the file through the REPL by setting file content
66
+ # as the REPL input stream.
67
+ def load
68
+ Pry.initial_session_setup
69
+ define_additional_commands
70
+
71
+ Pry.config.hooks.add_hook(:when_started, :start_non_interactively) do |o, t, _pry_|
72
+ non_interactive_mode(_pry_)
73
+ end
74
+
75
+ Pry.start(Pry.toplevel_binding,
76
+ :input => @content,
77
+ :input_stack => [StringIO.new("exit-all\n")])
78
+ end
79
+ end
80
+ end
@@ -1,3 +1,3 @@
1
1
  class Pry
2
- VERSION = "0.9.9.6"
2
+ VERSION = "0.9.10pre1"
3
3
  end