pry 0.9.8.2-i386-mswin32 → 0.9.8.3-i386-mswin32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. data/CHANGELOG +8 -0
  2. data/README.markdown +20 -13
  3. data/Rakefile +1 -1
  4. data/lib/pry.rb +1 -2
  5. data/lib/pry/command.rb +88 -2
  6. data/lib/pry/command_set.rb +15 -85
  7. data/lib/pry/commands.rb +12 -8
  8. data/lib/pry/default_commands/cd.rb +58 -0
  9. data/lib/pry/default_commands/commands.rb +62 -0
  10. data/lib/pry/default_commands/context.rb +48 -165
  11. data/lib/pry/default_commands/editing.rb +385 -0
  12. data/lib/pry/default_commands/help.rb +127 -0
  13. data/lib/pry/default_commands/hist.rb +116 -0
  14. data/lib/pry/default_commands/{shell.rb → input_and_output.rb} +137 -15
  15. data/lib/pry/default_commands/introspection.rb +79 -232
  16. data/lib/pry/default_commands/ls.rb +4 -2
  17. data/lib/pry/default_commands/{basic.rb → misc.rb} +1 -14
  18. data/lib/pry/default_commands/navigating_pry.rb +114 -0
  19. data/lib/pry/helpers/base_helpers.rb +15 -3
  20. data/lib/pry/helpers/command_helpers.rb +16 -0
  21. data/lib/pry/history.rb +12 -4
  22. data/lib/pry/method.rb +2 -2
  23. data/lib/pry/pry_class.rb +7 -1
  24. data/lib/pry/pry_instance.rb +6 -0
  25. data/lib/pry/rbx_path.rb +6 -18
  26. data/lib/pry/version.rb +1 -1
  27. data/pry.gemspec +8 -8
  28. data/test/helper.rb +8 -0
  29. data/test/test_command.rb +256 -2
  30. data/test/test_command_integration.rb +2 -13
  31. data/test/test_command_set.rb +13 -23
  32. data/test/test_default_commands/test_help.rb +57 -0
  33. data/test/test_default_commands/test_introspection.rb +23 -0
  34. data/test/test_pry.rb +11 -0
  35. metadata +13 -9
  36. data/lib/pry/default_commands/documentation.rb +0 -209
  37. data/lib/pry/default_commands/input.rb +0 -247
  38. data/test/test_default_commands.rb +0 -58
@@ -0,0 +1,62 @@
1
+ class Pry
2
+ module DefaultCommands
3
+ Commands = Pry::CommandSet.new do
4
+ create_command "import-set", "Import a command set" do
5
+ group "Commands"
6
+ def process(command_set_name)
7
+ raise CommandError, "Provide a command set name" if command_set.nil?
8
+
9
+ set = target.eval(arg_string)
10
+ _pry_.commands.import set
11
+ end
12
+ end
13
+
14
+ create_command "install-command", "Install a disabled command." do |name|
15
+ group 'Commands'
16
+
17
+ banner <<-BANNER
18
+ Usage: install-command COMMAND
19
+
20
+ Installs the gems necessary to run the given COMMAND. You will generally not
21
+ need to run this unless told to by an error message.
22
+ BANNER
23
+
24
+ def process(name)
25
+ require 'rubygems/dependency_installer' unless defined? Gem::DependencyInstaller
26
+ command = find_command(name)
27
+
28
+ if command_dependencies_met?(command.options)
29
+ output.puts "Dependencies for #{command.name} are met. Nothing to do."
30
+ return
31
+ end
32
+
33
+ output.puts "Attempting to install `#{name}` command..."
34
+ gems_to_install = Array(command.options[:requires_gem])
35
+
36
+ gems_to_install.each do |g|
37
+ next if gem_installed?(g)
38
+ output.puts "Installing `#{g}` gem..."
39
+
40
+ begin
41
+ Gem::DependencyInstaller.new.install(g)
42
+ rescue Gem::GemNotFoundException
43
+ raise CommandError, "Required Gem: `#{g}` not found. Aborting command installation."
44
+ end
45
+ end
46
+
47
+ Gem.refresh
48
+ gems_to_install.each do |g|
49
+ begin
50
+ require g
51
+ rescue LoadError
52
+ raise CommandError, "Required Gem: `#{g}` installed but not found?!. Aborting command installation."
53
+ end
54
+ end
55
+
56
+ output.puts "Installation of `#{name}` successful! Type `help #{name}` for information"
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+
@@ -1,167 +1,30 @@
1
1
  require "pry/default_commands/ls"
