pry 0.9.5-i386-mingw32 → 0.9.6-i386-mingw32

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.
@@ -9,9 +9,11 @@ class Pry
9
9
  target = target()
10
10
 
11
11
  opts = Slop.parse!(args) do |opt|
12
- opt.banner "Usage: show-method [OPTIONS] [METH 1] [METH 2] [METH N]\n" \
13
- "Show the source for method METH. Tries instance methods first and then methods by default.\n" \
14
- "e.g: show-method hello_method"
12
+ opt.banner unindent <<-USAGE
13
+ Usage: show-method [OPTIONS] [METH 1] [METH 2] [METH N]
14
+ Show the source for method METH. Tries instance methods first and then methods by default.
15
+ e.g: show-method hello_method
16
+ USAGE
15
17
 
16
18
  opt.on :l, "line-numbers", "Show line numbers."
17
19
  opt.on :b, "base-one", "Show line numbers but start numbering at 1 (useful for `amend-line` and `play` commands)."
@@ -58,16 +60,18 @@ class Pry
58
60
  end
59
61
  end
60
62
 
61
- alias_command "show-source", "show-method", ""
62
- alias_command "$", "show-method", ""
63
+ alias_command "show-source", "show-method"
64
+ alias_command "$", "show-method"
63
65
 
64
66
  command "show-command", "Show the source for CMD. Type `show-command --help` for more info." do |*args|
65
67
  target = target()
66
68
 
67
69
  opts = Slop.parse!(args) do |opt|
68
- opt.banner = "Usage: show-command [OPTIONS] [CMD]\n" \
69
- "Show the source for command CMD.\n" \
70
- "e.g: show-command show-method"
70
+ opt.banner unindent <<-USAGE
71
+ Usage: show-command [OPTIONS] [CMD]
72
+ Show the source for command CMD.
73
+ e.g: show-command show-method
74
+ USAGE
71
75
 
72
76
  opt.on :l, "line-numbers", "Show line numbers."
73
77
  opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
@@ -110,70 +114,86 @@ class Pry
110
114
 
111
115
  command "edit", "Invoke the default editor on a file. Type `edit --help` for more info" do |*args|
112
116
  opts = Slop.parse!(args) do |opt|
113
- opt.banner "Usage: edit [OPTIONS] [FILE]\n" \
114
- "Edit the method FILE in an editor.\nWhen no file given, opens editor with contents of input buffer and evals after closing." \
115
- "\nEnsure #{text.bold("Pry.config.editor")} is set to your editor of choice.\n" \
116
- "e.g: edit sample.rb"
117
-
118
- opt.on :r, "reload", "Eval file content after editing (evals at top level)"
119
- opt.on :n, "no-reload", "Do not automatically reload the file after editing (only applies to --ex and -t)."
120
- opt.on :ex, "Open an editor at the line and file that generated the most recent Exception, reloads file after editing."
121
- opt.on :t, "temp", "Open a temporary file in an editor with contents of input buffer and eval it in current context after closing (same as `edit` with no args)"
122
- opt.on :p, "play", "Use the pry `play` command to eval the file content after editing."
123
- opt.on :l, "line", "Specify line number to jump to in file", true, :as => Integer
117
+ opt.banner unindent <<-USAGE
118
+ Usage: edit [--no-reload|--reload] [--line LINE] [--temp|--ex|FILE[:LINE]]
119
+ Open a text editor. When no FILE is given, edits the pry input buffer.
120
+ Ensure #{text.bold("Pry.config.editor")} is set to your editor of choice.
121
+ e.g: edit sample.rb
122
+ USAGE
123
+
124
+ opt.on :e, :ex, "Open the file that raised the most recent exception (_ex_.file)", :optional => true, :as => Integer
125
+ opt.on :t, :temp, "Open an empty temporary file"
126
+ opt.on :l, :line, "Jump to this line in the opened file", true, :as => Integer
127
+ opt.on :n, :"no-reload", "Don't automatically reload the edited code"
128
+ opt.on :r, :reload, "Reload the edited code immediately (default for ruby files)"
124
129
  opt.on :h, :help, "This message." do
