Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Move all commands into individual files

  • Loading branch information...
commit 25cbe4313729d53cd8254dca8e3ce0022ab499eb 1 parent 997cd97
@rf- rf- authored
Showing with 2,542 additions and 2,633 deletions.
  1. +1 −0  lib/pry.rb
  2. +7 −26 lib/pry/commands.rb
  3. +43 −0 lib/pry/default_commands/amend_line.rb
  4. +8 −0 lib/pry/default_commands/bang.rb
  5. +5 −0 lib/pry/default_commands/bang_pry.rb
  6. +170 −0 lib/pry/default_commands/cat.rb
  7. +60 −65 lib/pry/default_commands/cd.rb
  8. +0 −62 lib/pry/default_commands/commands.rb
  9. +0 −98 lib/pry/default_commands/context.rb
  10. +78 −82 lib/pry/default_commands/easter_eggs.rb
  11. +137 −0 lib/pry/default_commands/edit.rb
  12. +179 −0 lib/pry/default_commands/edit_method.rb
  13. +0 −463 lib/pry/default_commands/editing.rb
  14. +41 −0 lib/pry/default_commands/exit.rb
  15. +14 −0 lib/pry/default_commands/exit_all.rb
  16. +9 −0 lib/pry/default_commands/exit_program.rb
  17. +139 −144 lib/pry/default_commands/find_method.rb
  18. +20 −0 lib/pry/default_commands/gem_cd.rb
  19. +28 −0 lib/pry/default_commands/gem_install.rb
  20. +31 −0 lib/pry/default_commands/gem_list.rb
  21. +0 −84 lib/pry/default_commands/gems.rb
  22. +156 −160 lib/pry/default_commands/gist.rb
  23. +103 −107 lib/pry/default_commands/help.rb
  24. +90 −98 lib/pry/default_commands/hist.rb
  25. +12 −0 lib/pry/default_commands/import_set.rb
  26. +0 −306 lib/pry/default_commands/input_and_output.rb
  27. +47 −0 lib/pry/default_commands/install_command.rb
  28. +0 −488 lib/pry/default_commands/introspection.rb
  29. +17 −0 lib/pry/default_commands/jump_to.rb
  30. +215 −221 lib/pry/default_commands/ls.rb
  31. +0 −38 lib/pry/default_commands/misc.rb
  32. +0 −110 lib/pry/default_commands/navigating_pry.rb
  33. +13 −0 lib/pry/default_commands/nesting.rb
  34. +84 −0 lib/pry/default_commands/play.rb
  35. +21 −0 lib/pry/default_commands/pry_backtrace.rb
  36. +5 −0 lib/pry/default_commands/pry_version.rb
  37. +23 −0 lib/pry/default_commands/raise_up.rb
  38. +15 −0 lib/pry/default_commands/reload_method.rb
  39. +6 −0 lib/pry/default_commands/reset.rb
  40. +46 −0 lib/pry/default_commands/ri.rb
  41. +95 −0 lib/pry/default_commands/save_file.rb
  42. +20 −0 lib/pry/default_commands/shell_command.rb
  43. +16 −0 lib/pry/default_commands/shell_mode.rb
  44. +42 −0 lib/pry/default_commands/show_command.rb
  45. +133 −0 lib/pry/default_commands/show_doc.rb
  46. +7 −0 lib/pry/default_commands/show_input.rb
  47. +128 −0 lib/pry/default_commands/show_source.rb
  48. +10 −0 lib/pry/default_commands/simple_prompt.rb
  49. +28 −0 lib/pry/default_commands/stat.rb
  50. +11 −0 lib/pry/default_commands/switch_to.rb
  51. +6 −0 lib/pry/default_commands/toggle_color.rb
  52. +71 −76 lib/pry/default_commands/whereami.rb
  53. +36 −0 lib/pry/default_commands/wtf.rb
  54. +1 −0  lib/pry/helpers.rb
  55. +106 −0 lib/pry/helpers/module_introspection_helpers.rb
  56. +1 −1  test/test_command.rb
  57. +3 −1 test/test_command_integration.rb
  58. +4 −1 test/test_command_set.rb
  59. +1 −2  test/test_default_commands/test_help.rb
