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.
- data/.gitignore +1 -0
- data/CHANGELOG +84 -6
- data/CONTRIBUTORS +13 -0
- data/README.markdown +23 -183
- data/Rakefile +22 -19
- data/TODO +36 -6
- data/bin/pry +12 -1
- data/lib/pry.rb +60 -12
- data/lib/pry/command_context.rb +21 -0
- data/lib/pry/command_processor.rb +62 -16
- data/lib/pry/command_set.rb +25 -11
- data/lib/pry/commands.rb +0 -3
- data/lib/pry/completion.rb +6 -6
- data/lib/pry/config.rb +25 -5
- data/lib/pry/default_commands/basic.rb +27 -6
- data/lib/pry/default_commands/context.rb +84 -35
- data/lib/pry/default_commands/documentation.rb +69 -31
- data/lib/pry/default_commands/easter_eggs.rb +5 -0
- data/lib/pry/default_commands/input.rb +193 -56
- data/lib/pry/default_commands/introspection.rb +98 -50
- data/lib/pry/default_commands/ls.rb +51 -21
- data/lib/pry/default_commands/shell.rb +57 -13
- data/lib/pry/extended_commands/experimental.rb +0 -32
- data/lib/pry/extended_commands/user_command_api.rb +33 -2
- data/lib/pry/helpers/base_helpers.rb +30 -10
- data/lib/pry/helpers/command_helpers.rb +75 -16
- data/lib/pry/helpers/text.rb +12 -11
- data/lib/pry/history.rb +61 -0
- data/lib/pry/plugins.rb +23 -12
- data/lib/pry/pry_class.rb +51 -50
- data/lib/pry/pry_instance.rb +129 -119
- data/lib/pry/version.rb +1 -1
- data/pry.gemspec +46 -0
- data/test/helper.rb +37 -3
- data/test/test_command_processor.rb +62 -19
- data/test/test_command_set.rb +40 -2
- data/test/test_completion.rb +27 -0
- data/test/test_default_commands/test_context.rb +185 -1
- data/test/test_default_commands/test_documentation.rb +10 -0
- data/test/test_default_commands/test_input.rb +207 -11
- data/test/test_default_commands/test_introspection.rb +20 -1
- data/test/test_default_commands/test_shell.rb +18 -0
- data/test/test_pry.rb +261 -45
- data/test/test_pry_history.rb +82 -0
- data/test/test_pry_output.rb +44 -0
- data/test/test_special_locals.rb +35 -0
- metadata +185 -159
data/lib/pry/helpers/text.rb
CHANGED
@@ -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
|
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.
|
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
|
data/lib/pry/history.rb
ADDED
@@ -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
|
-
|
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
|
-
|
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 =
|
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
|
-
|
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,
|
125
|
-
if obj.
|
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
|
135
|
-
|
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['
|
179
|
+
ENV['VISUAL'] || ENV['EDITOR'] || "notepad"
|
176
180
|
else
|
177
|
-
ENV['
|
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.
|
200
|
-
config.history.
|
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 =
|
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
|
250
|
+
if TOPLEVEL_BINDING.eval('self') == target
|
250
251
|
TOPLEVEL_BINDING
|
251
252
|
else
|
252
253
|
target.__binding__
|
data/lib/pry/pry_instance.rb
CHANGED
@@ -10,10 +10,15 @@ class Pry
|
|
10
10
|
attr_accessor :hooks
|
11
11
|
attr_accessor :custom_completions
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
attr_accessor :
|
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
|
-
|
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
|
-
|
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,
|
141
|
-
nesting.pop
|
152
|
+
def repl_epilogue(target, break_data)
|
142
153
|
exec_hook :after_session, output, target
|
143
154
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
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(
|
177
|
+
rep(binding_stack.last)
|
179
178
|
end
|
180
179
|
end
|
181
180
|
|
182
|
-
return_value = repl_epilogue(target,
|
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
|
-
#
|
215
|
-
|
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
|
-
|
226
|
-
|
227
|
-
|
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
|
-
|
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/ ||
|
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
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
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
|
-
|
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
|
-
# @
|
299
|
+
# @param [Binding] target The target of the Pry session.
|
306
300
|
def process_line(val, eval_string, target)
|
307
|
-
val
|
308
|
-
|
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
|
311
|
-
|
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
|
-
|
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
|
-
|
327
|
+
@last_result_is_exception = false
|
323
328
|
@output_array << result
|
324
|
-
|
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
|
-
|
333
|
-
|
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
|
-
#
|
351
|
+
# Update Pry's internal state after evalling code.
|
337
352
|
# This method should not need to be invoked directly.
|
338
|
-
# @param [
|
339
|
-
def
|
340
|
-
|
341
|
-
|
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
|
-
|
360
|
-
|
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,
|
412
|
+
Array(prompt).first.call(target_self, binding_stack.size - 1, self)
|
403
413
|
else
|
404
|
-
Array(prompt).last.call(target_self,
|
414
|
+
Array(prompt).last.call(target_self, binding_stack.size - 1, self)
|
405
415
|
end
|
406
416
|
end
|
407
417
|
|