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

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