pry 0.9.0pre3-java → 0.9.4pre2-java

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.
Files changed (47) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG +84 -6
  3. data/CONTRIBUTORS +13 -0
  4. data/README.markdown +23 -183
  5. data/Rakefile +22 -19
  6. data/TODO +36 -6
  7. data/bin/pry +12 -1
  8. data/lib/pry.rb +60 -12
  9. data/lib/pry/command_context.rb +21 -0
  10. data/lib/pry/command_processor.rb +62 -16
  11. data/lib/pry/command_set.rb +25 -11
  12. data/lib/pry/commands.rb +0 -3
  13. data/lib/pry/completion.rb +6 -6
  14. data/lib/pry/config.rb +25 -5
  15. data/lib/pry/default_commands/basic.rb +27 -6
  16. data/lib/pry/default_commands/context.rb +84 -35
  17. data/lib/pry/default_commands/documentation.rb +69 -31
  18. data/lib/pry/default_commands/easter_eggs.rb +5 -0
  19. data/lib/pry/default_commands/input.rb +193 -56
  20. data/lib/pry/default_commands/introspection.rb +98 -50
  21. data/lib/pry/default_commands/ls.rb +51 -21
  22. data/lib/pry/default_commands/shell.rb +57 -13
  23. data/lib/pry/extended_commands/experimental.rb +0 -32
  24. data/lib/pry/extended_commands/user_command_api.rb +33 -2
  25. data/lib/pry/helpers/base_helpers.rb +30 -10
  26. data/lib/pry/helpers/command_helpers.rb +75 -16
  27. data/lib/pry/helpers/text.rb +12 -11
  28. data/lib/pry/history.rb +61 -0
  29. data/lib/pry/plugins.rb +23 -12
  30. data/lib/pry/pry_class.rb +51 -50
  31. data/lib/pry/pry_instance.rb +129 -119
  32. data/lib/pry/version.rb +1 -1
  33. data/pry.gemspec +46 -0
  34. data/test/helper.rb +37 -3
  35. data/test/test_command_processor.rb +62 -19
  36. data/test/test_command_set.rb +40 -2
  37. data/test/test_completion.rb +27 -0
  38. data/test/test_default_commands/test_context.rb +185 -1
  39. data/test/test_default_commands/test_documentation.rb +10 -0
  40. data/test/test_default_commands/test_input.rb +207 -11
  41. data/test/test_default_commands/test_introspection.rb +20 -1
  42. data/test/test_default_commands/test_shell.rb +18 -0
  43. data/test/test_pry.rb +261 -45
  44. data/test/test_pry_history.rb +82 -0
  45. data/test/test_pry_output.rb +44 -0
  46. data/test/test_special_locals.rb +35 -0
  47. metadata +185 -159
@@ -1,10 +1,10 @@
1
1
  class Pry
2
2
  module Helpers
3
3
 
4
- # The methods defined on {Text} are available to custom commands via {Pry::CommandContext#text}.
4
+ # The methods defined on {Text} are available to custom commands via {Pry::CommandContext#text}.
5
5
  module Text
6
-
7
- COLORS =
6
+
7
+ COLORS =
8
8
  {
9
9
  "black" => 0,
10
10
  "red" => 1,
@@ -18,7 +18,7 @@ class Pry
18
18
  }
19
19
 
20
20
  class << self
21
-
21
+
22
22
  COLORS.each_pair do |color, value|
23
23
  define_method color do |text|
24
24
  Pry.color ? "\033[0;#{30+value}m#{text}\033[0m" : text.to_s
@@ -31,7 +31,7 @@ class Pry
31
31
 
32
32
  alias_method :grey, :bright_black
33
33
  alias_method :gray, :bright_black
34
-
34
+
35
35
 
36
36
  # Remove any color codes from _text_.
37
37
  #
