pry 0.10.0.pre2-universal-mswin32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +702 -0
  3. data/LICENSE +25 -0
  4. data/README.md +406 -0
  5. data/bin/pry +16 -0
  6. data/lib/pry.rb +161 -0
  7. data/lib/pry/cli.rb +220 -0
  8. data/lib/pry/code.rb +346 -0
  9. data/lib/pry/code/code_file.rb +103 -0
  10. data/lib/pry/code/code_range.rb +71 -0
  11. data/lib/pry/code/loc.rb +92 -0
  12. data/lib/pry/code_object.rb +172 -0
  13. data/lib/pry/color_printer.rb +55 -0
  14. data/lib/pry/command.rb +692 -0
  15. data/lib/pry/command_set.rb +443 -0
  16. data/lib/pry/commands.rb +6 -0
  17. data/lib/pry/commands/amend_line.rb +99 -0
  18. data/lib/pry/commands/bang.rb +20 -0
  19. data/lib/pry/commands/bang_pry.rb +17 -0
  20. data/lib/pry/commands/cat.rb +62 -0
  21. data/lib/pry/commands/cat/abstract_formatter.rb +27 -0
  22. data/lib/pry/commands/cat/exception_formatter.rb +77 -0
  23. data/lib/pry/commands/cat/file_formatter.rb +67 -0
  24. data/lib/pry/commands/cat/input_expression_formatter.rb +43 -0
  25. data/lib/pry/commands/cd.rb +41 -0
  26. data/lib/pry/commands/change_inspector.rb +27 -0
  27. data/lib/pry/commands/change_prompt.rb +26 -0
  28. data/lib/pry/commands/code_collector.rb +165 -0
  29. data/lib/pry/commands/disable_pry.rb +27 -0
  30. data/lib/pry/commands/disabled_commands.rb +2 -0
  31. data/lib/pry/commands/easter_eggs.rb +112 -0
  32. data/lib/pry/commands/edit.rb +195 -0
  33. data/lib/pry/commands/edit/exception_patcher.rb +25 -0
  34. data/lib/pry/commands/edit/file_and_line_locator.rb +36 -0
  35. data/lib/pry/commands/exit.rb +42 -0
  36. data/lib/pry/commands/exit_all.rb +29 -0
  37. data/lib/pry/commands/exit_program.rb +23 -0
  38. data/lib/pry/commands/find_method.rb +193 -0
  39. data/lib/pry/commands/fix_indent.rb +19 -0
  40. data/lib/pry/commands/gem_cd.rb +26 -0
  41. data/lib/pry/commands/gem_install.rb +32 -0
  42. data/lib/pry/commands/gem_list.rb +33 -0
  43. data/lib/pry/commands/gem_open.rb +29 -0
  44. data/lib/pry/commands/gist.rb +101 -0
  45. data/lib/pry/commands/help.rb +164 -0
  46. data/lib/pry/commands/hist.rb +180 -0
  47. data/lib/pry/commands/import_set.rb +22 -0
  48. data/lib/pry/commands/install_command.rb +53 -0
  49. data/lib/pry/commands/jump_to.rb +29 -0
  50. data/lib/pry/commands/list_inspectors.rb +35 -0
  51. data/lib/pry/commands/list_prompts.rb +35 -0
  52. data/lib/pry/commands/ls.rb +114 -0
  53. data/lib/pry/commands/ls/constants.rb +47 -0
  54. data/lib/pry/commands/ls/formatter.rb +49 -0
  55. data/lib/pry/commands/ls/globals.rb +48 -0
  56. data/lib/pry/commands/ls/grep.rb +21 -0
  57. data/lib/pry/commands/ls/instance_vars.rb +39 -0
  58. data/lib/pry/commands/ls/interrogatable.rb +18 -0
  59. data/lib/pry/commands/ls/jruby_hacks.rb +49 -0
  60. data/lib/pry/commands/ls/local_names.rb +35 -0
  61. data/lib/pry/commands/ls/local_vars.rb +39 -0
  62. data/lib/pry/commands/ls/ls_entity.rb +70 -0
  63. data/lib/pry/commands/ls/methods.rb +57 -0
  64. data/lib/pry/commands/ls/methods_helper.rb +46 -0
  65. data/lib/pry/commands/ls/self_methods.rb +32 -0
  66. data/lib/pry/commands/nesting.rb +25 -0
  67. data/lib/pry/commands/play.rb +103 -0
  68. data/lib/pry/commands/pry_backtrace.rb +25 -0
  69. data/lib/pry/commands/pry_version.rb +17 -0
  70. data/lib/pry/commands/raise_up.rb +32 -0
  71. data/lib/pry/commands/reload_code.rb +62 -0
  72. data/lib/pry/commands/reset.rb +18 -0
  73. data/lib/pry/commands/ri.rb +60 -0
  74. data/lib/pry/commands/save_file.rb +61 -0
  75. data/lib/pry/commands/shell_command.rb +48 -0
  76. data/lib/pry/commands/shell_mode.rb +25 -0
  77. data/lib/pry/commands/show_doc.rb +83 -0
  78. data/lib/pry/commands/show_info.rb +195 -0
  79. data/lib/pry/commands/show_input.rb +17 -0
  80. data/lib/pry/commands/show_source.rb +50 -0
  81. data/lib/pry/commands/simple_prompt.rb +22 -0
  82. data/lib/pry/commands/stat.rb +40 -0
  83. data/lib/pry/commands/switch_to.rb +23 -0
  84. data/lib/pry/commands/toggle_color.rb +24 -0
  85. data/lib/pry/commands/watch_expression.rb +105 -0
  86. data/lib/pry/commands/watch_expression/expression.rb +38 -0
  87. data/lib/pry/commands/whereami.rb +190 -0
  88. data/lib/pry/commands/wtf.rb +57 -0
  89. data/lib/pry/config.rb +24 -0
  90. data/lib/pry/config/behavior.rb +139 -0
  91. data/lib/pry/config/convenience.rb +26 -0
  92. data/lib/pry/config/default.rb +165 -0
  93. data/lib/pry/core_extensions.rb +131 -0
  94. data/lib/pry/editor.rb +133 -0
  95. data/lib/pry/exceptions.rb +77 -0
  96. data/lib/pry/helpers.rb +5 -0
  97. data/lib/pry/helpers/base_helpers.rb +113 -0
  98. data/lib/pry/helpers/command_helpers.rb +156 -0
  99. data/lib/pry/helpers/documentation_helpers.rb +75 -0
  100. data/lib/pry/helpers/options_helpers.rb +27 -0
  101. data/lib/pry/helpers/table.rb +109 -0
  102. data/lib/pry/helpers/text.rb +107 -0
  103. data/lib/pry/history.rb +125 -0
  104. data/lib/pry/history_array.rb +121 -0
  105. data/lib/pry/hooks.rb +230 -0
  106. data/lib/pry/indent.rb +406 -0
  107. data/lib/pry/input_completer.rb +242 -0
  108. data/lib/pry/input_lock.rb +132 -0
  109. data/lib/pry/inspector.rb +27 -0
  110. data/lib/pry/last_exception.rb +61 -0
  111. data/lib/pry/method.rb +546 -0
  112. data/lib/pry/method/disowned.rb +53 -0
  113. data/lib/pry/method/patcher.rb +125 -0
  114. data/lib/pry/method/weird_method_locator.rb +186 -0
  115. data/lib/pry/module_candidate.rb +136 -0
  116. data/lib/pry/object_path.rb +82 -0
  117. data/lib/pry/output.rb +50 -0
  118. data/lib/pry/pager.rb +234 -0
  119. data/lib/pry/plugins.rb +103 -0
  120. data/lib/pry/prompt.rb +26 -0
  121. data/lib/pry/pry_class.rb +375 -0
  122. data/lib/pry/pry_instance.rb +654 -0
  123. data/lib/pry/rbx_path.rb +22 -0
  124. data/lib/pry/repl.rb +202 -0
  125. data/lib/pry/repl_file_loader.rb +74 -0
  126. data/lib/pry/rubygem.rb +82 -0
  127. data/lib/pry/terminal.rb +79 -0
  128. data/lib/pry/test/helper.rb +170 -0
  129. data/lib/pry/version.rb +3 -0
  130. data/lib/pry/wrapped_module.rb +373 -0
  131. metadata +248 -0