View
1  lib/pry.rb
@@ -169,6 +169,7 @@ module ExtendCommandBundle
require "optparse"
require "slop"
require "rbconfig"
+require 'tempfile'
begin
require 'readline'
View
33 lib/pry/commands.rb
@@ -1,29 +1,10 @@
-require "pry/default_commands/misc"
-require "pry/default_commands/help"
-require "pry/default_commands/gems"
-require "pry/default_commands/context"
-require "pry/default_commands/commands"
-require "pry/default_commands/input_and_output"
-require "pry/default_commands/introspection"
-require "pry/default_commands/editing"
-require "pry/default_commands/navigating_pry"
-require "pry/default_commands/easter_eggs"
+# Default commands used by Pry.
+Pry::Commands = Pry::CommandSet.new
-require "pry/extended_commands/experimental"
-
-class Pry
+Dir[File.expand_path('../default_commands/*.rb', __FILE__)].each do |file|
+ require file
+end
- # Default commands used by Pry.
- Commands = Pry::CommandSet.new do
- import DefaultCommands::Misc
- import DefaultCommands::Help
- import DefaultCommands::Gems
- import DefaultCommands::Context
- import DefaultCommands::NavigatingPry
- import DefaultCommands::Editing
- import DefaultCommands::InputAndOutput
- import DefaultCommands::Introspection
- import DefaultCommands::EasterEggs
- import DefaultCommands::Commands
- end
+Dir[File.expand_path('../extended_commands/*.rb', __FILE__)].each do |file|
+ require file
end
View
43 lib/pry/default_commands/amend_line.rb
@@ -0,0 +1,43 @@
+class Pry
+ Pry::Commands.create_command(/amend-line(?: (-?\d+)(?:\.\.(-?\d+))?)?/) do
+ description "Amend a line of input in multi-line mode."
+ command_options :interpolate => false, :listing => "amend-line"
+
+ banner <<-'BANNER'
+ Amend a line of input in multi-line mode. `amend-line N`, where the N in `amend-line N` represents line to replace.
+
+ Can also specify a range of lines using `amend-line N..M` syntax. Passing '!' as replacement content deletes the line(s) instead.
+ e.g amend-line 1 puts 'hello world! # replace line 1'
+ e.g amend-line 1..4 ! # delete lines 1..4
+ e.g amend-line 3 >puts 'goodbye' # insert before line 3
+ e.g amend-line puts 'hello again' # no line number modifies immediately preceding line
+ BANNER
+
+ def process
+ start_line_number, end_line_number, replacement_line = *args
+
+ if eval_string.empty?
+ raise CommandError, "No input to amend."
+ end
+
+ replacement_line = "" if !replacement_line
+ input_array = eval_string.each_line.to_a
+
+ end_line_number = start_line_number.to_i if !end_line_number
+ 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
+
+ # delete selected lines if replacement line is '!'
+ if arg_string == "!"
+ input_array.slice!(line_range)
+ elsif arg_string.start_with?(">")
+ insert_slot = Array(line_range).first
+ input_array.insert(insert_slot, arg_string[1..-1] + "\n")
+ else
+ input_array[line_range] = arg_string + "\n"
+ end
+ eval_string.replace input_array.join
+ run "show-input"
+ end
+ end
+end
+
View
8 lib/pry/default_commands/bang.rb
@@ -0,0 +1,8 @@
+class Pry
+ Pry::Commands.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
+ def process
+ output.puts "Input buffer cleared!"
+ eval_string.replace("")
+ end
+ end
+end
View
5 lib/pry/default_commands/bang_pry.rb
@@ -0,0 +1,5 @@
+class Pry
+ Pry::Commands.command "!pry", "Start a Pry session on current self; this even works mid multi-line expression." do
+ target.pry
+ end
+end
View
170 lib/pry/default_commands/cat.rb
@@ -0,0 +1,170 @@
+class Pry
+ Pry::Commands.create_command "cat", "Show code from a file, Pry's input buffer, or the last exception." do
+ banner <<-USAGE
+ Usage: cat FILE
+ cat --ex [STACK_INDEX]
+ cat --in [INPUT_INDEX_OR_RANGE]
+
+ cat is capable of showing part or all of a source file, the context of the
+ last exception, or an expression from Pry's input history.
+
+ cat --ex defaults to showing the lines surrounding the location of the last
+ exception. Invoking it more than once travels up the exception's backtrace,
+ and providing a number shows the context of the given index of the backtrace.
+ USAGE
+
+ def options(opt)
+ opt.on :ex, "Show the context of the last exception.", :optional_argument => true, :as => Integer
+ opt.on :i, :in, "Show one or more entries from Pry's expression history.", :optional_argument => true, :as => Range, :default => -5..-1
+
+ opt.on :s, :start, "Starting line (defaults to the first line).", :optional_argument => true, :as => Integer
+ opt.on :e, :end, "Ending line (defaults to the last line).", :optional_argument => true, :as => Integer
+ opt.on :l, :'line-numbers', "Show line numbers."
+ opt.on :t, :type, "The file type for syntax highlighting (e.g., 'ruby' or 'python').", :argument => true, :as => Symbol
+
+ opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
+ end
+
+ def process
+ handler = case
+ when opts.present?(:ex)
+ method :process_ex
+ when opts.present?(:in)
+ method :process_in
+ else
+ method :process_file
+ end
+
+ output = handler.call do |code|
+ code.code_type = opts[:type] || :ruby
+
+ code.between(opts[:start] || 1, opts[:end] || -1).
+ with_line_numbers(opts.present?(:'line-numbers') || opts.present?(:ex))
+ end
+
+ render_output(output, opts)
+ end
+
+ def process_ex
+ window_size = Pry.config.default_window_size || 5
+ ex = _pry_.last_exception
+
+ raise CommandError, "No exception found." unless ex
+
+ if opts[:ex].nil?
+ bt_index = ex.bt_index
+ ex.inc_bt_index
+ else
+ bt_index = opts[:ex]
+ ex.bt_index = bt_index
+ ex.inc_bt_index
+ end
+
+ ex_file, ex_line = ex.bt_source_location_for(bt_index)
+
+ raise CommandError, "The given backtrace level is out of bounds." unless ex_file
+
+ if RbxPath.is_core_path?(ex_file)
+ ex_file = RbxPath.convert_path_to_full(ex_file)
+ end
+
+ set_file_and_dir_locals(ex_file)
+
+ start_line = ex_line - window_size
+ start_line = 1 if start_line < 1
+ end_line = ex_line + window_size
+
+ header = unindent <<-HEADER
+ #{text.bold 'Exception:'} #{ex.class}: #{ex.message}
+ --
+ #{text.bold('From:')} #{ex_file} @ line #{ex_line} @ #{text.bold("level: #{bt_index}")} of backtrace (of #{ex.backtrace.size - 1}).
+
+ HEADER
+
+ code = yield(Pry::Code.from_file(ex_file).
+ between(start_line, end_line).
+ with_marker(ex_line))
+
+ "#{header}#{code}"
+ end
+
+ def process_in
+ normalized_range = absolute_index_range(opts[:i], _pry_.input_array.length)
+ input_items = _pry_.input_array[normalized_range] || []
+
+ zipped_items = normalized_range.zip(input_items).reject { |_, s| s.nil? || s == "" }
+
+ unless zipped_items.length > 0
+ raise CommandError, "No expressions found."
+ end
+
+ if zipped_items.length > 1
+ contents = ""
+ zipped_items.each do |i, s|
+ contents << "#{text.bold(i.to_s)}:\n"
+ contents << yield(Pry::Code(s).with_indentation(2)).to_s
+ end
+ else
+ contents = yield(Pry::Code(zipped_items.first.last))
+ end
+
+ contents
+ end
+
+ def process_file
+ file_name = args.shift
+
+ unless file_name
+ raise CommandError, "Must provide a filename, --in, or --ex."
+ end
+
+ file_name, line_num = file_name.split(':')
+ file_name = File.expand_path(file_name)
+ set_file_and_dir_locals(file_name)
+
+ code = yield(Pry::Code.from_file(file_name))
+
+ code.code_type = opts[:type] || detect_code_type_from_file(file_name)
+ if line_num
+ code = code.around(line_num.to_i,
+ Pry.config.default_window_size || 7)
+ end
+
+ code
+ end
+
+ def detect_code_type_from_file(file_name)
+ name, ext = File.basename(file_name).split('.', 2)
+
+ if ext
+ case ext
+ when "py"
+ :python
+ when "rb", "gemspec", "rakefile", "ru"
+ :ruby
+ when "js"
+ return :javascript
+ when "yml", "prytheme"
+ :yaml
+ when "groovy"
+ :groovy
+ when "c"
+ :c
+ when "cpp"
+ :cpp
+ when "java"
+ :java
+ else
+ :text
+ end
+ else
+ case name
+ when "Rakefile", "Gemfile"
+ :ruby
+ else
+ :text
+ end
+ end
+ end
+ end
+end
View
125 lib/pry/default_commands/cd.rb
@@ -1,81 +1,76 @@
class Pry
- module DefaultCommands
- Cd = Pry::CommandSet.new do
- create_command "cd" do
- group "Context"
- description "Move into a new context (object or scope)."
+ Pry::Commands.create_command "cd" do
+ group "Context"
+ description "Move into a new context (object or scope)."
- banner <<-BANNER
- Usage: cd [OPTIONS] [--help]
+ banner <<-BANNER
+ Usage: cd [OPTIONS] [--help]
- Move into new context (object or scope). As in unix shells use
- `cd ..` to go back, `cd /` to return to Pry top-level and `cd -`
- to toggle between last two scopes).
- Complex syntax (e.g `cd ../@x/y`) also supported.
+ Move into new context (object or scope). As in unix shells use
+ `cd ..` to go back, `cd /` to return to Pry top-level and `cd -`
+ to toggle between last two scopes).
+ Complex syntax (e.g `cd ../@x/y`) also supported.
- e.g: `cd @x`
- e.g: `cd ..`
- e.g: `cd /`
- e.g: `cd -`
+ e.g: `cd @x`
+ e.g: `cd ..`
+ e.g: `cd /`
+ e.g: `cd -`
- https://github.com/pry/pry/wiki/State-navigation#wiki-Changing_scope
- BANNER
+ https://github.com/pry/pry/wiki/State-navigation#wiki-Changing_scope
+ BANNER
- def process
- # Extract command arguments. Delete blank arguments like " ", but
- # don't delete empty strings like "".
- path = arg_string.split(/\//).delete_if { |a| a =~ /\A\s+\z/ }
- stack = _pry_.binding_stack.dup
- old_stack = state.old_stack || []
+ def process
+ # Extract command arguments. Delete blank arguments like " ", but
+ # don't delete empty strings like "".
+ path = arg_string.split(/\//).delete_if { |a| a =~ /\A\s+\z/ }
+ stack = _pry_.binding_stack.dup
+ old_stack = state.old_stack || []
- # Special case when we only get a single "/", return to root.
- if path.empty?
- state.old_stack = stack.dup unless old_stack.empty?
- stack = [stack.first]
- end
-
- path.each_with_index do |context, i|
- begin
- case context.chomp
- when ""
- state.old_stack = stack.dup
- stack = [stack.first]
- when "::"
- state.old_stack = stack.dup
- stack.push(TOPLEVEL_BINDING)
- when "."
- next
- when ".."
- unless stack.size == 1
- # Don't rewrite old_stack if we're in complex expression
- # (e.g.: `cd 1/2/3/../4).
- state.old_stack = stack.dup if path.first == ".."
- stack.pop
- end
- when "-"
- unless old_stack.empty?
- # Interchange current stack and old stack with each other.
- stack, state.old_stack = state.old_stack, stack
- end
- else
- state.old_stack = stack.dup if i == 0
- stack.push(Pry.binding_for(stack.last.eval(context)))
- end
-
- rescue RescuableException => e
- # Restore old stack to its initial values.
- state.old_stack = old_stack
+ # Special case when we only get a single "/", return to root.
+ if path.empty?
+ state.old_stack = stack.dup unless old_stack.empty?
+ stack = [stack.first]
+ end
- output.puts "Bad object path: #{arg_string.chomp}. Failed trying to resolve: #{context}"
- output.puts e.inspect
- return
+ path.each_with_index do |context, i|
+ begin
+ case context.chomp
+ when ""
+ state.old_stack = stack.dup
+ stack = [stack.first]
+ when "::"
+ state.old_stack = stack.dup
+ stack.push(TOPLEVEL_BINDING)
+ when "."
+ next
+ when ".."
+ unless stack.size == 1
+ # Don't rewrite old_stack if we're in complex expression
+ # (e.g.: `cd 1/2/3/../4).
+ state.old_stack = stack.dup if path.first == ".."
+ stack.pop
+ end
+ when "-"
+ unless old_stack.empty?
+ # Interchange current stack and old stack with each other.
+ stack, state.old_stack = state.old_stack, stack
end
+ else
+ state.old_stack = stack.dup if i == 0
+ stack.push(Pry.binding_for(stack.last.eval(context)))
end
- _pry_.binding_stack = stack
- end
+ rescue RescuableException => e
+ # Restore old stack to its initial values.
+ state.old_stack = old_stack
+ output.puts "Bad object path: #{arg_string.chomp}. Failed trying to resolve: #{context}"
+ output.puts e.inspect
+ return
+ end
end
+
+ _pry_.binding_stack = stack
end
end
end
View
62 lib/pry/default_commands/commands.rb
@@ -1,62 +0,0 @@
-class Pry
- module DefaultCommands
- Commands = Pry::CommandSet.new do
- create_command "import-set", "Import a command set" do
- group "Commands"
- def process(command_set_name)
- raise CommandError, "Provide a command set name" if command_set.nil?
-
- set = target.eval(arg_string)
- _pry_.commands.import set
- end
- end
-
- create_command "install-command", "Install a disabled command." do |name|
- group 'Commands'
-
- banner <<-BANNER
- Usage: install-command COMMAND
-
- Installs the gems necessary to run the given COMMAND. You will generally not
- need to run this unless told to by an error message.
- BANNER
-
- def process(name)
- require 'rubygems/dependency_installer' unless defined? Gem::DependencyInstaller
- command = find_command(name)
-
- if command_dependencies_met?(command.options)
- output.puts "Dependencies for #{command.name} are met. Nothing to do."
- return
- end
-
- output.puts "Attempting to install `#{name}` command..."
- gems_to_install = Array(command.options[:requires_gem])
-
- gems_to_install.each do |g|
- next if gem_installed?(g)
- output.puts "Installing `#{g}` gem..."
-
- begin
- Gem::DependencyInstaller.new.install(g)
- rescue Gem::GemNotFoundException
- raise CommandError, "Required Gem: `#{g}` not found. Aborting command installation."
- end
- end
-
- Gem.refresh
- gems_to_install.each do |g|
- begin
- require g
- rescue LoadError
- raise CommandError, "Required Gem: `#{g}` installed but not found?!. Aborting command installation."
- end
- end
-
- output.puts "Installation of `#{name}` successful! Type `help #{name}` for information"
- end
- end
- end
- end
-end
-
View
98 lib/pry/default_commands/context.rb
@@ -1,98 +0,0 @@
-require "pry/default_commands/ls"
-require "pry/default_commands/cd"
-require "pry/default_commands/find_method"
-require "pry/default_commands/whereami"
-
-class Pry
- module DefaultCommands
-
- Context = Pry::CommandSet.new do
- import Ls
- import Cd
- import FindMethod
- import Whereami
-
- create_command "pry-backtrace", "Show the backtrace for the Pry session." do
- banner <<-BANNER
- Usage: pry-backtrace [OPTIONS] [--help]
-
- Show the backtrace for the position in the code where Pry was started. This can be used to
- infer the behavior of the program immediately before it entered Pry, just like the backtrace
- property of an exception.
-
- (NOTE: if you are looking for the backtrace of the most recent exception raised,
- just type: `_ex_.backtrace` instead, see https://github.com/pry/pry/wiki/Special-Locals)
-
- e.g: pry-backtrace
- BANNER
-
- def process
- output.puts "\n#{text.bold('Backtrace:')}\n--\n"
- stagger_output _pry_.backtrace.join("\n")
- end
- end
-
- command "reset", "Reset the REPL to a clean state." do
- output.puts "Pry reset."
- exec "pry"
- end
-
- create_command(/wtf([?!]*)/, "Show the backtrace of the most recent exception") do
- options :listing => 'wtf?'
-
- banner <<-BANNER
- Show's a few lines of the backtrace of the most recent exception (also available
- as _ex_.backtrace).
-
- If you want to see more lines, add more question marks or exclamation marks:
-
- e.g.
- pry(main)> wtf?
- pry(main)> wtf?!???!?!?
-
- To see the entire backtrace, pass the -v/--verbose flag:
-
- e.g.
- pry(main)> wtf -v
- BANNER
-
- def options(opt)
- opt.on(:v, :verbose, "Show the full backtrace.")
- end
-
- def process
- raise Pry::CommandError, "No most-recent exception" unless _pry_.last_exception
-
- output.puts "#{text.bold('Exception:')} #{_pry_.last_exception.class}: #{_pry_.last_exception}\n--"
- if opts.verbose?
- output.puts Code.new(_pry_.last_exception.backtrace, 0, :text).with_line_numbers.to_s
- else
- output.puts Code.new(_pry_.last_exception.backtrace.first([captures[0].size, 0.5].max * 10), 0, :text).with_line_numbers.to_s
- end
- end
- end
-
- # N.B. using a regular expresion here so that "raise-up 'foo'" does the right thing.
- create_command(/raise-up(!?\b.*)/, :listing => 'raise-up') do
- description "Raise an exception out of the current pry instance."
- banner <<-BANNER
- Raise up, like exit, allows you to quit pry. Instead of returning a value however, it raises an exception.
- If you don't provide the exception to be raised, it will use the most recent exception (in pry _ex_).
-
- e.g. `raise-up "get-me-out-of-here"` is equivalent to:
- `raise "get-me-out-of-here"
- raise-up`
-
- When called as raise-up! (with an exclamation mark), this command raises the exception through
- any nested prys you have created by "cd"ing into objects.
- BANNER
-
- def process
- return stagger_output help if captures[0] =~ /(-h|--help)\b/
- # Handle 'raise-up', 'raise-up "foo"', 'raise-up RuntimeError, 'farble' in a rubyesque manner
- target.eval("_pry_.raise_up#{captures[0]}")
- end
- end
- end
- end
-end
View
160 lib/pry/default_commands/easter_eggs.rb
@@ -1,95 +1,91 @@
class Pry
- module DefaultCommands
-
- EasterEggs = Pry::CommandSet.new do
-
- command "nyan-cat", "", :requires_gem => ["nyancat"] do
- run ".nyancat"
- end
+ Pry::Commands.instance_eval do
+ command "nyan-cat", "", :requires_gem => ["nyancat"] do
+ run ".nyancat"
+ end
- command(/!s\/(.*?)\/(.*?)/, "") do |source, dest|
- eval_string.gsub!(/#{source}/) { dest }
- run "show-input"
- end
+ command(/!s\/(.*?)\/(.*?)/, "") do |source, dest|
+ eval_string.gsub!(/#{source}/) { dest }
+ run "show-input"
+ end
- command "get-naked", "" do
- text = %{
---
-We dont have to take our clothes off to have a good time.
-We could dance & party all night And drink some cherry wine.
--- Jermaine Stewart }
- output.puts text
- text
- end
+ command "get-naked", "" do
+ text = %{
+ --
+ We dont have to take our clothes off to have a good time.
+ We could dance & party all night And drink some cherry wine.
+ -- Jermaine Stewart }
+ output.puts text
+ text
+ end
- command "east-coker", "" do
- text = %{
---
-Now the light falls
-Across the open field, leaving the deep lane
-Shuttered with branches, dark in the afternoon,
-Where you lean against a bank while a van passes,
-And the deep lane insists on the direction
-Into the village, in the electric heat
-Hypnotised. In a warm haze the sultry light
-Is absorbed, not refracted, by grey stone.
-The dahlias sleep in the empty silence.
-Wait for the early owl.
--- T.S Eliot
- }
- output.puts text
- text
- end
+ command "east-coker", "" do
+ text = %{
+ --
+ Now the light falls
+ Across the open field, leaving the deep lane
+ Shuttered with branches, dark in the afternoon,
+ Where you lean against a bank while a van passes,
+ And the deep lane insists on the direction
+ Into the village, in the electric heat
+ Hypnotised. In a warm haze the sultry light
+ Is absorbed, not refracted, by grey stone.
+ The dahlias sleep in the empty silence.
+ Wait for the early owl.
+ -- T.S Eliot
+ }
+ output.puts text
+ text
+ end
- command "cohen-poem", "" do
- text = %{
---
-When this American woman,
-whose thighs are bound in casual red cloth,
-comes thundering past my sitting place
-like a forest-burning Mongol tribe,
-the city is ravished
-and brittle buildings of a hundred years
-splash into the street;
-and my eyes are burnt
-for the embroidered Chinese girls,
-already old,
-and so small between the thin pines
-on these enormous landscapes,
-that if you turn your head
-they are lost for hours.
- -- Leonard Cohen
- }
- output.puts text
- text
-end
+ command "cohen-poem", "" do
+ text = %{
+ --
+ When this American woman,
+ whose thighs are bound in casual red cloth,
+ comes thundering past my sitting place
+ like a forest-burning Mongol tribe,
+ the city is ravished
+ and brittle buildings of a hundred years
+ splash into the street;
+ and my eyes are burnt
+ for the embroidered Chinese girls,
+ already old,
+ and so small between the thin pines
+ on these enormous landscapes,
+ that if you turn your head
+ they are lost for hours.
+ -- Leonard Cohen
+ }
+ output.puts text
+ text
+ end
- command "test-ansi", "" do
- prev_color = Pry.color
- Pry.color = true
+ command "test-ansi", "" do
+ prev_color = Pry.color
+ Pry.color = true
- picture = unindent <<-'EOS'.gsub(/[[:alpha:]!]/) { |s| text.red(s) }
- ____ _______________________
- / \ | A W G |
- / O O \ | N I O N ! |
- | | | S S R I ! |
- \ \__/ / __| I K ! |
- \____/ \________________________|
- EOS
+ picture = unindent <<-'EOS'.gsub(/[[:alpha:]!]/) { |s| text.red(s) }
+ ____ _______________________
+ / \ | A W G |
+ / O O \ | N I O N ! |
+ | | | S S R I ! |
+ \ \__/ / __| I K ! |
+ \____/ \________________________|
+ EOS
- if windows_ansi?
- move_up = proc { |n| "\e[#{n}F" }
- else
- move_up = proc { |n| "\e[#{n}A\e[0G" }
- end
+ if windows_ansi?
+ move_up = proc { |n| "\e[#{n}F" }
+ else
+ move_up = proc { |n| "\e[#{n}A\e[0G" }
+ end
- output.puts "\n" * 6
- output.puts picture.lines.map(&:chomp).reverse.join(move_up[1])
- output.puts "\n" * 6
- output.puts "** ENV['TERM'] is #{ENV['TERM']} **\n\n"
+ output.puts "\n" * 6
+ output.puts picture.lines.map(&:chomp).reverse.join(move_up[1])
+ output.puts "\n" * 6
+ output.puts "** ENV['TERM'] is #{ENV['TERM']} **\n\n"
- Pry.color = prev_color
- end
+ Pry.color = prev_color
end
end
end
View
137 lib/pry/default_commands/edit.rb
@@ -0,0 +1,137 @@
+class Pry
+ Pry::Commands.create_command "edit" do
+ description "Invoke the default editor on a file."
+
+ banner <<-BANNER
+ Usage: edit [--no-reload|--reload] [--line LINE] [--temp|--ex|FILE[:LINE]|--in N]
+
+ Open a text editor. When no FILE is given, edits the pry input buffer.
+ Ensure Pry.config.editor is set to your editor of choice.
+
+ e.g: `edit sample.rb`
+ e.g: `edit sample.rb --line 105`
+ e.g: `edit --ex`
+
+ https://github.com/pry/pry/wiki/Editor-integration#wiki-Edit_command
+ BANNER
+
+ def options(opt)
+ opt.on :e, :ex, "Open the file that raised the most recent exception (_ex_.file)", :optional_argument => true, :as => Integer
+ opt.on :i, :in, "Open a temporary file containing the Nth input expression. N may be a range.", :optional_argument => true, :as => Range, :default => -1..-1
+ opt.on :t, :temp, "Open an empty temporary file"
+ opt.on :l, :line, "Jump to this line in the opened file", :argument => true, :as => Integer
+ opt.on :n, :"no-reload", "Don't automatically reload the edited code"
+ opt.on :c, :"current", "Open the current __FILE__ and at __LINE__ (as returned by `whereami`)."
+ opt.on :r, :reload, "Reload the edited code immediately (default for ruby files)"
+ end
+
+ def process
+ if [opts.present?(:ex), opts.present?(:temp), opts.present?(:in), !args.empty?].count(true) > 1
+ raise CommandError, "Only one of --ex, --temp, --in and FILE may be specified."
+ end
+
+ if !opts.present?(:ex) && !opts.present?(:current) && args.empty?
+ # edit of local code, eval'd within pry.
+ process_local_edit
+ else
+ # edit of remote code, eval'd at top-level
+ process_remote_edit
+ end
+ end
+
+ def process_i
+ case opts[:i]
+ when Range
+ (_pry_.input_array[opts[:i]] || []).join
+ when Fixnum
+ _pry_.input_array[opts[:i]] || ""
+ else
+ return output.puts "Not a valid range: #{opts[:i]}"
+ end
+ end
+
+ def process_local_edit
+ content = case
+ when opts.present?(:temp)
+ ""
+ when opts.present?(:in)
+ process_i
+ when eval_string.strip != ""
+ eval_string
+ else
+ _pry_.input_array.reverse_each.find{ |x| x && x.strip != "" } || ""
+ end
+
+ line = content.lines.count
+
+ temp_file do |f|
+ f.puts(content)
+ f.flush
+ reload = !opts.present?(:'no-reload') && !Pry.config.disable_auto_reload
+ f.close(false)
+ invoke_editor(f.path, line, reload)
+ if reload
+ silence_warnings do
+ eval_string.replace(File.read(f.path))
+ end
+ end
+ end
+ end
+
+ def process_remote_edit
+ if opts.present?(:ex)
+ if _pry_.last_exception.nil?
+ raise CommandError, "No exception found."
+ end
+
+ ex = _pry_.last_exception
+ bt_index = opts[:ex].to_i
+
+ ex_file, ex_line = ex.bt_source_location_for(bt_index)
+ if ex_file && RbxPath.is_core_path?(ex_file)
+ file_name = RbxPath.convert_path_to_full(ex_file)
+ else
+ file_name = ex_file
+ end
+
+ line = ex_line
+
+ if file_name.nil?
+ raise CommandError, "Exception has no associated file."
+ end
+
+ if Pry.eval_path == file_name
+ raise CommandError, "Cannot edit exceptions raised in REPL."
+ end
+ elsif opts.present?(:current)
+ file_name = target.eval("__FILE__")
+ line = target.eval("__LINE__")
+ else
+
+ # break up into file:line
+ file_name = File.expand_path(args.first)
+ line = file_name.sub!(/:(\d+)$/, "") ? $1.to_i : 1
+ end
+
+ if not_a_real_file?(file_name)
+ raise CommandError, "#{file_name} is not a valid file name, cannot edit!"
+ end
+
+ line = opts[:l].to_i if opts.present?(:line)
+
+ reload = opts.present?(:reload) || ((opts.present?(:ex) || file_name.end_with?(".rb")) && !opts.present?(:'no-reload')) && !Pry.config.disable_auto_reload
+
+ # Sanitize blanks.
+ sanitized_file_name = Shellwords.escape(file_name)
+
+ invoke_editor(sanitized_file_name, line, reload)
+ set_file_and_dir_locals(sanitized_file_name)
+
+ if reload
+ silence_warnings do
+ TOPLEVEL_BINDING.eval(File.read(file_name), file_name)
+ end
+ end
+ end
+ end
+end
View
179 lib/pry/default_commands/edit_method.rb
@@ -0,0 +1,179 @@
+class Pry
+ Pry::Commands.create_command "edit-method" do
+ description "Edit the source code for a method."
+
+ banner <<-BANNER
+ Usage: edit-method [OPTIONS] [METH]
+
+ Edit the method METH in an editor.
+ Ensure Pry.config.editor is set to your editor of choice.
+
+ e.g: `edit-method hello_method`
+ e.g: `edit-method Pry#rep`
+ e.g: `edit-method`
+
+ https://github.com/pry/pry/wiki/Editor-integration#wiki-Edit_method
+ BANNER
+
+ command_options :shellwords => false
+
+ def options(opt)
+ method_options(opt)
+ opt.on :n, "no-reload", "Do not automatically reload the method's file after editing."
+ opt.on "no-jump", "Do not fast forward editor to first line of method."
+ opt.on :p, :patch, "Instead of editing the method's file, try to edit in a tempfile and apply as a monkey patch."
+ end
+
+ def process
+ if !Pry.config.editor
+ raise CommandError, "No editor set!\nEnsure that #{text.bold("Pry.config.editor")} is set to your editor of choice."
+ end
+
+ begin
+ @method = method_object
+ rescue MethodNotFound => err
+ end
+
+ if opts.present?(:patch) || (@method && @method.dynamically_defined?)
+ if err
+ raise err # can't patch a non-method
+ end
+
+ process_patch
+ else
+ if err && !File.exist?(target.eval('__FILE__'))
+ raise err # can't edit a non-file
+ end
+
+ process_file
+ end
+ end
+
+ def process_patch
+ lines = @method.source.lines.to_a
+
+ lines[0] = definition_line_for_owner(lines[0])
+
+ temp_file do |f|
+ f.puts lines
+ f.flush
+ f.close(false)
+ invoke_editor(f.path, 0, true)
+
+ source = wrap_for_nesting(wrap_for_owner(File.read(f.path)))
+
+ if @method.alias?
+ with_method_transaction(original_name, @method.owner) do
+ Pry.new(:input => StringIO.new(source)).rep(TOPLEVEL_BINDING)
+ Pry.binding_for(@method.owner).eval("alias #{@method.name} #{original_name}")
+ end
+ else
+ Pry.new(:input => StringIO.new(source)).rep(TOPLEVEL_BINDING)
+ end
+ end
+ end
+
+ def process_file
+ file, line = extract_file_and_line
+
+ reload = !opts.present?(:'no-reload') && !Pry.config.disable_auto_reload
+ invoke_editor(file, opts["no-jump"] ? 0 : line, reload)
+ silence_warnings do
+ load file if reload
+ end
+ end
+
+ protected
+ def extract_file_and_line
+ if @method
+ if @method.source_type == :c
+ raise CommandError, "Can't edit a C method."
+ else
+ [@method.source_file, @method.source_line]
+ end
+ else
+ [target.eval('__FILE__'), target.eval('__LINE__')]
+ end
+ end
+
+ # Run some code ensuring that at the end target#meth_name will not have changed.
+ #
+ # When we're redefining aliased methods we will overwrite the method at the
+ # unaliased name (so that super continues to work). By wrapping that code in a
+ # transation we make that not happen, which means that alias_method_chains, etc.
+ # continue to work.
+ #
+ # @param [String] meth_name The method name before aliasing
+ # @param [Module] target The owner of the method
+ def with_method_transaction(meth_name, target)
+ target = Pry.binding_for(target)
+ temp_name = "__pry_#{meth_name}__"
+
+ target.eval("alias #{temp_name} #{meth_name}")
+ yield
+ target.eval("alias #{meth_name} #{temp_name}")
+ ensure
+ target.eval("undef #{temp_name}") rescue nil
+ end
+
+ # The original name of the method, if it's not present raise an error telling
+ # the user why we don't work.
+ #
+ def original_name
+ @method.original_name or raise CommandError, "Pry can only patch methods created with the `def` keyword."
+ end
+
+ # Update the definition line so that it can be eval'd directly on the Method's
+ # owner instead of from the original context.
+ #
+ # In particular this takes `def self.foo` and turns it into `def foo` so that we
+ # don't end up creating the method on the singleton class of the singleton class
+ # by accident.
+ #
+ # This is necessarily done by String manipulation because we can't find out what
+ # syntax is needed for the argument list by ruby-level introspection.
+ #
+ # @param String The original definition line. e.g. def self.foo(bar, baz=1)
+ # @return String The new definition line. e.g. def foo(bar, baz=1)
+ def definition_line_for_owner(line)
+ if line =~ /^def (?:.*?\.)?#{Regexp.escape(original_name)}(?=[\(\s;]|$)/
+ "def #{original_name}#{$'}"
+ else
+ raise CommandError, "Could not find original `def #{original_name}` line to patch."
+ end
+ end
+
+ # Update the source code so that when it has the right owner when eval'd.
+ #
+ # This (combined with definition_line_for_owner) is backup for the case that
+ # wrap_for_nesting fails, to ensure that the method will stil be defined in
+ # the correct place.
+ #
+ # @param [String] source The source to wrap
+ # @return [String]
+ def wrap_for_owner(source)
+ Thread.current[:__pry_owner__] = @method.owner
+ source = "Thread.current[:__pry_owner__].class_eval do\n#{source}\nend"
+ end
+
+ # Update the new source code to have the correct Module.nesting.
+ #
+ # This method uses syntactic analysis of the original source file to determine
+ # the new nesting, so that we can tell the difference between:
+ #
+ # class A; def self.b; end; end
+ # class << A; def b; end; end
+ #
+ # The resulting code should be evaluated in the TOPLEVEL_BINDING.
+ #
+ # @param [String] source The source to wrap.
+ # @return [String]
+ def wrap_for_nesting(source)
+ nesting = Pry::Code.from_file(@method.source_file).nesting_at(@method.source_line)
+
+ (nesting + [source] + nesting.map{ "end" } + [""]).join("\n")
+ rescue Pry::Indent::UnparseableNestingError => e
+ source
+ end
+ end
+end
View
463 lib/pry/default_commands/editing.rb
@@ -1,463 +0,0 @@
-require 'tempfile'
-require 'shellwords'
-require 'pry/default_commands/hist'
-
-class Pry
- module DefaultCommands
-
- Editing = Pry::CommandSet.new do
- import Hist
-
- 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
- def process
- output.puts "Input buffer cleared!"
- eval_string.replace("")
- end
- end
-
- create_command "show-input", "Show the contents of the input buffer for the current multi-line expression." do
- def process
- output.puts Code.new(eval_string).with_line_numbers
- end
- end
-
- create_command "edit" do
- description "Invoke the default editor on a file."
-
- banner <<-BANNER
- Usage: edit [--no-reload|--reload] [--line LINE] [--temp|--ex|FILE[:LINE]|--in N]
-
- Open a text editor. When no FILE is given, edits the pry input buffer.
- Ensure Pry.config.editor is set to your editor of choice.
-
- e.g: `edit sample.rb`
- e.g: `edit sample.rb --line 105`
- e.g: `edit --ex`
-
- https://github.com/pry/pry/wiki/Editor-integration#wiki-Edit_command
- BANNER
-
- def options(opt)
- opt.on :e, :ex, "Open the file that raised the most recent exception (_ex_.file)", :optional_argument => true, :as => Integer
- opt.on :i, :in, "Open a temporary file containing the Nth input expression. N may be a range.", :optional_argument => true, :as => Range, :default => -1..-1
- opt.on :t, :temp, "Open an empty temporary file"
- opt.on :l, :line, "Jump to this line in the opened file", :argument => true, :as => Integer
- opt.on :n, :"no-reload", "Don't automatically reload the edited code"
- opt.on :c, :"current", "Open the current __FILE__ and at __LINE__ (as returned by `whereami`)."
- opt.on :r, :reload, "Reload the edited code immediately (default for ruby files)"
- end
-
- def process
- if [opts.present?(:ex), opts.present?(:temp), opts.present?(:in), !args.empty?].count(true) > 1
- raise CommandError, "Only one of --ex, --temp, --in and FILE may be specified."
- end
-
- if !opts.present?(:ex) && !opts.present?(:current) && args.empty?
- # edit of local code, eval'd within pry.
- process_local_edit
- else
- # edit of remote code, eval'd at top-level
- process_remote_edit
- end
- end
-
- def process_i
- case opts[:i]
- when Range
- (_pry_.input_array[opts[:i]] || []).join
- when Fixnum
- _pry_.input_array[opts[:i]] || ""
- else
- return output.puts "Not a valid range: #{opts[:i]}"
- end
- end
-
- def process_local_edit
- content = case
- when opts.present?(:temp)
- ""
- when opts.present?(:in)
- process_i
- when eval_string.strip != ""
- eval_string
- else
- _pry_.input_array.reverse_each.find{ |x| x && x.strip != "" } || ""
- end
-
- line = content.lines.count
-
- temp_file do |f|
- f.puts(content)
- f.flush
- reload = !opts.present?(:'no-reload') && !Pry.config.disable_auto_reload
- f.close(false)
- invoke_editor(f.path, line, reload)
- if reload
- silence_warnings do
- eval_string.replace(File.read(f.path))
- end
- end
- end
- end
-
- def process_remote_edit
- if opts.present?(:ex)
- if _pry_.last_exception.nil?
- raise CommandError, "No exception found."
- end
-
- ex = _pry_.last_exception
- bt_index = opts[:ex].to_i
-
- ex_file, ex_line = ex.bt_source_location_for(bt_index)
- if ex_file && RbxPath.is_core_path?(ex_file)
- file_name = RbxPath.convert_path_to_full(ex_file)
- else
- file_name = ex_file
- end
-
- line = ex_line
-
- if file_name.nil?
- raise CommandError, "Exception has no associated file."
- end
-
- if Pry.eval_path == file_name
- raise CommandError, "Cannot edit exceptions raised in REPL."
- end
- elsif opts.present?(:current)
- file_name = target.eval("__FILE__")
- line = target.eval("__LINE__")
- else
-
- # break up into file:line
- file_name = File.expand_path(args.first)
- line = file_name.sub!(/:(\d+)$/, "") ? $1.to_i : 1
- end
-
- if not_a_real_file?(file_name)
- raise CommandError, "#{file_name} is not a valid file name, cannot edit!"
- end
-
- line = opts[:l].to_i if opts.present?(:line)
-
- reload = opts.present?(:reload) || ((opts.present?(:ex) || file_name.end_with?(".rb")) && !opts.present?(:'no-reload')) && !Pry.config.disable_auto_reload
-
- # Sanitize blanks.
- sanitized_file_name = Shellwords.escape(file_name)
-
- invoke_editor(sanitized_file_name, line, reload)
- set_file_and_dir_locals(sanitized_file_name)
-
- if reload
- silence_warnings do
- TOPLEVEL_BINDING.eval(File.read(file_name), file_name)
- end
- end
- end
- end
-
- create_command "edit-method" do
- description "Edit the source code for a method."
-
- banner <<-BANNER
- Usage: edit-method [OPTIONS] [METH]
-
- Edit the method METH in an editor.
- Ensure Pry.config.editor is set to your editor of choice.
-
- e.g: `edit-method hello_method`
- e.g: `edit-method Pry#rep`
- e.g: `edit-method`
-
- https://github.com/pry/pry/wiki/Editor-integration#wiki-Edit_method
- BANNER
-
- command_options :shellwords => false
-
- def options(opt)
- method_options(opt)
- opt.on :n, "no-reload", "Do not automatically reload the method's file after editing."
- opt.on "no-jump", "Do not fast forward editor to first line of method."
- opt.on :p, :patch, "Instead of editing the method's file, try to edit in a tempfile and apply as a monkey patch."
- end
-
- def process
- if !Pry.config.editor
- raise CommandError, "No editor set!\nEnsure that #{text.bold("Pry.config.editor")} is set to your editor of choice."
- end
-
- begin
- @method = method_object
- rescue MethodNotFound => err
- end
-
- if opts.present?(:patch) || (@method && @method.dynamically_defined?)
- if err
- raise err # can't patch a non-method
- end
-
- process_patch
- else
- if err && !File.exist?(target.eval('__FILE__'))
- raise err # can't edit a non-file
- end
-
- process_file
- end
- end
-
- def process_patch
- lines = @method.source.lines.to_a
-
- lines[0] = definition_line_for_owner(lines[0])
-
- temp_file do |f|
- f.puts lines
- f.flush
- f.close(false)
- invoke_editor(f.path, 0, true)
-
- source = wrap_for_nesting(wrap_for_owner(File.read(f.path)))
-
- if @method.alias?
- with_method_transaction(original_name, @method.owner) do
- Pry.new(:input => StringIO.new(source)).rep(TOPLEVEL_BINDING)
- Pry.binding_for(@method.owner).eval("alias #{@method.name} #{original_name}")
- end
- else
- Pry.new(:input => StringIO.new(source)).rep(TOPLEVEL_BINDING)
- end
- end
- end
-
- def process_file
- file, line = extract_file_and_line
-
- reload = !opts.present?(:'no-reload') && !Pry.config.disable_auto_reload
- invoke_editor(file, opts["no-jump"] ? 0 : line, reload)
- silence_warnings do
- load file if reload
- end
- end
-
- protected
- def extract_file_and_line
- if @method
- if @method.source_type == :c
- raise CommandError, "Can't edit a C method."
- else
- [@method.source_file, @method.source_line]
- end
- else
- [target.eval('__FILE__'), target.eval('__LINE__')]
- end
- end
-
- # Run some code ensuring that at the end target#meth_name will not have changed.
- #
- # When we're redefining aliased methods we will overwrite the method at the
- # unaliased name (so that super continues to work). By wrapping that code in a
- # transation we make that not happen, which means that alias_method_chains, etc.
- # continue to work.
- #
- # @param [String] meth_name The method name before aliasing
- # @param [Module] target The owner of the method
- def with_method_transaction(meth_name, target)
- target = Pry.binding_for(target)
- temp_name = "__pry_#{meth_name}__"
-
- target.eval("alias #{temp_name} #{meth_name}")
- yield
- target.eval("alias #{meth_name} #{temp_name}")
- ensure
- target.eval("undef #{temp_name}") rescue nil
- end
-
- # The original name of the method, if it's not present raise an error telling
- # the user why we don't work.
- #
- def original_name
- @method.original_name or raise CommandError, "Pry can only patch methods created with the `def` keyword."
- end
-
- # Update the definition line so that it can be eval'd directly on the Method's
- # owner instead of from the original context.
- #
- # In particular this takes `def self.foo` and turns it into `def foo` so that we
- # don't end up creating the method on the singleton class of the singleton class
- # by accident.
- #
- # This is necessarily done by String manipulation because we can't find out what
- # syntax is needed for the argument list by ruby-level introspection.
- #
- # @param String The original definition line. e.g. def self.foo(bar, baz=1)
- # @return String The new definition line. e.g. def foo(bar, baz=1)
- def definition_line_for_owner(line)
- if line =~ /^def (?:.*?\.)?#{Regexp.escape(original_name)}(?=[\(\s;]|$)/
- "def #{original_name}#{$'}"
- else
- raise CommandError, "Could not find original `def #{original_name}` line to patch."
- end
- end
-
- # Update the source code so that when it has the right owner when eval'd.
- #
- # This (combined with definition_line_for_owner) is backup for the case that
- # wrap_for_nesting fails, to ensure that the method will stil be defined in
- # the correct place.
- #
- # @param [String] source The source to wrap
- # @return [String]
- def wrap_for_owner(source)
- Thread.current[:__pry_owner__] = @method.owner
- source = "Thread.current[:__pry_owner__].class_eval do\n#{source}\nend"
- end
-
- # Update the new source code to have the correct Module.nesting.
- #
- # This method uses syntactic analysis of the original source file to determine
- # the new nesting, so that we can tell the difference between:
- #
- # class A; def self.b; end; end
- # class << A; def b; end; end
- #
- # The resulting code should be evaluated in the TOPLEVEL_BINDING.
- #
- # @param [String] source The source to wrap.
- # @return [String]
- def wrap_for_nesting(source)
- nesting = Pry::Code.from_file(@method.source_file).nesting_at(@method.source_line)
-
- (nesting + [source] + nesting.map{ "end" } + [""]).join("\n")
- rescue Pry::Indent::UnparseableNestingError => e
- source
- end
- end
-
- create_command(/amend-line(?: (-?\d+)(?:\.\.(-?\d+))?)?/) do
- description "Amend a line of input in multi-line mode."
- command_options :interpolate => false, :listing => "amend-line"
-
- banner <<-'BANNER'
- Amend a line of input in multi-line mode. `amend-line N`, where the N in `amend-line N` represents line to replace.
-
- Can also specify a range of lines using `amend-line N..M` syntax. Passing '!' as replacement content deletes the line(s) instead.
- e.g amend-line 1 puts 'hello world! # replace line 1'
- e.g amend-line 1..4 ! # delete lines 1..4
- e.g amend-line 3 >puts 'goodbye' # insert before line 3
- e.g amend-line puts 'hello again' # no line number modifies immediately preceding line
- BANNER
-
- def process
- start_line_number, end_line_number, replacement_line = *args
-
- if eval_string.empty?
- raise CommandError, "No input to amend."
- end
-
- replacement_line = "" if !replacement_line
- input_array = eval_string.each_line.to_a
-
- end_line_number = start_line_number.to_i if !end_line_number
- 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
-
- # delete selected lines if replacement line is '!'
- if arg_string == "!"
- input_array.slice!(line_range)
- elsif arg_string.start_with?(">")
- insert_slot = Array(line_range).first
- input_array.insert(insert_slot, arg_string[1..-1] + "\n")
- else
- input_array[line_range] = arg_string + "\n"
- end
- eval_string.replace input_array.join
- run "show-input"
- end
- end
-
- create_command "play" do
- include Helpers::DocumentationHelpers
-
- description "Play back a string variable or a method or a file as input."
-
- banner <<-BANNER
- Usage: play [OPTIONS] [--help]
-
- The play command enables you to replay code from files and methods as
- if they were entered directly in the Pry REPL. Default action (no
- options) is to play the provided string variable
-
- e.g: `play -i 20 --lines 1..3`
- e.g: `play -m Pry#repl --lines 1..-1`
- e.g: `play -f Rakefile --lines 5`
-
- https://github.com/pry/pry/wiki/User-Input#wiki-Play
- BANNER
-
- attr_accessor :content
-
- def setup
- self.content = ""
- end
-
- def options(opt)
- opt.on :m, :method, "Play a method's source.", :argument => true do |meth_name|
- meth = get_method_or_raise(meth_name, target, {})
- self.content << meth.source
- end
- opt.on :d, :doc, "Play a method's documentation.", :argument => true do |meth_name|
- meth = get_method_or_raise(meth_name, target, {})
- text.no_color do
- self.content << process_comment_markup(meth.doc)
- end
- end
- opt.on :c, :command, "Play a command's source.", :argument => true do |command_name|
- command = find_command(command_name)
- block = Pry::Method.new(command.block)
- self.content << block.source
- end
- opt.on :f, :file, "Play a file.", :argument => true do |file|
- self.content << File.read(File.expand_path(file))
- end
- opt.on :l, :lines, "Only play a subset of lines.", :optional_argument => true, :as => Range, :default => 1..-1
- opt.on :i, :in, "Play entries from Pry's input expression history. Takes an index or range. Note this can only replay pure Ruby code, not Pry commands.", :optional_argument => true,
- :as => Range, :default => -5..-1 do |range|
- input_expressions = _pry_.input_array[range] || []
- Array(input_expressions).each { |v| self.content << v }
- end
- 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.'
- end
-
- def process
- perform_play
- run "show-input" unless Pry::Code.complete_expression?(eval_string)
- end
-
- def process_non_opt
- args.each do |arg|
- begin
- self.content << target.eval(arg)
- rescue Pry::RescuableException
- raise CommandError, "Problem when evaling #{arg}."
- end
- end
- end
-
- def perform_play
- process_non_opt
-
- if opts.present?(:lines)
- self.content = restrict_to_lines(self.content, opts[:l])
- end
-
- if opts.present?(:open)
- self.content = restrict_to_lines(self.content, 1..-2)
- end
-
- eval_string << self.content
- end
- end
- end
- end
-end
View
41 lib/pry/default_commands/exit.rb
@@ -0,0 +1,41 @@
+class Pry
+ Pry::Commands.create_command "exit" do
+ description "Pop the previous binding (does NOT exit program). Aliases: quit"
+
+ banner <<-BANNER
+ Usage: exit [OPTIONS] [--help]
+ Aliases: quit
+
+ It can be useful to exit a context with a user-provided value. For
+ instance an exit value can be used to determine program flow.
+
+ e.g: `exit "pry this"`
+ e.g: `exit`
+
+ https://github.com/pry/pry/wiki/State-navigation#wiki-Exit_with_value
+ BANNER
+
+ command_options(
+ :keep_retval => true
+ )
+
+ def process
+ if _pry_.binding_stack.one?
+ _pry_.run_command "exit-all #{arg_string}"
+ else
+ # otherwise just pop a binding and return user supplied value
+ process_pop_and_return
+ end
+ end
+
+ def process_pop_and_return
+ popped_object = _pry_.binding_stack.pop.eval('self')
+
+ # return a user-specified value if given otherwise return the object
+ return target.eval(arg_string) unless arg_string.empty?
+ popped_object
+ end
+ end
+
+ Pry::Commands.alias_command "quit", "exit"
+end
View
14 lib/pry/default_commands/exit_all.rb
@@ -0,0 +1,14 @@
+class Pry
+ Pry::Commands.command "exit-all", "End the current Pry session (popping all bindings) and returning to caller. Accepts optional return value. Aliases: !!@" do
+ # calculate user-given value
+ exit_value = target.eval(arg_string)
+
+ # clear the binding stack
+ _pry_.binding_stack.clear
+
+ # break out of the repl loop
+ throw(:breakout, exit_value)
+ end
+
+ Pry::Commands.alias_command "!!@", "exit-all"
+end
View
9 lib/pry/default_commands/exit_program.rb
@@ -0,0 +1,9 @@
+class Pry
+ Pry::Commands.command "exit-program", "End the current program. Aliases: quit-program, !!!" do
+ Pry.save_history if Pry.config.history.should_save
+ Kernel.exit target.eval(arg_string).to_i
+ end
+
+ Pry::Commands.alias_command "quit-program", "exit-program"
+ Pry::Commands.alias_command "!!!", "exit-program"
+end
View
283 lib/pry/default_commands/find_method.rb
@@ -1,168 +1,163 @@
class Pry
- module DefaultCommands
- FindMethod = Pry::CommandSet.new do
+ Pry::Commands.create_command "find-method" do
+ extend Pry::Helpers::BaseHelpers
- create_command "find-method" do
- extend Helpers::BaseHelpers
+ group "Context"
- group "Context"
+ options :requires_gem => "ruby18_source_location" if mri_18?
+ options :shellwords => false
- options :requires_gem => "ruby18_source_location" if mri_18?
- options :shellwords => false
+ description "Recursively search for a method within a Class/Module or the current namespace. find-method [-n | -c] METHOD [NAMESPACE]"
- description "Recursively search for a method within a Class/Module or the current namespace. find-method [-n | -c] METHOD [NAMESPACE]"
+ banner <<-BANNER
+ Usage: find-method [-n | -c] METHOD [NAMESPACE]
- banner <<-BANNER
- Usage: find-method [-n | -c] METHOD [NAMESPACE]
+ Recursively search for a method within a Class/Module or the current namespace.
+ Use the `-n` switch (the default) to search for methods whose name matches the given regex.
+ Use the `-c` switch to search for methods that contain the given code.
- Recursively search for a method within a Class/Module or the current namespace.
- Use the `-n` switch (the default) to search for methods whose name matches the given regex.
- Use the `-c` switch to search for methods that contain the given code.
+ e.g find-method re Pry # find all methods whose name match /re/ inside the Pry namespace. Matches Pry#repl, etc.
+ e.g find-method -c 'output.puts' Pry # find all methods that contain the code: output.puts inside the Pry namepsace.
+ BANNER
- e.g find-method re Pry # find all methods whose name match /re/ inside the Pry namespace. Matches Pry#repl, etc.
- e.g find-method -c 'output.puts' Pry # find all methods that contain the code: output.puts inside the Pry namepsace.
- BANNER
+ def setup
+ require 'ruby18_source_location' if mri_18?
+ end
- def setup
- require 'ruby18_source_location' if mri_18?
- end
+ def options(opti)
+ opti.on :n, :name, "Search for a method by name"
+ opti.on :c, :content, "Search for a method based on content in Regex form"
+ end
- def options(opti)
- opti.on :n, :name, "Search for a method by name"
- opti.on :c, :content, "Search for a method based on content in Regex form"
+ def process
+ return if args.size < 1
+ pattern = ::Regexp.new args[0]
+ if args[1]
+ klass = target.eval(args[1])
+ if !klass.is_a?(Module)
+ klass = klass.class
end
+ else
+ klass = (target_self.is_a?(Module)) ? target_self : target_self.class
+ end
- def process
- return if args.size < 1
- pattern = ::Regexp.new args[0]
- if args[1]
- klass = target.eval(args[1])
- if !klass.is_a?(Module)
- klass = klass.class
- end
- else
- klass = (target_self.is_a?(Module)) ? target_self : target_self.class
- end
-
- matches = if opts.content?
- content_search(pattern, klass)
- else
- name_search(pattern, klass)
- end
-
- if matches.empty?
- output.puts text.bold("No Methods Matched")
- else
- print_matches(matches, pattern)
- end
+ matches = if opts.content?
+ content_search(pattern, klass)
+ else
+ name_search(pattern, klass)
+ end
- end
+ if matches.empty?
+ output.puts text.bold("No Methods Matched")
+ else
+ print_matches(matches, pattern)
+ end
- private
-
- # pretty-print a list of matching methods.
- #
- # @param Array[Method]
- def print_matches(matches, pattern)
- grouped = matches.group_by(&:owner)
- order = grouped.keys.sort_by{ |x| x.name || x.to_s }
-
- order.each do |klass|
- output.puts text.bold(klass.name)
- grouped[klass].each do |method|
- header = method.name_with_owner
-
- extra = if opts.content?
- header += ": "
- colorize_code((method.source.split(/\n/).select {|x| x =~ pattern }).join("\n#{' ' * header.length}"))
- else
- ""
- end
-
- output.puts header + extra
- end
- end
- end
+ end
+
+ private
+
+ # pretty-print a list of matching methods.
+ #
+ # @param Array[Method]
+ def print_matches(matches, pattern)
+ grouped = matches.group_by(&:owner)
+ order = grouped.keys.sort_by{ |x| x.name || x.to_s }
+
+ order.each do |klass|
+ output.puts text.bold(klass.name)
+ grouped[klass].each do |method|
+ header = method.name_with_owner
- # Run the given block against every constant in the provided namespace.
- #
- # @param Module The namespace in which to start the search.
- # @param Hash[Module,Boolean] The namespaces we've already visited (private)
- # @yieldparam klazz Each class/module in the namespace.
- #
- def recurse_namespace(klass, done={}, &block)
- return if !(Module === klass) || done[klass]
-
- done[klass] = true
-
- yield klass
-
- klass.constants.each do |name|
- next if klass.autoload?(name)
- begin
- const = klass.const_get(name)
- rescue RescuableException
- # constant loading is an inexact science at the best of times,
- # this often happens when a constant was .autoload? but someone
- # tried to load it. It's now not .autoload? but will still raise
- # a NameError when you access it.
- else
- recurse_namespace(const, done, &block)
- end
- end
+ extra = if opts.content?
+ header += ": "
+ colorize_code((method.source.split(/\n/).select {|x| x =~ pattern }).join("\n#{' ' * header.length}"))
+ else
+ ""
+ end
+
+ output.puts header + extra
end
+ end
+ end
- # Gather all the methods in a namespace that pass the given block.
- #
- # @param Module The namespace in which to search.
- # @yieldparam Method The method to test
- # @yieldreturn Boolean
- # @return Array[Method]
- #
- def search_all_methods(namespace)
- done = Hash.new{ |h,k| h[k] = {} }
- matches = []
-
- recurse_namespace(namespace) do |klass|
- (Pry::Method.all_from_class(klass) + Pry::Method.all_from_obj(klass)).each do |method|
- next if done[method.owner][method.name]
- done[method.owner][method.name] = true
-
- matches << method if yield method
- end
- end
-
- matches
+ # Run the given block against every constant in the provided namespace.
+ #
+ # @param Module The namespace in which to start the search.
+ # @param Hash[Module,Boolean] The namespaces we've already visited (private)
+ # @yieldparam klazz Each class/module in the namespace.
+ #
+ def recurse_namespace(klass, done={}, &block)
+ return if !(Module === klass) || done[klass]
+
+ done[klass] = true
+
+ yield klass
+
+ klass.constants.each do |name|
+ next if klass.autoload?(name)
+ begin
+ const = klass.const_get(name)
+ rescue RescuableException
+ # constant loading is an inexact science at the best of times,
+ # this often happens when a constant was .autoload? but someone
+ # tried to load it. It's now not .autoload? but will still raise
+ # a NameError when you access it.
+ else
+ recurse_namespace(const, done, &block)
end
+ end
+ end
- # Search for all methods with a name that matches the given regex
- # within a namespace.
- #
- # @param Regex The regex to search for
- # @param Module The namespace to search
- # @return Array[Method]
- #
- def name_search(regex, namespace)
- search_all_methods(namespace) do |meth|
- meth.name =~ regex
- end
+ # Gather all the methods in a namespace that pass the given block.
+ #
+ # @param Module The namespace in which to search.
+ # @yieldparam Method The method to test
+ # @yieldreturn Boolean
+ # @return Array[Method]
+ #
+ def search_all_methods(namespace)
+ done = Hash.new{ |h,k| h[k] = {} }
+ matches = []
+
+ recurse_namespace(namespace) do |klass|
+ (Pry::Method.all_from_class(klass) + Pry::Method.all_from_obj(klass)).each do |method|
+ next if done[method.owner][method.name]
+ done[method.owner][method.name] = true
+
+ matches << method if yield method
end
+ end
+
+ matches
+ end
+
+ # Search for all methods with a name that matches the given regex
+ # within a namespace.
+ #
+ # @param Regex The regex to search for
+ # @param Module The namespace to search
+ # @return Array[Method]
+ #
+ def name_search(regex, namespace)
+ search_all_methods(namespace) do |meth|
+ meth.name =~ regex
+ end
+ end
- # Search for all methods who's implementation matches the given regex
- # within a namespace.
- #
- # @param Regex The regex to search for
- # @param Module The namespace to search
- # @return Array[Method]
- #
- def content_search(regex, namespace)
- search_all_methods(namespace) do |meth|
- begin
- meth.source =~ regex
- rescue RescuableException
- false
- end
- end
+ # Search for all methods who's implementation matches the given regex
+ # within a namespace.
+ #
+ # @param Regex The regex to search for
+ # @param Module The namespace to search
+ # @return Array[Method]
+ #
+ def content_search(regex, namespace)
+ search_all_methods(namespace) do |meth|
+ begin
+ meth.source =~ regex
+ rescue RescuableException
+ false
end
end
end
View
20 lib/pry/default_commands/gem_cd.rb
@@ -0,0 +1,20 @@
+class Pry
+ Pry::Commands.create_command "gem-cd", "Change working directory to specified gem's directory.", :argument_required => true do |gem|
+ banner <<-BANNER
+ Usage: gem-cd GEM_NAME
+
+ Change the current working directory to that in which the given gem is installed.
+ BANNER
+
+ def process(gem)
+ specs = Gem::Specification.respond_to?(:each) ? Gem::Specification.find_all_by_name(gem) : Gem.source_index.find_name(gem)
+ spec = specs.sort { |a,b| Gem::Version.new(b.version) <=> Gem::Version.new(a.version) }.first
+ if spec
+ Dir.chdir(spec.full_gem_path)
+ output.puts(Dir.pwd)
+ else
+ raise CommandError, "Gem `#{gem}` not found."
+ end
+ end
+ end
+end
View
28 lib/pry/default_commands/gem_install.rb
@@ -0,0 +1,28 @@
+class Pry
+ Pry::Commands.create_command "gem-install", "Install a gem and refresh the gem cache.", :argument_required => true do |gem|
+ banner <<-BANNER
+ Usage: gem-install GEM_NAME
+
+ Installs the given gem and refreshes the gem cache so that you can immediately 'require GEM_FILE'
+ BANNER
+
+ def setup
+ require 'rubygems/dependency_installer' unless defined? Gem::DependencyInstaller
+ end
+
+ def process(gem)
+ begin
+ destination = File.writable?(Gem.dir) ? Gem.dir : Gem.user_dir
+ installer = Gem::DependencyInstaller.new :install_dir => destination
+ installer.install gem
+ rescue Errno::EACCES
+ raise CommandError, "Insufficient permissions to install `#{text.green gem}`."
+ rescue Gem::GemNotFoundException
+ raise CommandError, "Gem `#{text.green gem}` not found."
+ else
+ Gem.refresh
+ output.puts "Gem `#{text.green gem}` installed."
+ end
+ end
+ end
+end
View
31 lib/pry/default_commands/gem_list.rb
@@ -0,0 +1,31 @@
+class Pry
+ Pry::Commands.create_command "gem-list", "List and search installed gems." do |pattern|
+ banner <<-BANNER
+ Usage: gem-list [REGEX]
+
+ List all installed gems, when a regex is provided, limit the output to those that
+ match the regex.
+ BANNER
+
+ def process(pattern=nil)
+ pattern = Regexp.compile(pattern || '')
+ gems = if Gem::Specification.respond_to?(:each)
+ Gem::Specification.select{|spec| spec.name =~ pattern }.group_by(&:name)
+ else
+ Gem.source_index.gems.values.group_by(&:name).select { |gemname, specs| gemname =~ pattern }
+ end
+
+ gems.each do |gem, specs|
+ specs.sort! do |a,b|
+ Gem::Version.new(b.version) <=> Gem::Version.new(a.version)
+ end
+
+ versions = specs.each_with_index.map do |spec, index|
+ index == 0 ? text.bright_green(spec.version.to_s) : text.green(spec.version.to_s)
+ end
+
+ output.puts "#{text.default gem} (#{versions.join ', '})"
+ end
+ end
+ end
+end
View
84 lib/pry/default_commands/gems.rb
@@ -1,84 +0,0 @@
-class Pry
- module DefaultCommands
-
- Gems = Pry::CommandSet.new do
-
- create_command "gem-install", "Install a gem and refresh the gem cache.", :argument_required => true do |gem|
-
- banner <<-BANNER
- Usage: gem-install GEM_NAME
-
- Installs the given gem and refreshes the gem cache so that you can immediately 'require GEM_FILE'
- BANNER
-
- def setup
- require 'rubygems/dependency_installer' unless defined? Gem::DependencyInstaller
- end
-
- def process(gem)
- begin
- destination = File.writable?(Gem.dir) ? Gem.dir : Gem.user_dir
- installer = Gem::DependencyInstaller.new :install_dir => destination
- installer.install gem
- rescue Errno::EACCES
- raise CommandError, "Insufficient permissions to install `#{text.green gem}`."
- rescue Gem::GemNotFoundException
- raise CommandError, "Gem `#{text.green gem}` not found."
- else
- Gem.refresh
- output.puts "Gem `#{text.green gem}` installed."
- end
- end
- end
-
- create_command "gem-cd", "Change working directory to specified gem's directory.", :argument_required => true do |gem|
- banner <<-BANNER
- Usage: gem-cd GEM_NAME
-
- Change the current working directory to that in which the given gem is installed.
- BANNER
-
- def process(gem)
- specs = Gem::Specification.respond_to?(:each) ? Gem::Specification.find_all_by_name(gem) : Gem.source_index.find_name(gem)
- spec = specs.sort { |a,b| Gem::Version.new(b.version) <=> Gem::Version.new(a.version) }.first
- if spec
- Dir.chdir(spec.full_gem_path)
- output.puts(Dir.pwd)
- else
- raise CommandError, "Gem `#{gem}` not found."
- end
- end
- end
-
- create_command "gem-list", "List and search installed gems." do |pattern|
- banner <<-BANNER
- Usage: gem-list [REGEX]
-
- List all installed gems, when a regex is provided, limit the output to those that
- match the regex.
- BANNER
-
- def process(pattern=nil)
- pattern = Regexp.compile(pattern || '')
- gems = if Gem::Specification.respond_to?(:each)
- Gem::Specification.select{|spec| spec.name =~ pattern }.group_by(&:name)
- else
- Gem.source_index.gems.values.group_by(&:name).select { |gemname, specs| gemname =~ pattern }
- end
-
- gems.each do |gem, specs|
- specs.sort! do |a,b|
- Gem::Version.new(b.version) <=> Gem::Version.new(a.version)
- end
-
- versions = specs.each_with_index.map do |spec, index|
- index == 0 ? text.bright_green(spec.version.to_s) : text.green(spec.version.to_s)
- end
-
- output.puts "#{text.default gem} (#{versions.join ', '})"
- end
- end
- end
- end
- end
-end
View
316 lib/pry/default_commands/gist.rb
@@ -1,187 +1,183 @@
class Pry
- module DefaultCommands
- Gist = Pry::CommandSet.new do
- create_command "gist", "Gist a method or expression history to GitHub.", :requires_gem => "jist" do
- include Pry::Helpers::DocumentationHelpers
-
- banner <<-USAGE
- Usage: gist [OPTIONS] [METH]
- Gist method (doc or source) or input expression to GitHub.
-
- If you'd like to permanently associate your gists with your GitHub account run `gist --login`.
-
- e.g: gist -m my_method # gist the method my_method
- e.g: gist -d my_method # gist the documentation for my_method
- e.g: gist -i 1..10 # gist the input expressions from 1 to 10
- e.g: gist -k show-method # gist the command show-method
- e.g: gist -c Pry # gist the Pry class
- e.g: gist -m hello_world --lines 2..-2 # gist from lines 2 to the second-last of the hello_world method
- e.g: gist -m my_method --clip # Copy my_method source to clipboard, do not gist it.
- USAGE
-
- command_options :shellwords => false
-
- attr_accessor :content
- attr_accessor :filename
-
- def setup
- require 'jist'
- self.content = ""
- self.filename = "a.rb"
- end
+ Pry::Commands.create_command "gist", "Gist a method or expression history to GitHub.", :requires_gem => "jist" do
+ include Pry::Helpers::DocumentationHelpers
- def options(opt)
- opt.on :login, "Authenticate the jist gem with GitHub"
- opt.on :m, :method, "Gist a method's source.", :argument => true do |meth_name|
- meth = get_method_or_raise(meth_name, target, {})
- self.content << meth.source << "\n"
- self.filename = meth.source_file
- end
- opt.on :d, :doc, "Gist a method's documentation.", :argument => true do |meth_name|
- meth = get_method_or_raise(meth_name, target, {})
- text.no_color do
- self.content << process_comment_markup(meth.doc) << "\n"
- end
- self.filename = meth.source_file + ".doc"
- end
- opt.on :k, :command, "Gist a command's source.", :argument => true do |command_name|
- command = find_command(command_name)
- block = Pry::Method.new(command.block)
- self.content << block.source << "\n"
- self.filename = block.source_file
- end
- opt.on :c, :class, "Gist a class or module's source.", :argument => true do |class_name|
- mod = Pry::WrappedModule.from_str(class_name, target)
- self.content << mod.source << "\n"
- self.filename = mod.source_file
- end
- opt.on :var, "Gist a variable's content.", :argument => true do |variable_name|
- begin
- obj = target.eval(variable_name)
- rescue Pry::RescuableException
- raise CommandError, "Gist failed: Invalid variable name: #{variable_name}"
- end
+ banner <<-USAGE
+ Usage: gist [OPTIONS] [METH]
+ Gist method (doc or source) or input expression to GitHub.
- self.content << Pry.config.gist.inspecter.call(obj) << "\n"
- end
- opt.on :hist, "Gist a range of Readline history lines.", :optional_argument => true, :as => Range, :default => -20..-1 do |range|
- h = Pry.history.to_a
- self.content << h[one_index_range(convert_to_range(range))].join("\n") << "\n"
- end
+ If you'd like to permanently associate your gists with your GitHub account run `gist --login`.
- opt.on :f, :file, "Gist a file.", :argument => true do |file|
- self.content << File.read(File.expand_path(file)) << "\n"
- self.filename = file
- end
- opt.on :o, :out, "Gist entries from Pry's output result history. Takes an index or range.", :optional_argument => true,
- :as => Range, :default => -1 do |range|
- range = convert_to_range(range)
+ e.g: gist -m my_method # gist the method my_method
+ e.g: gist -d my_method # gist the documentation for my_method
+ e.g: gist -i 1..10 # gist the input expressions from 1 to 10
+ e.g: gist -k show-method # gist the command show-method
+ e.g: gist -c Pry # gist the Pry class
+ e.g: gist -m hello_world --lines 2..-2 # gist from lines 2 to the second-last of the hello_world method
+ e.g: gist -m my_method --clip # Copy my_method source to clipboard, do not gist it.
+ USAGE
- range.each do |v|
- self.content << Pry.config.gist.inspecter.call(_pry_.output_array[v])
- end
+ command_options :shellwords => false
- self.content << "\n"
- end
- opt.on :clip, "Copy the selected content to clipboard instead, do NOT gist it.", :default => false
- opt.on :p, :public, "Create a public gist (default: false)", :default => false
- opt.on :l, :lines, "Only gist a subset of lines from the gistable content.", :optional_argument => true, :as => Range, :default => 1..-1
- opt.on :i, :in, "Gist entries from Pry's input expression history. Takes an index or range.", :optional_argument => true,
- :as => Range, :default => -1 do |range|
- range = convert_to_range(range)
- input_expressions = _pry_.input_array[range] || []
- Array(input_expressions).each_with_index do |code, index|
- corrected_index = index + range.first
- if code && code != ""
- self.content << code
- if code !~ /;\Z/
- self.content << "#{comment_expression_result_for_gist(Pry.config.gist.inspecter.call(_pry_.output_array[corrected_index]))}"
- end
- end
- end
- end