@@ -41,11 +41,11 @@ class Pry
41
41
  text.to_s.gsub(/\e\[.*?(\d)+m/ , '')
42
42
  end
43
43
 
44
- # Returns _text_ as bold text for use on a terminal.
44
+ # Returns _text_ as bold text for use on a terminal.
45
45
  # _Pry.color_ must be true for this method to perform any transformations.
46
46
  #
47
47
  # @param [String, #to_s] text
48
- # @return [String] _text_
48
+ # @return [String] _text_
49
49
  def bold text
50
50
  Pry.color ? "\e[1m#{text}\e[0m" : text.to_s
51
51
  end
@@ -63,15 +63,16 @@ class Pry
63
63
  end
64
64
 
65
65
  # Returns _text_ in a numbered list, beginning at _offset_.
66
- #
66
+ #
67
67
  # @param [#each_line] text
68
68
  # @param [Fixnum] offset
69
69
  # @return [String]
70
- def with_line_numbers text, offset
70
+ def with_line_numbers(text, offset, color=:blue)
71
71
  lines = text.each_line.to_a
72
+ max_width = (offset + lines.count).to_s.length
72
73
  lines.each_with_index.map do |line, index|
73
- adjusted_index = index + offset
74
- "#{self.blue adjusted_index}: #{line}"
74
+ adjusted_index = (index + offset).to_s.rjust(max_width)
75
+ "#{self.send(color, adjusted_index)}: #{line}"
75
76
  end.join
76
77
  end
77
78
  end
@@ -0,0 +1,61 @@
1
+ class Pry
2
+ # The History class is responsible for maintaining the user's input history, both
3
+ # internally and within Readline::HISTORY.
4
+ class History
5
+ def initialize
6
+ @history = []
7
+ @saved_lines = 0
8
+ end
9
+
10
+ # Loads a file's contents into the input history.
11
+ # @param [String] filename
12
+ # @return [Integer] The number of lines loaded
13
+ def load(filename)
14
+ File.foreach(filename) do |line|
15
+ Readline::HISTORY << line.chomp
16
+ @history << line.chomp
17
+ end
18
+ @saved_lines = @history.length
19
+ end
20
+
21
+ # Appends input history from this session to a file.
22
+ # @param [String] filename
23
+ # @return [Integer] The number of lines saved
24
+ def save(filename)
25
+ history_to_save = @history[@saved_lines..-1]
26
+ File.open(filename, 'a') do |f|
27
+ history_to_save.each { |ln| f.puts ln }
28
+ end
29
+ @saved_lines = @history.length
30
+ history_to_save.length
31
+ end
32
+
33
+ # Adds a line to the input history, ignoring blank and duplicate lines.
34
+ # @param [String] line
35
+ # @return [String] The same line that was passed in
36
+ def push(line)
37
+ unless line.empty? || (@history.last && line.strip == @history.last.strip)
38
+ Readline::HISTORY << line
39
+ @history << line
40
+ end
41
+ line
42
+ end
43
+ alias << push
44
+
45
+ # Clears all history. Anything the user entered before this point won't be
46
+ # saved, but anything they put in afterwards will still be appended to the
47
+ # history file on exit.
48
+ def clear
49
+ Readline::HISTORY.shift until Readline::HISTORY.empty?
50
+ @history = []
51
+ @saved_lines = 0
52
+ end
53
+
54
+ # Returns an Array containing all stored history.
55
+ # @return [Array<String>] An Array containing all lines of history loaded
56
+ # or entered by the user in the current session.
57
+ def to_a
58
+ @history.dup
59
+ end
60
+ end
61
+ end
data/lib/pry/plugins.rb CHANGED
@@ -1,33 +1,44 @@
1
1
  class Pry
2
2
  class PluginManager
3
3
  PRY_PLUGIN_PREFIX = /^pry-/
4
- PluginNotFound = Class.new(LoadError)
5
4
 
6
- MessageSink = Object.new.tap { |o| def o.method_missing(*args) end }
5
+ # Placeholder when no associated gem found, displays warning
6
+ class NoPlugin
7
+ def initialize(name)
8
+ @name = name
9
+ end
10
+
11
+ def method_missing(*args)
12
+ $stderr.puts "Warning: The plugin '#{@name}' was not found! (no gem found)"
13
+ end
14
+ end
7
15
 
8
16
  class Plugin
9
- attr_accessor :name, :gem_name, :enabled, :active
17
+ attr_accessor :name, :gem_name, :enabled, :spec, :active
10
18
 
11
- def initialize(name, gem_name, enabled)
12
- @name, @gem_name, @enabled = name, gem_name, enabled
19
+ def initialize(name, gem_name, spec, enabled)
20
+ @name, @gem_name, @enabled, @spec = name, gem_name, enabled, spec
13
21
  end
14
22
 
15
- # Disable a plugin.
23
+ # Disable a plugin. (prevents plugin from being loaded, cannot
24
+ # disable an already activated plugin)
16
25
  def disable!
17
26
  self.enabled = false
18
27
  end
19
28
 
20
- # Enable a plugin.
29
+ # Enable a plugin. (does not load it immediately but puts on
30
+ # 'white list' to be loaded)
21
31
  def enable!
22
32
  self.enabled = true
23
33
  end
24
34
 
25
- # Activate the plugin (require the gem).
35
+ # Activate the plugin (require the gem - enables/loads the
36
+ # plugin immediately at point of call, even if plugin is disabled)
26
37
  def activate!
27
38
  begin
28
- require gem_name
39
+ require gem_name if !active?
29
40
  rescue LoadError
30
- raise PluginNotFound, "The plugin '#{gem_name}' was not found!"
41
+ $stderr.puts "Warning: The plugin '#{gem_name}' was not found! (gem found but could not be loaded)"
31
42
  end
32
43
  self.active = true
33
44
  self.enabled = true
@@ -47,7 +58,7 @@ class Pry
47
58
  (Gem::Specification.respond_to?(:each) ? Gem::Specification : Gem.source_index.find_name('')).each do |gem|
48
59
  next if gem.name !~ PRY_PLUGIN_PREFIX
49
60
  plugin_name = gem.name.split('-', 2).last
50
- @plugins << Plugin.new(plugin_name, gem.name, true) if !gem_located?(gem.name)
61
+ @plugins << Plugin.new(plugin_name, gem.name, gem, true) if !gem_located?(gem.name)
51
62
  end
52
63
  @plugins
53
64
  end
@@ -55,7 +66,7 @@ class Pry
55
66
  # @return [Hash] A hash with all plugin names (minus the 'pry-') as
56
67
  # keys and Plugin objects as values.
57
68
  def plugins
58
- h = Pry.config.plugins.strict_loading ? {} : Hash.new { MessageSink }
69
+ h = Hash.new { |_, key| NoPlugin.new(key) }
59
70
  @plugins.each do |plugin|
60
71
  h[plugin.name] = plugin
61
72
  end
data/lib/pry/pry_class.rb CHANGED
@@ -18,26 +18,6 @@ class Pry
18
18
  def_delegators delagatee, *names.map { |v| "#{v}=" }
19
19
  end
20
20
 
21
- # Get nesting data.
22
- # This method should not need to be accessed directly.
23
- # @return [Array] The unparsed nesting information.
24
- attr_reader :nesting
25
-
26
- # Get last value evaluated by Pry.
27
- # This method should not need to be accessed directly.
28
- # @return [Object] The last result.
29
- attr_accessor :last_result
30
-
31
- # Get last exception raised.
32
- # This method should not need to be accessed directly.
33
- # @return [Exception] The last exception.
34
- attr_accessor :last_exception
35
-
36
- # Get the active Pry instance that manages the active Pry session.
37
- # This method should not need to be accessed directly.
38
- # @return [Pry] The active Pry instance.
39
- attr_accessor :active_instance
40
-
41
21
  # Get/Set the Proc that defines extra Readline completions (on top
42
22
  # of the ones defined for IRB).
43
23
  # @return [Proc] The Proc that defines extra Readline completions (on top
@@ -45,10 +25,6 @@ class Pry
45
25
  # Pry.custom_completions = proc { Dir.entries('.') }
46
26
  attr_accessor :custom_completions
47
27
 
48
- # Value returned by last executed Pry command.
49
- # @return [Object] The command value
50
- attr_accessor :cmd_ret_value
51
-
52
28
  # @return [Fixnum] The current input line.
53
29
  attr_accessor :current_line
54
30
 
@@ -62,9 +38,15 @@ class Pry
62
38
  # @return [OpenStruct] Return Pry's config object.
63
39
  attr_accessor :config
64
40
 
41
+ # @return [History] Return Pry's line history object.
42
+ attr_accessor :history
43
+
65
44
  # @return [Boolean] Whether Pry was activated from the command line.
66
45
  attr_accessor :cli
67
46
 
47
+ # @return [Fixnum] The number of active Pry sessions.
48
+ attr_accessor :active_sessions
49
+
68
50
  # plugin forwardables
69
51
  def_delegators :@plugin_manager, :plugins, :load_plugins, :locate_plugins
70
52
 
@@ -82,6 +64,13 @@ class Pry
82
64
  end
83
65
  end
84
66
 
67
+ # Load any Ruby files specified with the -r flag on the command line.
68
+ def self.load_requires
69
+ Pry.config.requires.each do |file|
70
+ require file
71
+ end
72
+ end
73
+
85
74
  # Start a Pry REPL.
86
75
  # This method also loads the files specified in `Pry::RC_FILES` the
87
76
  # first time it is invoked.
@@ -97,7 +86,8 @@ class Pry
97
86
  # multiple times per each new session (i.e in debugging)
98
87
  load_rc if Pry.config.should_load_rc
99
88
  load_plugins if Pry.config.plugins.enabled
100
- load_history if Pry.config.history.load
89
+ load_requires if Pry.config.should_load_requires
90
+ load_history if Pry.config.history.should_load
101
91
 
102
92
  @initial_session = false
103
93
  end
@@ -121,18 +111,32 @@ class Pry
121
111
  # @param obj The object to view.
122
112
  # @param max_size The maximum number of chars before clipping occurs.
123
113
  # @return [String] The string representation of `obj`.
124
- def self.view_clip(obj, max_size=60)
125
- if obj.inspect.size < max_size
114
+ def self.view_clip(obj, max_length = 60)
115
+ if obj.kind_of?(Module) && obj.name && obj.name != "" && obj.name.to_s.length <= max_length
116
+ obj.name.to_s
117
+ elsif obj.inspect.length <= max_length
126
118
  obj.inspect
127
- else
119
+ else
128
120
  "#<#{obj.class}:%#x>" % (obj.object_id << 1)
129
121
  end
122
+
123
+ rescue
124
+ "unknown"
130
125
  end
131
126
 
132
127
  # Load Readline history if required.
133
128
  def self.load_history
134
- history_file = File.expand_path(Pry.config.history.file)
135
- Readline::HISTORY.push(*File.readlines(history_file).map(&:chomp)) if File.exists?(history_file)
129
+ Pry.history.load(history_file) if File.exists?(history_file)
130
+ end
131
+
132
+ # Save new lines of Readline history if required.
133
+ def self.save_history
134
+ Pry.history.save(history_file)
135
+ end
136
+
137
+ # Get the full path of the history_path for pry.
138
+ def self.history_file
139
+ File.expand_path(Pry.config.history.file)
136
140
  end
137
141
 
138
142
  # @return [Boolean] Whether this is the first time a Pry session has
@@ -172,9 +176,9 @@ class Pry
172
176
 
173
177
  def self.default_editor_for_platform
174
178
  if RUBY_PLATFORM =~ /mswin|mingw/
175
- ENV['EDITOR'] ? ENV['EDITOR'] : "notepad"
179
+ ENV['VISUAL'] || ENV['EDITOR'] || "notepad"
176
180
  else
177
- ENV['EDITOR'] ? ENV['EDITOR'] : "nano"
181
+ ENV['VISUAL'] || ENV['EDITOR'] || "nano"
178
182
  end
179
183
  end
180
184
 
@@ -190,16 +194,23 @@ class Pry
190
194
  config.pager = true
191
195
  config.editor = default_editor_for_platform
192
196
  config.should_load_rc = true
197
+ config.disable_auto_reload = false
198
+ config.command_prefix = ""
193
199
 
194
200
  config.plugins ||= OpenStruct.new
195
201
  config.plugins.enabled = true
196
202
  config.plugins.strict_loading = true
197
203
 
204
+ config.requires ||= []
205
+ config.should_load_requires = true
206
+
198
207
  config.history ||= OpenStruct.new
199
- config.history.save = true
200
- config.history.load = true
208
+ config.history.should_save = true
209
+ config.history.should_load = true
201
210
  config.history.file = File.expand_path("~/.pry_history")
202
211
 
212
+ config.control_d_handler = DEFAULT_CONTROL_D_HANDLER
213
+
203
214
  config.memory_size = 100
204
215
  end
205
216
 
@@ -211,32 +222,22 @@ class Pry
211
222
 
212
223
  self.custom_completions = DEFAULT_CUSTOM_COMPLETIONS
213
224
  self.cli = false
214
- self.current_line = 0
215
- self.line_buffer = []
225
+ self.current_line = 1
226
+ self.line_buffer = [""]
216
227
  self.eval_path = "(pry)"
228
+ self.active_sessions = 0
217
229
  end
218
230
 
219
231
  # Basic initialization.
220
232
  def self.init
221
233
  @plugin_manager ||= PluginManager.new
222
-
223
234
  self.config ||= Config.new
235
+ self.history ||= History.new
236
+
224
237
  reset_defaults
225
238
  locate_plugins
226
239
  end
227
240
 
228
- @nesting = []
229
- def @nesting.level
230
- last.is_a?(Array) ? last.first : nil
231
- end
232
-
233
- # Return all active Pry sessions.
234
- # @return [Array<Pry>] Active Pry sessions.
235
- def self.sessions
236
- # last element in nesting array is the pry instance
237
- nesting.map(&:last)
238
- end
239
-
240
241
  # Return a `Binding` object for `target` or return `target` if it is
241
242
  # already a `Binding`.
242
243
  # In the case where `target` is top-level then return `TOPLEVEL_BINDING`
@@ -246,7 +247,7 @@ class Pry
246
247
  if target.is_a?(Binding)
247
248
  target
248
249
  else
249
- if target == TOPLEVEL_BINDING.eval('self')
250
+ if TOPLEVEL_BINDING.eval('self') == target
250
251
  TOPLEVEL_BINDING
251
252
  else
252
253
  target.__binding__
@@ -10,10 +10,15 @@ class Pry
10
10
  attr_accessor :hooks
11
11
  attr_accessor :custom_completions
12
12
 
13
- # Returns the target binding for the session. Note that altering this
14
- # attribute will not change the target binding.
15
- # @return [Binding] The target object for the session
16
- attr_accessor :session_target
13
+ attr_accessor :binding_stack
14
+
15
+ attr_accessor :last_result
16
+ attr_accessor :last_exception
17
+ attr_accessor :last_file
18
+ attr_accessor :last_dir
19
+
20
+ attr_reader :input_array
21
+ attr_reader :output_array
17
22
 
18
23
  # Create a new `Pry` object.
19
24
  # @param [Hash] options The optional configuration parameters.
@@ -28,6 +33,7 @@ class Pry
28
33
  refresh(options)
29
34
 
30
35
  @command_processor = CommandProcessor.new(self)
36
+ @binding_stack = []
31
37
  end
32
38
 
33
39
  # Refresh the Pry instance settings from the Pry class.
@@ -73,6 +79,18 @@ class Pry
73
79
  end
74
80
  end
75
81
 
82
+ # Injects a local variable into the provided binding.
83
+ # @param [String] name The name of the local to inject.
84
+ # @param [Object] value The value to set the local to.
85
+ # @param [Binding] b The binding to set the local on.
86
+ # @return [Object] The value the local was set to.
87
+ def inject_local(name, value, b)
88
+ Thread.current[:__pry_local__] = value
89
+ b.eval("#{name} = Thread.current[:__pry_local__]")
90
+ ensure
91
+ Thread.current[:__pry_local__] = nil
92
+ end
93
+
76
94
  # @return [Integer] The maximum amount of objects remembered by the inp and
77
95
  # out arrays. Defaults to 100.
78
96
  def memory_size
@@ -84,32 +102,6 @@ class Pry
84
102
  @output_array = Pry::HistoryArray.new(size)
85
103
  end
86
104
 
87
- # Get nesting data.
88
- # This method should not need to be accessed directly.
89
- # @return [Array] The unparsed nesting information.
90
- def nesting
91
- self.class.nesting
92
- end
93
-
94
- # Set nesting data.
95
- # This method should not need to be accessed directly.
96
- # @param v nesting data.
97
- def nesting=(v)
98
- self.class.nesting = v
99
- end
100
-
101
- # @return [Boolean] Whether top-level session has ended.
102
- def finished_top_level_session?
103
- nesting.empty?
104
- end
105
-
106
- # Return parent of current Pry session.
107
- # @return [Pry] The parent of the current Pry session.
108
- def parent
109
- idx = Pry.sessions.index(self)
110
- Pry.sessions[idx - 1] if idx && idx > 0
111
- end
112
-
113
105
  # Execute the hook `hook_name`, if it is defined.
114
106
  # @param [Symbol] hook_name The hook to execute
115
107
  # @param [Array] args The arguments to pass to the hook.
@@ -117,41 +109,53 @@ class Pry
117
109
  hooks[hook_name].call(*args, &block) if hooks[hook_name]
118
110
  end
119
111
 
112
+ # Make sure special locals exist at start of session
113
+ def initialize_special_locals(target)
114
+ inject_local("_in_", @input_array, target)
115
+ inject_local("_out_", @output_array, target)
116
+ inject_local("_pry_", self, target)
117
+ inject_local("_ex_", nil, target)
118
+ inject_local("_file_", nil, target)
119
+ inject_local("_dir_", nil, target)
120
+
121
+ # without this line we get 1 test failure, ask Mon_Ouie
122
+ set_last_result(nil, target)
123
+ inject_local("_", nil, target)
124
+ end
125
+ private :initialize_special_locals
126
+
127
+ def inject_special_locals(target)
128
+ inject_local("_in_", @input_array, target)
129
+ inject_local("_out_", @output_array, target)
130
+ inject_local("_pry_", self, target)
131
+ inject_local("_ex_", self.last_exception, target)
132
+ inject_local("_file_", self.last_file, target)
133
+ inject_local("_dir_", self.last_dir, target)
134
+ inject_local("_", self.last_result, target)
135
+ end
136
+
120
137
  # Initialize the repl session.
121
138
  # @param [Binding] target The target binding for the session.
122
139
  def repl_prologue(target)
123
140
  exec_hook :before_session, output, target
124
- Pry.active_instance = self
125
-
126
- # Make sure special locals exist
127
- target.eval("inp = ::Pry.active_instance.instance_eval { @input_array }")
128
- target.eval("out = ::Pry.active_instance.instance_eval { @output_array }")
141
+ initialize_special_locals(target)
129
142
 
130
- set_active_instance(target)
131
143
  @input_array << nil # add empty input so inp and out match
132
- set_last_result(Pry.last_result, target)
133
144
 
134
- self.session_target = target
145
+ Pry.active_sessions += 1
146
+ binding_stack.push target
135
147
  end
136
148
 
137
149
  # Clean-up after the repl session.
138
150
  # @param [Binding] target The target binding for the session.
139
151
  # @return [Object] The return value of the repl session (if one exists).
140
- def repl_epilogue(target, nesting_level, break_data)
141
- nesting.pop
152
+ def repl_epilogue(target, break_data)
142
153
  exec_hook :after_session, output, target
143
154
 
144
- # If break_data is an array, then the last element is the return value
145
- break_level, return_value = Array(break_data)
146
-
147
- # keep throwing until we reach the desired nesting level
148
- if nesting_level != break_level
149
- throw :breakout, break_data
150
- end
151
-
152
- save_history if Pry.config.history.save && finished_top_level_session?
153
-
154
- return_value
155
+ Pry.active_sessions -= 1
156
+ binding_stack.pop
157
+ Pry.save_history if Pry.config.history.should_save && Pry.active_sessions == 0
158
+ break_data
155
159
  end
156
160
 
157
161
  # Start a read-eval-print-loop.
@@ -168,18 +172,13 @@ class Pry
168
172
 
169
173
  repl_prologue(target)
170
174
 
171
- # cannot rely on nesting.level as
172
- # nesting.level changes with new sessions
173
- nesting_level = nesting.size
174
-
175
175
  break_data = catch(:breakout) do
176
- nesting.push [nesting.size, target_self, self]
177
176
  loop do
178
- rep(target)
177
+ rep(binding_stack.last)
179
178
  end
180
179
  end
181
180
 
182
- return_value = repl_epilogue(target, nesting_level, break_data)
181
+ return_value = repl_epilogue(target, break_data)
183
182
  return_value || target_self
184
183
  end
185
184
 
@@ -211,29 +210,18 @@ class Pry
211
210
  Readline.completion_proc = Pry::InputCompleter.build_completion_proc target, instance_eval(&custom_completions)
212
211
  end
213
212
 
214
- # save the pry instance to active_instance
215
- Pry.active_instance = self
216
-
217
- target.eval("inp = ::Pry.active_instance.instance_eval { @input_array }")
218
- target.eval("out = ::Pry.active_instance.instance_eval { @output_array }")
219
-
220
- @last_result_is_exception = false
221
- set_active_instance(target)
213
+ # It's not actually redundant to inject them continually as we may have
214
+ # moved into the scope of a new Binding (e.g the user typed `cd`)
215
+ inject_special_locals(target)
222
216
 
223
217
  code = r(target)
224
218
 
225
- Pry.line_buffer.push(*code.each_line)
226
- res = set_last_result(target.eval(code, Pry.eval_path, Pry.current_line), target)
227
- res
228
- rescue SystemExit => e
229
- exit
230
- rescue Exception => e
231
- @last_result_is_exception = true
232
- @output_array << e
219
+ result = set_last_result(target.eval(code, Pry.eval_path, Pry.current_line), target)
220
+ result
221
+ rescue RescuableException => e
233
222
  set_last_exception(e, target)
234
223
  ensure
235
- @input_array << code
236
- Pry.current_line += code.each_line.count if code
224
+ update_input_history(code)
237
225
  end
238
226
 
239
227
  # Perform a read.
@@ -258,7 +246,7 @@ class Pry
258
246
  break if valid_expression?(eval_string)
259
247
  end
260
248
 
261
- @suppress_output = true if eval_string =~ /;\Z/ || null_input?(val)
249
+ @suppress_output = true if eval_string =~ /;\Z/ || eval_string.empty?
262
250
 
263
251
  eval_string
264
252
  end
@@ -270,14 +258,19 @@ class Pry
270
258
  else
271
259
  print.call output, result
272
260
  end
273
- end
274
-
275
- # Returns true if input is "" and a command is not returning a
276
- # value.
277
- # @param [String] val The input string.
278
- # @return [Boolean] Whether the input is null.
279
- def null_input?(val)
280
- val.empty? && !Pry.cmd_ret_value
261
+ rescue RescuableException => e
262
+ # Being uber-paranoid here, given that this exception arose because we couldn't
263
+ # serialize something in the user's program, let's not assume we can serialize
264
+ # the exception either.
265
+ begin
266
+ output.puts "output error: #{e.inspect}"
267
+ rescue RescuableException => e
268
+ if last_result_is_exception?
269
+ output.puts "output error: failed to show exception"
270
+ else
271
+ output.puts "output error: failed to show result"
272
+ end
273
+ end
281
274
  end
282
275
 
283
276
  # Read a line of input and check for ^d, also determine prompt to use.
@@ -289,28 +282,40 @@ class Pry
289
282
  current_prompt = select_prompt(eval_string.empty?, target.eval('self'))
290
283
  val = readline(current_prompt)
291
284
 
292
- # exit session if we receive EOF character
285
+ # exit session if we receive EOF character (^D)
293
286
  if !val
294
- output.puts
295
- throw(:breakout, nesting.level)
287
+ output.puts ""
288
+ Pry.config.control_d_handler.call(eval_string, self)
289
+ ""
290
+ else
291
+ val
296
292
  end
297
-
298
- val
299
293
  end
300
294
 
301
295
  # Process the line received.
302
296
  # This method should not need to be invoked directly.
303
297
  # @param [String] val The line to process.
304
298
  # @param [String] eval_string The cumulative lines of input.
305
- # @target [Binding] target The target of the Pry session.
299
+ # @param [Binding] target The target of the Pry session.
306
300
  def process_line(val, eval_string, target)
307
- val.rstrip!
308
- Pry.cmd_ret_value = @command_processor.process_commands(val, eval_string, target)
301
+ result = @command_processor.process_commands(val, eval_string, target)
302
+
303
+ # set a temporary (just so we can inject the value we want into eval_string)
304
+ Thread.current[:__pry_cmd_result__] = result
309
305
 
310
- if Pry.cmd_ret_value
311
- eval_string << "Pry.cmd_ret_value\n"
306
+ # note that `result` wraps the result of command processing; if a
307
+ # command was matched and invoked then `result.command?` returns true,
308
+ # otherwise it returns false.
309
+ if result.command? && !result.void_command?
310
+
311
+ # the command that was invoked was non-void (had a return value) and so we make
312
+ # the value of the current expression equal to the return value
313
+ # of the command.
314
+ eval_string.replace "Thread.current[:__pry_cmd_result__].retval\n"
312
315
  else
313
- eval_string << "#{val}\n" if !val.empty?
316
+ # only commands should have an empty `val`
317
+ # so this ignores their result
318
+ eval_string << "#{val.rstrip}\n" if !val.empty?
314
319
  end
315
320
  end
316
321
 
@@ -319,9 +324,10 @@ class Pry
319
324
  # @param [Object] result The result.
320
325
  # @param [Binding] target The binding to set `_` on.
321
326
  def set_last_result(result, target)
322
- Pry.last_result = result
327
+ @last_result_is_exception = false
323
328
  @output_array << result
324
- target.eval("_ = ::Pry.last_result")
329
+
330
+ self.last_result = result
325
331
  end
326
332
 
327
333
  # Set the last exception for a session.
@@ -329,16 +335,29 @@ class Pry
329
335
  # @param [Exception] ex The exception.
330
336
  # @param [Binding] target The binding to set `_ex_` on.
331
337
  def set_last_exception(ex, target)
332
- Pry.last_exception = ex
333
- target.eval("_ex_ = ::Pry.last_exception")
338
+ class << ex
339
+ attr_accessor :file, :line
340
+ end
341
+
342
+ ex.backtrace.first =~ /(.*):(\d+)/
343
+ ex.file, ex.line = $1, $2.to_i
344
+
345
+ @last_result_is_exception = true
346
+ @output_array << ex
347
+
348
+ self.last_exception = ex
334
349
  end
335
350
 
336
- # Set the active instance for a session.
351
+ # Update Pry's internal state after evalling code.
337
352
  # This method should not need to be invoked directly.
338
- # @param [Binding] target The binding to set `_ex_` on.
339
- def set_active_instance(target)
340
- Pry.active_instance = self
341
- target.eval("_pry_ = ::Pry.active_instance")
353
+ # @param [String] code The code we just eval'd
354
+ def update_input_history(code)
355
+ # Always push to the @input_array as the @output_array is always pushed to.
356
+ @input_array << code
357
+ if code
358
+ Pry.line_buffer.push(*code.each_line)
359
+ Pry.current_line += code.each_line.count
360
+ end
342
361
  end
343
362
 
344
363
  # @return [Boolean] True if the last result is an exception that was raised,
@@ -355,10 +374,9 @@ class Pry
355
374
  def readline(current_prompt="> ")
356
375
 
357
376
  if input == Readline
358
-
359
- # Readline must be treated differently
360
- # as it has a second parameter.
361
- input.readline(current_prompt, true)
377
+ line = input.readline(current_prompt, false)
378
+ Pry.history << line.dup if line
379
+ line
362
380
  else
363
381
  begin
364
382
  if input.method(:readline).arity == 1
@@ -382,14 +400,6 @@ class Pry
382
400
  !@suppress_output || last_result_is_exception?
383
401
  end
384
402
 
385
- # Save readline history to a file.
386
- def save_history
387
- history_file = File.expand_path(Pry.config.history.file)
388
- File.open(history_file, 'w') do |f|
389
- f.write Readline::HISTORY.to_a.join("\n")
390
- end
391
- end
392
-
393
403
  # Returns the appropriate prompt to use.
394
404
  # This method should not need to be invoked directly.
395
405
  # @param [Boolean] first_line Whether this is the first line of input
@@ -399,9 +409,9 @@ class Pry
399
409
  def select_prompt(first_line, target_self)
400
410
 
401
411
  if first_line
402
- Array(prompt).first.call(target_self, nesting.level)
412
+ Array(prompt).first.call(target_self, binding_stack.size - 1, self)
403
413
  else
404
- Array(prompt).last.call(target_self, nesting.level)
414
+ Array(prompt).last.call(target_self, binding_stack.size - 1, self)
405
415
  end
406
416
  end
407
417