pry 0.9.0pre3-java → 0.9.4pre2-java

Sign up to get free protection for your applications and to get access to all the features.
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