2
+ require "pry/default_commands/cd"
2
3
 
3
4
  class Pry
4
5
  module DefaultCommands
5
6
 
6
7
  Context = Pry::CommandSet.new do
7
8
  import Ls
9
+ import Cd
8
10
 
9
- create_command "cd" do
10
- description "Move into a new context (object or scope). Type `cd --help` for more information."
11
-
12
- banner <<-BANNER
13
- Usage: cd [OPTIONS] [--help]
14
-
15
- Move into new context (object or scope). As in unix shells use
16
- `cd ..` to go back and `cd /` to return to Pry top-level).
17
- Complex syntax (e.g cd ../@x/y) also supported.
18
-
19
- e.g: `cd @x`
20
- e.g: `cd ..
21
- e.g: `cd /`
22
-
23
- https://github.com/pry/pry/wiki/State-navigation#wiki-Changing_scope
24
- BANNER
25
-
26
- def process
27
- path = arg_string.split(/\//)
28
- stack = _pry_.binding_stack.dup
29
-
30
- # special case when we only get a single "/", return to root
31
- stack = [stack.first] if path.empty?
32
-
33
- path.each do |context|
34
- begin
35
- case context.chomp
36
- when ""
37
- stack = [stack.first]
38
- when "::"
39
- stack.push(TOPLEVEL_BINDING)
40
- when "."
41
- next
42
- when ".."
43
- unless stack.size == 1
44
- stack.pop
45
- end
46
- else
47
- stack.push(Pry.binding_for(stack.last.eval(context)))
48
- end
49
-
50
- rescue RescuableException => e
51
- output.puts "Bad object path: #{arg_string.chomp}. Failed trying to resolve: #{context}"
52
- output.puts e.inspect
53
- return
54
- end
55
- end
56
-
57
- _pry_.binding_stack = stack
58
- end
59
- end
60
-
61
- command "switch-to", "Start a new sub-session on a binding in the current stack (numbered by nesting)." do |selection|
62
- selection = selection.to_i
63
-
64
- if selection < 0 || selection > _pry_.binding_stack.size - 1
65
- raise CommandError, "Invalid binding index #{selection} - use `nesting` command to view valid indices."
66
- else
67
- Pry.start(_pry_.binding_stack[selection])
68
- end
69
- end
70
-
71
- command "nesting", "Show nesting information." do
72
- output.puts "Nesting status:"
73
- output.puts "--"
74
- _pry_.binding_stack.each_with_index do |obj, level|
75
- if level == 0
76
- output.puts "#{level}. #{Pry.view_clip(obj.eval('self'))} (Pry top level)"
77
- else
78
- output.puts "#{level}. #{Pry.view_clip(obj.eval('self'))}"
79
- end
80
- end
81
- end
82
-
83
- command "jump-to", "Jump to a binding further up the stack, popping all bindings below." do |break_level|
84
- break_level = break_level.to_i
85
- nesting_level = _pry_.binding_stack.size - 1
86
-
87
- case break_level
88
- when nesting_level
89
- output.puts "Already at nesting level #{nesting_level}"
90
- when (0...nesting_level)
91
- _pry_.binding_stack.slice!(break_level + 1, _pry_.binding_stack.size)
92
-
93
- else
94
- max_nest_level = nesting_level - 1
95
- output.puts "Invalid nest level. Must be between 0 and #{max_nest_level}. Got #{break_level}."
96
- end
97
- end
98
-
99
- command "exit-all", "End the current Pry session (popping all bindings) and returning to caller. Accepts optional return value. Aliases: !!@" do
100
- # clear the binding stack
101
- _pry_.binding_stack.clear
102
-
103
- # break out of the repl loop
104
- throw(:breakout, target.eval(arg_string))
105
- end
106
-
107
- alias_command "!!@", "exit-all"
108
-
109
- create_command "exit" do
110
- description "Pop the previous binding (does NOT exit program). Type `exit --help` for more information. Aliases: quit"
111
-
112
- banner <<-BANNER
113
- Usage: exit [OPTIONS] [--help]
114
- Aliases: quit
115
-
116
- It can be useful to exit a context with a user-provided value. For
117
- instance an exit value can be used to determine program flow.
118
-
119
- e.g: `exit "pry this"`
120
- e.g: `exit`
121
-
122
- https://github.com/pry/pry/wiki/State-navigation#wiki-Exit_with_value
123
- BANNER
124
-
125
- command_options(
126
- :keep_retval => true
127
- )
128
-
129
- def process
130
- if _pry_.binding_stack.one?
131
- # when breaking out of top-level then behave like `exit-all`
132
- process_exit_all
133
- else
134
- # otherwise just pop a binding and return user supplied value
135
- process_pop_and_return
136
- end
137
- end
138
-
139
- def process_exit_all
140
- _pry_.binding_stack.clear
141
- throw(:breakout, target.eval(arg_string))
142
- end
143
-
144
- def process_pop_and_return
145
- popped_object = _pry_.binding_stack.pop.eval('self')
11
+ command "whereami", "Show the code context for the session. (whereami <n> shows <n> extra lines of code around the invocation line. Default: 5)" do |num|
12
+ file, line_num = file_and_line_from_binding(target)
13
+ i_num = num ? num.to_i : 5
146
14
 
147
- # return a user-specified value if given otherwise return the object
148
- return target.eval(arg_string) unless arg_string.empty?
149
- popped_object
15
+ if file != Pry.eval_path && (file =~ /(\(.*\))|<.*>/ || file == "" || file == "-e")
16
+ raise CommandError, "Cannot find local context. Did you use binding.pry?"
150
17
  end
151
- end
152
-
153
- alias_command "quit", "exit"
154
18
 
155
- command "exit-program", "End the current program. Aliases: quit-program, !!!" do
156
- Pry.save_history if Pry.config.history.should_save
157
- Kernel.exit target.eval(arg_string).to_i
158
- end
19
+ set_file_and_dir_locals(file)
159
20
 
160
- alias_command "quit-program", "exit-program"
161
- alias_command "!!!", "exit-program"
21
+ method = Pry::Method.from_binding(target)
22
+ method_description = method ? " in #{method.name_with_owner}" : ""
23
+ output.puts "\n#{text.bold('From:')} #{file} @ line #{line_num}#{method_description}:\n\n"
162
24
 
163
- command "!pry", "Start a Pry session on current self; this even works mid multi-line expression." do
164
- target.pry
25
+ code = Pry::Code.from_file(file).around(line_num, i_num)
26
+ output.puts code.with_line_numbers.with_marker(line_num)
27
+ output.puts
165
28
  end
166
29
 
167
30
  create_command "pry-backtrace", "Show the backtrace for the Pry session." do
@@ -184,24 +47,44 @@ class Pry
184
47
  end
185
48
  end
186
49
 
187
- command "whereami", "Show the code context for the session. (whereami <n> shows <n> extra lines of code around the invocation line. Default: 5)" do |num|
188
- file = target.eval('__FILE__')
189
- line_num = target.eval('__LINE__')
190
- i_num = num ? num.to_i : 5
50
+ command "reset", "Reset the REPL to a clean state." do
51
+ output.puts "Pry reset."
52
+ exec "pry"
53
+ end
191
54
 
192
- if file != Pry.eval_path && (file =~ /(\(.*\))|<.*>/ || file == "" || file == "-e")
193
- raise CommandError, "Cannot find local context. Did you use `binding.pry`?"
194
- end
55
+ create_command /wtf([?!]*)/, "Show the backtrace of the most recent exception" do
56
+ options :listing => 'wtf?'
195
57
 
196
- set_file_and_dir_locals(file)
58
+ banner <<-BANNER
59
+ Show's a few lines of the backtrace of the most recent exception (also available
60
+ as _ex_.backtrace).
197
61
 
198
- method = Pry::Method.from_binding(target)
199
- method_description = method ? " in #{method.name_with_owner}" : ""
200
- output.puts "\n#{text.bold('From:')} #{file} @ line #{line_num}#{method_description}:\n\n"
62
+ If you want to see more lines, add more question marks or exclamation marks:
201
63
 
202
- code = Pry::Code.from_file(file).around(line_num, i_num)
203
- output.puts code.with_line_numbers.with_marker(line_num)
204
- output.puts
64
+ e.g.
65
+ pry(main)> wtf?
66
+ pry(main)> wtf?!???!?!?
67
+
68
+ To see the entire backtrace, pass the -v/--verbose flag:
69
+
70
+ e.g.
71
+ pry(main)> wtf -v
72
+ BANNER
73
+
74
+ def options(opt)
75
+ opt.on(:v, :verbose, "Show the full backtrace.")
76
+ end
77
+
78
+ def process
79
+ raise Pry::CommandError, "No most-recent exception" unless _pry_.last_exception
80
+
81
+ output.puts "#{text.bold('Exception:')} #{_pry_.last_exception.class}: #{_pry_.last_exception}\n--"
82
+ if opts.verbose?
83
+ output.puts Code.new(_pry_.last_exception.backtrace, 0, :text).with_line_numbers.to_s
84
+ else
85
+ output.puts Code.new(_pry_.last_exception.backtrace.first([captures[0].size, 0.5].max * 10), 0, :text).with_line_numbers.to_s
86
+ end
87
+ end
205
88
  end
206
89
 
207
90
  end
@@ -0,0 +1,385 @@
1
+ require 'tempfile'
2
+ require 'pry/default_commands/hist'
3
+
4
+ class Pry
5
+ module DefaultCommands
6
+
7
+ Editing = Pry::CommandSet.new do
8
+ import Hist
9
+
10
+ create_command "!", "Clear the input buffer. Useful if the parsing process goes wrong and you get stuck in the read loop.", :use_prefix => false do
11
+ def process
12
+ output.puts "Input buffer cleared!"
13
+ eval_string.replace("")
14
+ end
15
+ end
16
+
17
+ create_command "show-input", "Show the contents of the input buffer for the current multi-line expression." do
18
+ def process
19
+ output.puts Code.new(eval_string).with_line_numbers
20
+ end
21
+ end
22
+
23
+ create_command "edit" do
24
+ description "Invoke the default editor on a file."
25
+
26
+ banner <<-BANNER
27
+ Usage: edit [--no-reload|--reload] [--line LINE] [--temp|--ex|FILE[:LINE]|--in N]
28
+
29
+ Open a text editor. When no FILE is given, edits the pry input buffer.
30
+ Ensure Pry.config.editor is set to your editor of choice.
31
+
32
+ e.g: `edit sample.rb`
33
+ e.g: `edit sample.rb --line 105`
34
+ e.g: `edit --ex`
35
+
36
+ https://github.com/pry/pry/wiki/Editor-integration#wiki-Edit_command
37
+ BANNER
38
+
39
+ def options(opt)
40
+ opt.on :e, :ex, "Open the file that raised the most recent exception (_ex_.file)", :optional => true, :as => Integer
41
+ opt.on :i, :in, "Open a temporary file containing the Nth line of _in_. N may be a range.", :optional => true, :as => Range, :default => -1..-1
42
+ opt.on :t, :temp, "Open an empty temporary file"
43
+ opt.on :l, :line, "Jump to this line in the opened file", true, :as => Integer
44
+ opt.on :n, :"no-reload", "Don't automatically reload the edited code"
45
+ opt.on :c, :"current", "Open the current __FILE__ and at __LINE__ (as returned by `whereami`)."
46
+ opt.on :r, :reload, "Reload the edited code immediately (default for ruby files)"
47
+ end
48
+
49
+ def process
50
+ if [opts.present?(:ex), opts.present?(:temp), opts.present?(:in), !args.empty?].count(true) > 1
51
+ raise CommandError, "Only one of --ex, --temp, --in and FILE may be specified."
52
+ end
53
+
54
+ if !opts.present?(:ex) && !opts.present?(:current) && args.empty?
55
+ # edit of local code, eval'd within pry.
56
+ process_local_edit
57
+ else
58
+ # edit of remote code, eval'd at top-level
59
+ process_remote_edit
60
+ end
61
+ end
62
+
63
+ def process_i
64
+ case opts[:i]
65
+ when Range
66
+ (_pry_.input_array[opts[:i]] || []).join
67
+ when Fixnum
68
+ _pry_.input_array[opts[:i]] || ""
69
+ else
70
+ return output.puts "Not a valid range: #{opts[:i]}"
71
+ end
72
+ end
73
+
74
+ def process_local_edit
75
+ content = case
76
+ when opts.present?(:temp)
77
+ ""
78
+ when opts.present?(:in)
79
+ process_i
80
+ when eval_string.strip != ""
81
+ eval_string
82
+ else
83
+ _pry_.input_array.reverse_each.find{ |x| x && x.strip != "" } || ""
84
+ end
85
+
86
+ line = content.lines.count
87
+
88
+ temp_file do |f|
89
+ f.puts(content)
90
+ f.flush
91
+ invoke_editor(f.path, line)
92
+ if !opts.present?(:'no-reload') && !Pry.config.disable_auto_reload
93
+ silence_warnings do
94
+ eval_string.replace(File.read(f.path))
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ def process_remote_edit
101
+ if opts.present?(:ex)
102
+ if _pry_.last_exception.nil?
103
+ raise CommandError, "No exception found."
104
+ end
105
+
106
+ ex = _pry_.last_exception
107
+ bt_index = opts[:ex].to_i
108
+
109
+ ex_file, ex_line = ex.bt_source_location_for(bt_index)
110
+ if ex_file && RbxPath.is_core_path?(ex_file)
111
+ file_name = RbxPath.convert_path_to_full(ex_file)
112
+ else
113
+ file_name = ex_file
114
+ end
115
+
116
+ line = ex_line
117
+
118
+ if file_name.nil?
119
+ raise CommandError, "Exception has no associated file."
120
+ end
121
+
122
+ if Pry.eval_path == file_name
123
+ raise CommandError, "Cannot edit exceptions raised in REPL."
124
+ end
125
+ elsif opts.present?(:current)
126
+ file_name = target.eval("__FILE__")
127
+ line = target.eval("__LINE__")
128
+ else
129
+
130
+ # break up into file:line
131
+ file_name = File.expand_path(args.first)
132
+ line = file_name.sub!(/:(\d+)$/, "") ? $1.to_i : 1
133
+ end
134
+
135
+ if not_a_real_file?(file_name)
136
+ raise CommandError, "#{file_name} is not a valid file name, cannot edit!"
137
+ end
138
+
139
+ line = opts[:l].to_i if opts.present?(:line)
140
+
141
+ invoke_editor(file_name, line)
142
+ set_file_and_dir_locals(file_name)
143
+
144
+ if opts.present?(:reload) || ((opts.present?(:ex) || file_name.end_with?(".rb")) && !opts.present?(:'no-reload')) && !Pry.config.disable_auto_reload
145
+ silence_warnings do
146
+ TOPLEVEL_BINDING.eval(File.read(file_name), file_name)
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ create_command "edit-method" do
153
+ description "Edit the source code for a method."
154
+
155
+ banner <<-BANNER
156
+ Usage: edit-method [OPTIONS] [METH]
157
+
158
+ Edit the method METH in an editor.
159
+ Ensure Pry.config.editor is set to your editor of choice.
160
+
161
+ e.g: `edit-method hello_method`
162
+ e.g: `edit-method Pry#rep`
163
+ e.g: `edit-method`
164
+
165
+ https://github.com/pry/pry/wiki/Editor-integration#wiki-Edit_method
166
+ BANNER
167
+
168
+ command_options :shellwords => false
169
+
170
+ def options(opt)
171
+ method_options(opt)
172
+ opt.on :n, "no-reload", "Do not automatically reload the method's file after editing."
173
+ opt.on "no-jump", "Do not fast forward editor to first line of method."
174
+ opt.on :p, :patch, "Instead of editing the method's file, try to edit in a tempfile and apply as a monkey patch."
175
+ end
176
+
177
+ def process
178
+ if !Pry.config.editor
179
+ raise CommandError, "No editor set!\nEnsure that #{text.bold("Pry.config.editor")} is set to your editor of choice."
180
+ end
181
+
182
+ begin
183
+ @method = method_object
184
+ rescue NonMethodContextError => err
185
+ end
186
+
187
+ if opts.present?(:patch) || (@method && @method.dynamically_defined?)
188
+ if err
189
+ raise err # can't patch a non-method
190
+ end
191
+
192
+ process_patch
193
+ else
194
+ if err && !File.exist?(target.eval('__FILE__'))
195
+ raise err # can't edit a non-file
196
+ end
197
+
198
+ process_file
199
+ end
200
+ end
201
+
202
+ def process_patch
203
+ lines = @method.source.lines.to_a
204
+
205
+ if ((original_name = @method.original_name) &&
206
+ lines[0] =~ /^def (?:.*?\.)?#{original_name}(?=[\(\s;]|$)/)
207
+ lines[0] = "def #{original_name}#{$'}"
208
+ else
209
+ raise CommandError, "Pry can only patch methods created with the `def` keyword."
210
+ end
211
+
212
+ temp_file do |f|
213
+ f.puts lines.join
214
+ f.flush
215
+ invoke_editor(f.path, 0)
216
+
217
+ if @method.alias?
218
+ with_method_transaction(original_name, @method.owner) do
219
+ Pry.new(:input => StringIO.new(File.read(f.path))).rep(@method.owner)
220
+ Pry.binding_for(@method.owner).eval("alias #{@method.name} #{original_name}")
221
+ end
222
+ else
223
+ Pry.new(:input => StringIO.new(File.read(f.path))).rep(@method.owner)
224
+ end
225
+ end
226
+ end
227
+
228
+ def process_file
229
+ file, line = extract_file_and_line
230
+
231
+ invoke_editor(file, opts["no-jump"] ? 0 : line)
232
+ silence_warnings do
233
+ load file unless opts.present?(:'no-reload') || Pry.config.disable_auto_reload
234
+ end
235
+ end
236
+
237
+ protected
238
+ def extract_file_and_line
239
+ if @method
240
+ if @method.source_type == :c
241
+ raise CommandError, "Can't edit a C method."
242
+ else
243
+ [@method.source_file, @method.source_line]
244
+ end
245
+ else
246
+ [target.eval('__FILE__'), target.eval('__LINE__')]
247
+ end
248
+ end
249
+
250
+ def with_method_transaction(meth_name, target=TOPLEVEL_BINDING)
251
+ target = Pry.binding_for(target)
252
+ temp_name = "__pry_#{meth_name}__"
253
+
254
+ target.eval("alias #{temp_name} #{meth_name}")
255
+ yield
256
+ target.eval("alias #{meth_name} #{temp_name}")
257
+ ensure
258
+ target.eval("undef #{temp_name}") rescue nil
259
+ end
260
+ end
261
+
262
+ create_command(/amend-line(?: (-?\d+)(?:\.\.(-?\d+))?)?/) do
263
+ description "Amend a line of input in multi-line mode."
264
+ command_options :interpolate => false, :listing => "amend-line"
265
+
266
+ banner <<-'BANNER'
267
+ Amend a line of input in multi-line mode. `amend-line N`, where the N in `amend-line N` represents line to replace.
268
+
269
+ Can also specify a range of lines using `amend-line N..M` syntax. Passing '!' as replacement content deletes the line(s) instead.
270
+ e.g amend-line 1 puts 'hello world! # replace line 1'
271
+ e.g amend-line 1..4 ! # delete lines 1..4
272
+ e.g amend-line 3 >puts 'goodbye' # insert before line 3
273
+ e.g amend-line puts 'hello again' # no line number modifies immediately preceding line
274
+ BANNER
275
+
276
+ def process
277
+ start_line_number, end_line_number, replacement_line = *args
278
+
279
+ if eval_string.empty?
280
+ raise CommandError, "No input to amend."
281
+ end
282
+
283
+ replacement_line = "" if !replacement_line
284
+ input_array = eval_string.each_line.to_a
285
+
286
+ end_line_number = start_line_number.to_i if !end_line_number
287
+ line_range = start_line_number ? (one_index_number(start_line_number.to_i)..one_index_number(end_line_number.to_i)) : input_array.size - 1
288
+
289
+ # delete selected lines if replacement line is '!'
290
+ if arg_string == "!"
291
+ input_array.slice!(line_range)
292
+ elsif arg_string.start_with?(">")
293
+ insert_slot = Array(line_range).first
294
+ input_array.insert(insert_slot, arg_string[1..-1] + "\n")
295
+ else
296
+ input_array[line_range] = arg_string + "\n"
297
+ end
298
+ eval_string.replace input_array.join
299
+ run "show-input"
300
+ end
301
+ end
302
+
303
+ create_command "play" do
304
+ description "Play back a string variable or a method or a file as input."
305
+
306
+ banner <<-BANNER
307
+ Usage: play [OPTIONS] [--help]
308
+
309
+ The play command enables you to replay code from files and methods as
310
+ if they were entered directly in the Pry REPL. Default action (no
311
+ options) is to play the provided string variable
312
+
313
+ e.g: `play -i 20 --lines 1..3`
314
+ e.g: `play -m Pry#repl --lines 1..-1`
315
+ e.g: `play -f Rakefile --lines 5`
316
+
317
+ https://github.com/pry/pry/wiki/User-Input#wiki-Play
318
+ BANNER
319
+
320
+ attr_accessor :content
321
+
322
+ def setup
323
+ self.content = ""
324
+ end
325
+
326
+ def options(opt)
327
+ opt.on :m, :method, "Play a method's source.", true do |meth_name|
328
+ meth = get_method_or_raise(meth_name, target, {})
329
+ self.content << meth.source
330
+ end
331
+ opt.on :d, :doc, "Play a method's documentation.", true do |meth_name|
332
+ meth = get_method_or_raise(meth_name, target, {})
333
+ text.no_color do
334
+ self.content << process_comment_markup(meth.doc, :ruby)
335
+ end
336
+ end
337
+ opt.on :c, :command, "Play a command's source.", true do |command_name|
338
+ command = find_command(command_name)
339
+ block = Pry::Method.new(find_command(command_name).block)
340
+ self.content << block.source
341
+ end
342
+ opt.on :f, :file, "Play a file.", true do |file|
343
+ self.content << File.read(File.expand_path(file))
344
+ end
345
+ opt.on :l, :lines, "Only play a subset of lines.", :optional => true, :as => Range, :default => 1..-1
346
+ opt.on :i, :in, "Play entries from Pry's input expression history. Takes an index or range.", :optional => true,
347
+ :as => Range, :default => -5..-1 do |range|
348
+ input_expressions = _pry_.input_array[range] || []
349
+ Array(input_expressions).each { |v| self.content << v }
350
+ end
351
+ opt.on :o, "open", 'When used with the -m switch, it plays the entire method except the last line, leaving the method definition "open". `amend-line` can then be used to modify the method.'
352
+ end
353
+
354
+ def process
355
+ perform_play
356
+ run "show-input" unless _pry_.complete_expression?(eval_string)
357
+ end
358
+
359
+ def process_non_opt
360
+ args.each do |arg|
361
+ begin
362
+ self.content << target.eval(arg)
363
+ rescue Pry::RescuableException
364
+ raise CommandError, "Prblem when evaling #{arg}."
365
+ end
366
+ end
367
+ end
368
+
369
+ def perform_play
370
+ process_non_opt
371
+
372
+ if opts.present?(:lines)
373
+ self.content = restrict_to_lines(self.content, opts[:l])
374
+ end
375
+
376
+ if opts.present?(:open)
377
+ self.content = restrict_to_lines(self.content, 1..-2)
378
+ end
379
+
380
+ eval_string << self.content
381
+ end
382
+ end
383
+ end
384
+ end
385
+ end