@@ -0,0 +1,242 @@
1
+ # taken from irb
2
+ # Implements tab completion for Readline in Pry
3
+ class Pry::InputCompleter
4
+ NUMERIC_REGEXP = /^(-?(0[dbo])?[0-9_]+(\.[0-9_]+)?([eE]-?[0-9]+)?)\.([^.]*)$/
5
+ ARRAY_REGEXP = /^([^\]]*\])\.([^.]*)$/
6
+ SYMBOL_REGEXP = /^(:[^:.]*)$/
7
+ SYMBOL_METHOD_CALL_REGEXP = /^(:[^:.]+)\.([^.]*)$/
8
+ REGEX_REGEXP = /^(\/[^\/]*\/)\.([^.]*)$/
9
+ PROC_OR_HASH_REGEXP = /^([^\}]*\})\.([^.]*)$/
10
+ TOPLEVEL_LOOKUP_REGEXP = /^::([A-Z][^:\.\(]*)$/
11
+ CONSTANT_REGEXP = /^([A-Z][A-Za-z0-9]*)$/
12
+ CONSTANT_OR_METHOD_REGEXP = /^([A-Z].*)::([^:.]*)$/
13
+ HEX_REGEXP = /^(-?0x[0-9a-fA-F_]+)\.([^.]*)$/
14
+ GLOBALVARIABLE_REGEXP = /^(\$[^.]*)$/
15
+ VARIABLE_REGEXP = /^([^."].*)\.([^.]*)$/
16
+
17
+ ReservedWords = [
18
+ "BEGIN", "END",
19
+ "alias", "and",
20
+ "begin", "break",
21
+ "case", "class",
22
+ "def", "defined", "do",
23
+ "else", "elsif", "end", "ensure",
24
+ "false", "for",
25
+ "if", "in",
26
+ "module",
27
+ "next", "nil", "not",
28
+ "or",
29
+ "redo", "rescue", "retry", "return",
30
+ "self", "super",
31
+ "then", "true",
32
+ "undef", "unless", "until",
33
+ "when", "while",
34
+ "yield" ]
35
+
36
+ Operators = [
37
+ "%", "&", "*", "**", "+", "-", "/",
38
+ "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
39
+ "[]", "[]=", "^", "!", "!=", "!~"
40
+ ]
41
+
42
+ WORD_ESCAPE_STR = " \t\n\"\\'`><=;|&{("
43
+
44
+ def initialize(input, pry = nil)
45
+ @pry = pry
46
+ @input = input
47
+ @input.basic_word_break_characters = WORD_ESCAPE_STR if @input.respond_to?(:basic_word_break_characters=)
48
+ @input.completion_append_character = nil if @input.respond_to?(:completion_append_character=)
49
+ end
50
+
51
+ #
52
+ # Return a new completion proc for use by Readline.
53
+ #
54
+ def call(str, options = {})
55
+ custom_completions = options[:custom_completions] || []
56
+ # if there are multiple contexts e.g. cd 1/2/3
57
+ # get new target for 1/2 and find candidates for 3
58
+ path, input = build_path(str)
59
+
60
+ if path.call.empty?
61
+ target = options[:target]
62
+ else
63
+ # Assume the user is tab-completing the 'cd' command
64
+ begin
65
+ target = Pry::ObjectPath.new(path.call, @pry.binding_stack).resolve.last
66
+ # but if that doesn't work, assume they're doing division with no spaces
67
+ rescue Pry::CommandError
68
+ target = options[:target]
69
+ end
70
+ end
71
+
72
+ begin
73
+ bind = target
74
+ # Complete stdlib symbols
75
+ case input
76
+ when REGEX_REGEXP # Regexp
77
+ receiver = $1
78
+ message = Regexp.quote($2)
79
+ candidates = Regexp.instance_methods.collect(&:to_s)
80
+ select_message(path, receiver, message, candidates)
81
+ when ARRAY_REGEXP # Array
82
+ receiver = $1
83
+ message = Regexp.quote($2)
84
+ candidates = Array.instance_methods.collect(&:to_s)
85
+ select_message(path, receiver, message, candidates)
86
+ when PROC_OR_HASH_REGEXP # Proc or Hash
87
+ receiver = $1
88
+ message = Regexp.quote($2)
89
+ candidates = Proc.instance_methods.collect(&:to_s)
90
+ candidates |= Hash.instance_methods.collect(&:to_s)
91
+ select_message(path, receiver, message, candidates)
92
+ when SYMBOL_REGEXP # Symbol
93
+ if Symbol.respond_to?(:all_symbols)
94
+ sym = Regexp.quote($1)
95
+ candidates = Symbol.all_symbols.collect{|s| ":" << s.id2name}
96
+ candidates.grep(/^#{sym}/)
97
+ else
98
+ []
99
+ end
100
+ when TOPLEVEL_LOOKUP_REGEXP # Absolute Constant or class methods
101
+ receiver = $1
102
+ candidates = Object.constants.collect(&:to_s)
103
+ candidates.grep(/^#{receiver}/).collect{|e| "::" << e}
104
+ when CONSTANT_REGEXP # Constant
105
+ message = $1
106
+ begin
107
+ context = target.eval("self")
108
+ context = context.class unless context.respond_to? :constants
109
+ candidates = context.constants.collect(&:to_s)
110
+ rescue
111
+ candidates = []
112
+ end
113
+ candidates = candidates.grep(/^#{message}/).collect(&path)
114
+ when CONSTANT_OR_METHOD_REGEXP # Constant or class methods
115
+ receiver = $1
116
+ message = Regexp.quote($2)
117
+ begin
118
+ candidates = eval("#{receiver}.constants.collect(&:to_s)", bind)
119
+ candidates |= eval("#{receiver}.methods.collect(&:to_s)", bind)
120
+ rescue Pry::RescuableException
121
+ candidates = []
122
+ end
123
+ candidates.grep(/^#{message}/).collect{|e| receiver << "::" << e}
124
+ when SYMBOL_METHOD_CALL_REGEXP # method call on a Symbol
125
+ receiver = $1
126
+ message = Regexp.quote($2)
127
+ candidates = Symbol.instance_methods.collect(&:to_s)
128
+ select_message(path, receiver, message, candidates)
129
+ when NUMERIC_REGEXP
130
+ # Numeric
131
+ receiver = $1
132
+ message = Regexp.quote($5)
133
+ begin
134
+ candidates = eval(receiver, bind).methods.collect(&:to_s)
135
+ rescue Pry::RescuableException
136
+ candidates = []
137
+ end
138
+ select_message(path, receiver, message, candidates)
139
+ when HEX_REGEXP
140
+ # Numeric(0xFFFF)
141
+ receiver = $1
142
+ message = Regexp.quote($2)
143
+ begin
144
+ candidates = eval(receiver, bind).methods.collect(&:to_s)
145
+ rescue Pry::RescuableException
146
+ candidates = []
147
+ end
148
+ select_message(path, receiver, message, candidates)
149
+ when GLOBALVARIABLE_REGEXP # global
150
+ regmessage = Regexp.new(Regexp.quote($1))
151
+ candidates = global_variables.collect(&:to_s).grep(regmessage)
152
+ when VARIABLE_REGEXP # variable
153
+ receiver = $1
154
+ message = Regexp.quote($2)
155
+
156
+ gv = eval("global_variables", bind).collect(&:to_s)
157
+ lv = eval("local_variables", bind).collect(&:to_s)
158
+ cv = eval("self.class.constants", bind).collect(&:to_s)
159
+
160
+ if (gv | lv | cv).include?(receiver) or /^[A-Z]/ =~ receiver && /\./ !~ receiver
161
+ # foo.func and foo is local var. OR
162
+ # Foo::Bar.func
163
+ begin
164
+ candidates = eval("#{receiver}.methods", bind).collect(&:to_s)
165
+ rescue Pry::RescuableException
166
+ candidates = []
167
+ end
168
+ else
169
+ # func1.func2
170
+ candidates = []
171
+ ObjectSpace.each_object(Module){|m|
172
+ begin
173
+ name = m.name.to_s
174
+ rescue Pry::RescuableException
175
+ name = ""
176
+ end
177
+ next if name != "IRB::Context" and
178
+ /^(IRB|SLex|RubyLex|RubyToken)/ =~ name
179
+
180
+ # jruby doesn't always provide #instance_methods() on each
181
+ # object.
182
+ if m.respond_to?(:instance_methods)
183
+ candidates.concat m.instance_methods(false).collect(&:to_s)
184
+ end
185
+ }
186
+ candidates.sort!
187
+ candidates.uniq!
188
+ end
189
+ select_message(path, receiver, message, candidates)
190
+ when /^\.([^.]*)$/
191
+ # Unknown(maybe String)
192
+ receiver = ""
193
+ message = Regexp.quote($1)
194
+ candidates = String.instance_methods(true).collect(&:to_s)
195
+ select_message(path, receiver, message, candidates)
196
+ else
197
+ candidates = eval(
198
+ "methods | private_methods | local_variables | " \
199
+ "self.class.constants | instance_variables",
200
+ bind
201
+ ).collect(&:to_s)
202
+
203
+ if eval("respond_to?(:class_variables)", bind)
204
+ candidates += eval("class_variables", bind).collect(&:to_s)
205
+ end
206
+ candidates = (candidates|ReservedWords|custom_completions).grep(/^#{Regexp.quote(input)}/)
207
+ candidates.collect(&path)
208
+ end
209
+ rescue Pry::RescuableException
210
+ []
211
+ end
212
+ end
213
+
214
+ def select_message(path, receiver, message, candidates)
215
+ candidates.grep(/^#{message}/).collect { |e|
216
+ case e
217
+ when /^[a-zA-Z_]/
218
+ path.call(receiver + "." << e)
219
+ when /^[0-9]/
220
+ when *Operators
221
+ #receiver + " " << e
222
+ end
223
+ }.compact
224
+ end
225
+
226
+ # build_path seperates the input into two parts: path and input.
227
+ # input is the partial string that should be completed
228
+ # path is a proc that takes an input and builds a full path.
229
+ def build_path(input)
230
+ # check to see if the input is a regex
231
+ return proc {|i| i.to_s }, input if input[/\/\./]
232
+ trailing_slash = input.end_with?('/')
233
+ contexts = input.chomp('/').split(/\//)
234
+ input = contexts[-1]
235
+ path = proc do |i|
236
+ p = contexts[0..-2].push(i).join('/')
237
+ p += '/' if trailing_slash && !i.nil?
238
+ p
239
+ end
240
+ return path, input
241
+ end
242
+ end
@@ -0,0 +1,132 @@
1
+ require 'thread'
2
+
3
+ class Pry
4
+ # There is one InputLock per input (such as STDIN) as two REPLs on the same
5
+ # input makes things delirious. InputLock serializes accesses to the input so
6
+ # that threads to not conflict with each other. The latest thread to request
7
+ # ownership of the input wins.
8
+ class InputLock
9
+ class Interrupt < Exception; end
10
+
11
+ class << self
12
+ attr_accessor :input_locks
13
+ attr_accessor :global_lock
14
+ end
15
+
16
+ self.input_locks = {}
17
+ self.global_lock = Mutex.new
18
+
19
+ def self.for(input)
20
+ # XXX This method leaks memory, as we never unregister an input once we
21
+ # are done with it. Fortunately, the leak is tiny (or so we hope). In
22
+ # usual scenarios, we would leak the StringIO that is passed to be
23
+ # evaluated from the command line.
24
+ global_lock.synchronize do
25
+ input_locks[input] ||= Pry::InputLock.new
26
+ end
27
+ end
28
+
29
+ def initialize
30
+ @mutex = Mutex.new
31
+ @cond = ConditionVariable.new
32
+ @owners = []
33
+ @interruptible = false
34
+ end
35
+
36
+ # Adds ourselves to the ownership list. The last one in the list may access
37
+ # the input through interruptible_region().
38
+ def __with_ownership(&block)
39
+ @mutex.synchronize do
40
+ # Three cases:
41
+ # 1) There are no owners, in this case we are good to go.
42
+ # 2) The current owner of the input is not reading the input (it might
43
+ # just be evaluating some ruby that the user typed).
44
+ # The current owner will figure out that it cannot go back to reading
45
+ # the input since we are adding ourselves to the @owners list, which
46
+ # in turns makes us the current owner.
47
+ # 3) The owner of the input is in the interruptible region, reading from
48
+ # the input. It's safe to send an Interrupt exception to interrupt
49
+ # the owner. It will then proceed like in case 2).
50
+ # We wait until the owner sets the interruptible flag back
51
+ # to false, meaning that he's out of the interruptible region.
52
+ # Note that the owner may receive multiple interrupts since, but that
53
+ # should be okay (and trying to avoid it is futile anyway).
54
+ while @interruptible
55
+ @owners.last.raise Interrupt
56
+ @cond.wait(@mutex)
57
+ end
58
+ @owners << Thread.current
59
+ end
60
+
61
+ block.call
62
+
63
+ ensure
64
+ @mutex.synchronize do
65
+ # We are releasing any desire to have the input ownership by removing
66
+ # ourselves from the list.
67
+ @owners.delete(Thread.current)
68
+
69
+ # We need to wake up the thread at the end of the @owners list, but
70
+ # sadly Ruby doesn't allow us to choose which one we wake up, so we wake
71
+ # them all up.
72
+ @cond.broadcast
73
+ end
74
+ end
75
+
76
+ def with_ownership(&block)
77
+ # If we are in a nested with_ownership() call (nested pry context), we do nothing.
78
+ nested = @mutex.synchronize { @owners.include?(Thread.current) }
79
+ nested ? block.call : __with_ownership(&block)
80
+ end
81
+
82
+ def enter_interruptible_region
83
+ @mutex.synchronize do
84
+ # We patiently wait until we are the owner. This may happen as another
85
+ # thread calls with_ownership() because of a binding.pry happening in
86
+ # another thread.
87
+ @cond.wait(@mutex) until @owners.last == Thread.current
88
+
89
+ # We are the legitimate owner of the input. We mark ourselves as
90
+ # interruptible, so other threads can send us an Interrupt exception
91
+ # while we are blocking from reading the input.
92
+ @interruptible = true
93
+ end
94
+ end
95
+
96
+ def leave_interruptible_region
97
+ @mutex.synchronize do
98
+ # We check if we are still the owner, because we could have received an
99
+ # Interrupt right after the following @cond.broadcast, making us retry.
100
+ @interruptible = false if @owners.last == Thread.current
101
+ @cond.broadcast
102
+ end
103
+ rescue Interrupt
104
+ # We need to guard against a spurious interrupt delivered while we are
105
+ # trying to acquire the lock (the rescue block is no longer in our scope).
106
+ retry
107
+ end
108
+
109
+ def interruptible_region(&block)
110
+ enter_interruptible_region
111
+
112
+ # XXX Note that there is a chance that we get the interrupt right after
113
+ # the readline call succeeded, but we'll never know, and we will retry the
114
+ # call, discarding that piece of input.
115
+ block.call
116
+
117
+ rescue Interrupt
118
+ # We were asked to back off. The one requesting the interrupt will be
119
+ # waiting on the conditional for the interruptible flag to change to false.
120
+ # Note that there can be some inefficiency, as we could immediately
121
+ # succeed in enter_interruptible_region(), even before the one requesting
122
+ # the ownership has the chance to register itself as an owner.
123
+ # To mitigate the issue, we sleep a little bit.
124
+ leave_interruptible_region
125
+ sleep 0.01
126
+ retry
127
+
128
+ ensure
129
+ leave_interruptible_region
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,27 @@
1
+ class Pry::Inspector
2
+ MAP = {
3
+ "default" => {
4
+ value: Pry::DEFAULT_PRINT,
5
+ description: <<-DESCRIPTION.each_line.map(&:lstrip!)
6
+ The default Pry inspector. It has paging and color support, and uses
7
+ pretty_inspect when printing an object.
8
+ DESCRIPTION
9
+ },
10
+
11
+ "simple" => {
12
+ value: Pry::SIMPLE_PRINT,
13
+ description: <<-DESCRIPTION.each_line.map(&:lstrip)
14
+ A simple inspector that uses #puts and #inspect when printing an
15
+ object. It has no pager, color, or pretty_inspect support.
16
+ DESCRIPTION
17
+ },
18
+
19
+ "clipped" => {
20
+ value: Pry::CLIPPED_PRINT,
21
+ description: <<-DESCRIPTION.each_line.map(&:lstrip)
22
+ The clipped inspector has the same features as the 'simple' inspector
23
+ but prints large objects as a smaller string.
24
+ DESCRIPTION
25
+ }
26
+ }
27
+ end
@@ -0,0 +1,61 @@
1
+ #
2
+ # {Pry::LastException} is a proxy class who wraps an Exception object for
3
+ # {Pry#last_exception}. it extends the exception object with methods that
4
+ # help pry commands be useful.
5
+ #
6
+ # the original exception object is not modified and method calls are forwarded
7
+ # to the wrapped exception object.
8
+ #
9
+ class Pry::LastException < BasicObject
10
+ attr_accessor :bt_index
11
+
12
+ def initialize(e)
13
+ @e = e
14
+ @bt_index = 0
15
+ @file, @line = bt_source_location_for(0)
16
+ end
17
+
18
+ def method_missing(name, *args, &block)
19
+ if @e.respond_to?(name)
20
+ @e.public_send(name, *args, &block)
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ def respond_to_missing?(name, include_private = false)
27
+ @e.respond_to?(name)
28
+ end
29
+
30
+ #
31
+ # @return [String]
32
+ # returns the path to a file for the current backtrace. see {#bt_index}.
33
+ #
34
+ def file
35
+ @file
36
+ end
37
+
38
+ #
39
+ # @return [Fixnum]
40
+ # returns the line for the current backtrace. see {#bt_index}.
41
+ #
42
+ def line
43
+ @line
44
+ end
45
+
46
+ # @return [Exception]
47
+ # returns the wrapped exception
48
+ #
49
+ def wrapped_exception
50
+ @e
51
+ end
52
+
53
+ def bt_source_location_for(index)
54
+ backtrace[index] =~ /(.*):(\d+)/
55
+ [$1, $2.to_i]
56
+ end
57
+
58
+ def inc_bt_index
59
+ @bt_index = (@bt_index + 1) % backtrace.size
60
+ end
61
+ end