125
130
  output.puts opt
126
131
  end
127
132
  end
128
133
  next if opts.h?
129
134
 
130
- should_reload_at_top_level = opts[:r]
131
- should_reload_locally = false
132
-
133
- if opts.ex?
134
- next output.puts "No Exception found." if _pry_.last_exception.nil?
135
+ if [opts.ex? || nil, opts.t? || nil, !args.empty? || nil].compact.size > 1
136
+ next output.puts "Only one of --ex, --temp, and FILE may be specified"
137
+ end
135
138
 
136
- if is_core_rbx_path?(_pry_.last_exception.file)
137
- file_name = rbx_convert_path_to_full(_pry_.last_exception.file)
138
- else
139
- file_name = _pry_.last_exception.file
139
+ # edit of local code, eval'd within pry.
140
+ if !opts.ex? && args.empty?
141
+
142
+ content = if opts.t?
143
+ ""
144
+ elsif eval_string.strip != ""
145
+ eval_string
146
+ else
147
+ _pry_.input_array.reverse_each.find{ |x| x && x.strip != "" } || ""
148
+ end
149
+
150
+ line = content.lines.count
151
+
152
+ temp_file do |f|
153
+ f.puts(content)
154
+ f.flush
155
+ invoke_editor(f.path, line)
156
+ if !opts.n?
157
+ silence_warnings do
158
+ eval_string.replace(File.read(f.path))
159
+ end
160
+ end
140
161
  end
141
162
 
142
- line = _pry_.last_exception.line
143
- next output.puts "Exception has no associated file." if file_name.nil?
144
- next output.puts "Cannot edit exceptions raised in REPL." if Pry.eval_path == file_name
163
+ # edit of remote code, eval'd at top-level
164
+ else
165
+ if opts.ex?
166
+ next output.puts "No Exception found." if _pry_.last_exception.nil?
167
+ ex = _pry_.last_exception
168
+ bt_index = opts[:ex].to_i
169
+
170
+ ex_file, ex_line = ex.bt_source_location_for(bt_index)
171
+ if ex_file && is_core_rbx_path?(ex_file)
172
+ file_name = rbx_convert_path_to_full(ex_file)
173
+ else
174
+ file_name = ex_file
175
+ end
176
+
177
+ line = ex_line
178
+ next output.puts "Exception has no associated file." if file_name.nil?
179
+ next output.puts "Cannot edit exceptions raised in REPL." if Pry.eval_path == file_name
145
180
 
146
- should_reload_at_top_level = opts[:n] ? false : true
181
+ else
182
+ # break up into file:line
183
+ file_name = File.expand_path(args.first)
147
184
 
148
- elsif opts.t? || args.first.nil?
149
- file_name = temp_file do |f|
150
- f.puts eval_string if !eval_string.empty?
185
+ line = file_name.sub!(/:(\d+)$/, "") ? $1.to_i : 1
151
186
  end
152
- line = eval_string.lines.count + 1
153
- should_reload_locally = opts[:n] ? false : true
154
- else
155
- # break up into file:line
156
- /(:(\d+))?$/ =~ File.expand_path(args.first)
157
187
 
158
- # $` is pre-match
159
- file_name, line = [$`, $2]
160
- line = line ? line.to_i : opts[:l].to_i
161
- end
188
+ line = opts[:l].to_i if opts.l?
162
189
 
163
- invoke_editor(file_name, line)
164
- set_file_and_dir_locals(file_name)
190
+ invoke_editor(file_name, line)
191
+ set_file_and_dir_locals(file_name)
165
192
 
166
- if opts[:p]
167
- silence_warnings do
168
- _pry_.input = StringIO.new(File.readlines(file_name).join)
169
- end
170
- elsif should_reload_locally
171
- silence_warnings do
172
- eval_string.replace(File.read(file_name))
173
- end
174
- elsif should_reload_at_top_level
175
- silence_warnings do
176
- TOPLEVEL_BINDING.eval(File.read(file_name), file_name)
193
+ if opts.r? || ((opts.ex? || file_name.end_with?(".rb")) && !opts.n?)
194
+ silence_warnings do
195
+ TOPLEVEL_BINDING.eval(File.read(file_name), file_name)
196
+ end
177
197
  end
178
198
  end
179
199
  end
@@ -182,15 +202,18 @@ class Pry
182
202
  target = target()
183
203
 
184
204
  opts = Slop.parse!(args) do |opt|
185
- opt.banner "Usage: edit-method [OPTIONS] [METH]\n" \
186
- "Edit the method METH in an editor.\n" \
187
- "Ensure #{text.bold("Pry.config.editor")} is set to your editor of choice.\n" \
188
- "e.g: edit-method hello_method"
205
+ opt.banner unindent <<-USAGE
206
+ Usage: edit-method [OPTIONS] [METH]
207
+ Edit the method METH in an editor.
208
+ Ensure #{text.bold("Pry.config.editor")} is set to your editor of choice.
209
+ e.g: edit-method hello_method
210
+ USAGE
189
211
 
190
212
  opt.on :M, "instance-methods", "Operate on instance methods."
191
213
  opt.on :m, :methods, "Operate on methods."
192
214
  opt.on :n, "no-reload", "Do not automatically reload the method's file after editing."
193
215
  opt.on "no-jump", "Do not fast forward editor to first line of method."
216
+ opt.on :p, :patch, "Instead of editing the method's file, try to edit in a tempfile and apply as a monkey patch."
194
217
  opt.on :c, :context, "Select object context to run under.", true do |context|
195
218
  target = Pry.binding_for(target.eval(context))
196
219
  end
@@ -201,20 +224,42 @@ class Pry
201
224
 
202
225
  next if opts.help?
203
226
 
227
+ if !Pry.config.editor
228
+ output.puts "Error: No editor set!"
229
+ output.puts "Ensure that #{text.bold("Pry.config.editor")} is set to your editor of choice."
230
+ next
231
+ end
232
+
204
233
  meth_name = args.shift
205
- if (meth = get_method_object(meth_name, target, opts.to_hash(true))).nil?
234
+ meth_name, target, type = get_method_attributes(meth_name, target, opts.to_hash(true))
235
+ meth = get_method_object_from_target(meth_name, target, type)
236
+
237
+ if meth.nil?
206
238
  output.puts "Invalid method name: #{meth_name}."
207
239
  next
208
240
  end
209
241
 
210
- next output.puts "Error: No editor set!\nEnsure that #{text.bold("Pry.config.editor")} is set to your editor of choice." if !Pry.config.editor
242
+ if opts.p? || is_a_dynamically_defined_method?(meth)
243
+ code, _ = code_and_code_type_for(meth)
244
+
245
+ lines = code.lines.to_a
246
+ if lines[0] =~ /^def [^( \n]+/
247
+ lines[0] = "def #{meth_name}#{$'}"
248
+ else
249
+ next output.puts "Error: Pry can only patch methods created with the `def` keyword."
250
+ end
251
+
252
+ temp_file do |f|
253
+ f.puts lines.join
254
+ f.flush
255
+ invoke_editor(f.path, 0)
256
+ Pry.new(:input => StringIO.new(File.read(f.path))).rep(meth.owner)
257
+ end
258
+ next
259
+ end
211
260
 
212
261
  if is_a_c_method?(meth)
213
262
  output.puts "Error: Can't edit a C method."
214
- elsif is_a_dynamically_defined_method?(meth)
215
- output.puts "Error: Can't edit an eval method."
216
-
217
- # editor is invoked here
218
263
  else
219
264
  file, line = path_line_for(meth)
220
265
  set_file_and_dir_locals(file)
@@ -11,11 +11,8 @@ class Pry
11
11
  rescue Errno::ENOENT
12
12
  output.puts "No such directory: #{dest}"
13
13
  end
14
-
15
14
  else
16
- if !system(cmd)
17
- output.puts "Error: there was a problem executing system command: #{cmd}"
18
- end
15
+ Pry.config.system.call(output, cmd, _pry_)
19
16
  end
20
17
  end
21
18
 
@@ -32,12 +29,13 @@ class Pry
32
29
  end
33
30
  end
34
31
 
35
- alias_command "file-mode", "shell-mode", ""
32
+ alias_command "file-mode", "shell-mode"
36
33
 
37
34
  command "cat", "Show output of file FILE. Type `cat --help` for more information." do |*args|
38
35
  start_line = 0
39
36
  end_line = -1
40
37
  file_name = nil
38
+ bt_index = 0
41
39
 
42
40
  opts = Slop.parse!(args) do |opt|
43
41
  opt.on :s, :start, "Start line (defaults to start of file)Line 1 is the first line.", true, :as => Integer do |line|
@@ -48,17 +46,25 @@ class Pry
48
46
  end_line = line - 1
49
47
  end
50
48
 
51
- opt.on :ex, "Show a window of N lines either side of the last exception (defaults to 5).", :optional => true, :as => Integer do |window_size|
52
- window_size ||= 5
49
+ opt.on :ex, "Show a window of N lines either side of the last exception (defaults to 5).", :optional => true, :as => Integer do |bt_index_arg|
50
+ window_size = Pry.config.exception_window_size || 5
53
51
  ex = _pry_.last_exception
54
52
  next if !ex
55
- start_line = (ex.line - 1) - window_size
53
+ if bt_index_arg
54
+ bt_index = bt_index_arg
55
+ else
56
+ bt_index = ex.bt_index
57
+ end
58
+ ex.bt_index = (bt_index + 1) % ex.backtrace.size
59
+
60
+ ex_file, ex_line = ex.bt_source_location_for(bt_index)
61
+ start_line = (ex_line - 1) - window_size
56
62
  start_line = start_line < 0 ? 0 : start_line
57
- end_line = (ex.line - 1) + window_size
58
- if is_core_rbx_path?(ex.file)
59
- file_name = rbx_convert_path_to_full(ex.file)
63
+ end_line = (ex_line - 1) + window_size
64
+ if ex_file && is_core_rbx_path?(ex_file)
65
+ file_name = rbx_convert_path_to_full(ex_file)
60
66
  else
61
- file_name = ex.file
67
+ file_name = ex_file
62
68
  end
63
69
  end
64
70
 
@@ -74,7 +80,6 @@ class Pry
74
80
 
75
81
  if opts.ex?
76
82
  next output.puts "No Exception or Exception has no associated file." if file_name.nil?
77
- next output.puts "Cannot cat exceptions raised in REPL." if Pry.eval_path == file_name
78
83
  else
79
84
  file_name = args.shift
80
85
  end
@@ -84,8 +89,13 @@ class Pry
84
89
  next
85
90
  end
86
91
 
87
- contents, _, _ = read_between_the_lines(file_name, start_line, end_line)
88
- contents = syntax_highlight_by_file_type_or_specified(contents, file_name, opts[:type])
92
+ begin
93
+ contents, _, _ = read_between_the_lines(file_name, start_line, end_line)
94
+ contents = syntax_highlight_by_file_type_or_specified(contents, file_name, opts[:type])
95
+ rescue Errno::ENOENT
96
+ output.puts "Could not find file: #{file_name}"
97
+ next
98
+ end
89
99
 
90
100
  if opts.l?
91
101
  contents = text.with_line_numbers contents, start_line + 1
@@ -93,11 +103,12 @@ class Pry
93
103
 
94
104
  # add the arrow pointing to line that caused the exception
95
105
  if opts.ex?
106
+ ex_file, ex_line = _pry_.last_exception.bt_source_location_for(bt_index)
96
107
  contents = text.with_line_numbers contents, start_line + 1, :bright_red
97
108
 
98
109
  contents = contents.lines.each_with_index.map do |line, idx|
99
110
  l = idx + start_line
100
- if l == (_pry_.last_exception.line - 1)
111
+ if l == (ex_line - 1)
101
112
  " =>#{line}"
102
113
  else
103
114
  " #{line}"
@@ -106,7 +117,7 @@ class Pry
106
117
 
107
118
  # header for exceptions
108
119
  output.puts "\n#{Pry::Helpers::Text.bold('Exception:')} #{_pry_.last_exception.class}: #{_pry_.last_exception.message}\n--"
109
- output.puts "#{Pry::Helpers::Text.bold('From:')} #{file_name} @ line #{_pry_.last_exception.line}\n\n"
120
+ output.puts "#{Pry::Helpers::Text.bold('From:')} #{ex_file} @ line #{ex_line} @ #{text.bold('level: ')} #{bt_index} of backtrace (of #{_pry_.last_exception.backtrace.size - 1}).\n\n"
110
121
  end
111
122
 
112
123
  set_file_and_dir_locals(file_name)
@@ -44,7 +44,6 @@ class Pry
44
44
  def temp_file
45
45
  file = Tempfile.new(["tmp", ".rb"])
46
46
  yield file
47
- file.path
48
47
  ensure
49
48
  file.close
50
49
  end
@@ -178,37 +177,43 @@ class Pry
178
177
  [doc, code_type]
179
178
  end
180
179
 
181
- def get_method_object(meth_name, target, options)
180
+ def get_method_object(meth_name, target=nil, options={})
181
+ get_method_object_from_target(*get_method_attributes(meth_name, target, options)) rescue nil
182
+ end
183
+
184
+ def get_method_attributes(meth_name, target=nil, options={})
182
185
  if meth_name
183
186
  if meth_name =~ /(\S+)\#(\S+)\Z/
184
187
  context, meth_name = $1, $2
185
188
  target = Pry.binding_for(target.eval(context))
186
- options["instance-methods"] = true
187
- options[:methods] = false
189
+ type = :instance
188
190
  elsif meth_name =~ /(\S+)\.(\S+)\Z/
189
191
  context, meth_name = $1, $2
190
192
  target = Pry.binding_for(target.eval(context))
191
- options["instance-methods"] = false
192
- options[:methods] = true
193
+ type = :singleton
194
+ elsif options["instance_methods"]
195
+ type = :instance
196
+ elsif options[:methods]
197
+ type = :singleton
198
+ else
199
+ type = nil
193
200
  end
194
201
  else
195
202
  meth_name = meth_name_from_binding(target)
203
+ type = nil
196
204
  end
205
+ [meth_name, target, type]
206
+ end
197
207
 
198
- if !meth_name
199
- return nil
200
- end
201
-
202
- if options["instance-methods"]
208
+ def get_method_object_from_target(meth_name, target, type=nil)
209
+ case type
210
+ when :instance
203
211
  target.eval("instance_method(:#{meth_name})") rescue nil
204
- elsif options[:methods]
212
+ when :singleton
205
213
  target.eval("method(:#{meth_name})") rescue nil
206
214
  else
207
- begin
208
- target.eval("instance_method(:#{meth_name})")
209
- rescue
210
- target.eval("method(:#{meth_name})") rescue nil
211
- end
215
+ get_method_object_from_target(meth_name, target, :instance) ||
216
+ get_method_object_from_target(meth_name, target, :singleton)
212
217
  end
213
218
  end
214
219
 
@@ -305,7 +310,11 @@ class Pry
305
310
  # returns the file content between the lines and the normalized
306
311
  # start and end line numbers.
307
312
  def read_between_the_lines(file_name, start_line, end_line)
308
- content = File.read(File.expand_path(file_name))
313
+ if file_name == Pry.eval_path
314
+ content = Pry.line_buffer.drop(1).join
315
+ else
316
+ content = File.read(File.expand_path(file_name))
317
+ end
309
318
  lines_array = content.each_line.to_a
310
319
 
311
320
  [lines_array[start_line..end_line].join, normalized_line_number(start_line, lines_array.size),
@@ -372,6 +381,7 @@ class Pry
372
381
  else
373
382
  editor_invocation = "#{Pry.config.editor} #{start_line_syntax_for_editor(file, line)}"
374
383
  end
384
+ return nil unless editor_invocation
375
385
 
376
386
  if jruby?
377
387
  begin
@@ -379,18 +389,23 @@ class Pry
379
389
  pid = Spoon.spawnp(*editor_invocation.split)
380
390
  Process.waitpid(pid)
381
391
  rescue FFI::NotFoundError
382
- run ".#{editor_invocation}"
392
+ system(editor_invocation)
383
393
  end
384
394
  else
385
- run ".#{editor_invocation}"
395
+ # Note we dont want to use Pry.config.system here as that
396
+ # may be invoked non-interactively (i.e via Open4), whereas we want to
397
+ # ensure the editor is always interactive
398
+ system(editor_invocation)
386
399
  end
387
400
  end
388
401
 
402
+ # Return the syntax for a given editor for starting the editor
403
+ # and moving to a particular line within that file
389
404
  def start_line_syntax_for_editor(file_name, line_number)
390
405
  file_name = file_name.gsub(/\//, '\\') if RUBY_PLATFORM =~ /mswin|mingw/
391
406
 
392
- # special case 0th line
393
- return file_name if line_number <= 0
407
+ # special case for 1st line
408
+ return file_name if line_number <= 1
394
409
 
395
410
  case Pry.config.editor
396
411
  when /^[gm]?vi/, /^emacs/, /^nano/, /^pico/, /^gedit/, /^kate/
@@ -410,27 +425,45 @@ class Pry
410
425
  end
411
426
  end
412
427
 
413
- def prompt(message, options="Yn")
414
- opts = options.scan(/./)
415
- optstring = opts.join("/") # case maintained
416
- defaults = opts.select{|o| o.upcase == o }
417
- opts = opts.map{|o| o.downcase}
418
-
419
- raise "Error: Too many default values for the prompt: #{default.inspect}" if defaults.size > 1
420
-
421
- default = defaults.first
422
-
423
- loop do
424
- response = Pry.input.readline("#{message} (#{optstring}) ").downcase
425
- case response
426
- when *opts
427
- return response
428
- when ""
429
- return default.downcase
428
+ # Remove any common leading whitespace from every line in `text`.
429
+ #
430
+ # This can be used to make a HEREDOC line up with the left margin, without
431
+ # sacrificing the indentation level of the source code.
432
+ #
433
+ # e.g.
434
+ # opt.banner unindent <<-USAGE
435
+ # Lorem ipsum dolor sit amet, consectetur adipisicing elit,
436
+ # sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
437
+ # "Ut enim ad minim veniam."
438
+ # USAGE
439
+ #
440
+ # @param [String] The text from which to remove indentation
441
+ # @return [String], The text with indentation stripped.
442
+ #
443
+ # @copyright Heavily based on textwrap.dedent from Python, which is:
444
+ # Copyright (C) 1999-2001 Gregory P. Ward.
445
+ # Copyright (C) 2002, 2003 Python Software Foundation.
446
+ # Written by Greg Ward <gward@python.net>
447
+ #
448
+ # Licensed under <http://docs.python.org/license.html>
449
+ # From <http://hg.python.org/cpython/file/6b9f0a6efaeb/Lib/textwrap.py>
450
+ #
451
+ def unindent(text)
452
+ # Empty blank lines
453
+ text = text.sub(/^[ \t]+$/, '')
454
+
455
+ # Find the longest common whitespace to all indented lines
456
+ margin = text.scan(/^[ \t]*(?=[^ \t\n])/).inject do |current_margin, next_indent|
457
+ if next_indent.start_with?(current_margin)
458
+ current_margin
459
+ elsif current_margin.start_with?(next_indent)
460
+ next_indent
430
461
  else
431
- output.puts " |_ Invalid option: #{response.inspect}. Try again."
462
+ ""
432
463
  end
433
464
  end
465
+
466
+ text.gsub(/^#{margin}/, '')
434
467
  end
435
468
 
436
469
  end