Command system

Foo Bar edited this page Nov 18, 2015 · 30 revisions

Command system

Quick Menu:

Back to Main Menu

Overview

The command system is a unique feature that sets Pry apart from other REPLs. Pry commands are not methods; instead they are special strings that are interpreted directly by Pry before the input buffer is evaluated. This approach was chosen because:

  • Commands can do things that methods cannot do: such as modifying the code that the user has typed.
  • Command syntax is more intuitive, and commands can easily support flags like --help that users expect.
  • Commands are local to the Pry console, they don't require global monkey-patches, but they can still be used no-matter which object you are Prying.

As Commands are implemented in Ruby, there's an endless number of things that they can be used to do. At the extreme end of the spectrum, the pry_nav plugin adds "step", and "next" commands for walking through Ruby code. A more simple example is provided by the pry-highlight plugin, which adds a single "highlight" command to pretty-print JSON and XML.

Invoking commands

Simply enter the name of the command at the prompt, followed by any arguments that it takes, and it will be run:

pry(main)> ls -l
locals: _  _ex_  _pry_  _in_  _out_  _file_  _dir_
pry(main)>

In the rare case that the name of a command conflicts with some ruby that you would like to execute, you can prefix the ruby code with a semicolon to prevent commands from being run:

pry(main)> ;ls = "hello"
=> "hello"
pry(main)> ;ls
=> "hello"

HINT: if you find this happens to you a lot, consider setting the Command prefix.

Back to top

The help command

The help command outputs a list of all commands currently defined in Pry, along with a short description of what that command does:

pry(main)> help
...
gist               Gist a method or expression history to github. Type `gist --help` for more info.
help               Show a list of commands, or help for one command
hist               Show and replay Readline history. Aliases: history
...

The help command can also be used to show more details about each individual command, as explained on the Live help page.

Back to top

The command prefix

As stated above, command evaluation takes precedence over normal Ruby code execution. This precedence order should not normally be an issue, but if turns out to be, there are a couple good options.

For a quick fix, you can prefix any line with a semicolon (or any other valid Ruby syntax) to make that line bypass interpretation as a command.

Example:

From: /home/rking/shared/src/scrap/foo.rb @ line 3 Frog#jump:
    3: def jump
    4:   ls = 22
 => 5:   binding.pry
    6: end
[1] pry(#<Frog>)> ls
Frog#methods: jump
locals: _  __  _dir_  _ex_  _file_  _in_  _out_  _pry_  ls
[2] pry(#<Frog>)> ;ls
22

As a broader solution, you can set a `Pry.config.command_prefix`, which is a short string that must be prepended before a command to further disambiguate it from actual Ruby code.

Note that two commands ignore this prefix for convenience: [shell commands|Shell-integration#wiki-Execute_shell_commands] and the ['clear input buffer' command|User-Input#wiki-Clear_input].

The Pry.config.command_prefix option defaults to "" (no prefix).

Example:

pry(main)> Pry.config.command_prefix = "%"
=> "%"
pry(main)> ls -l
NameError: undefined local variable or method `l' for main:Object
from (pry):2:in `<main>'
pry(main)> %ls
locals: _  _ex_  _pry_  _in_  _out_  _file_  _dir_
pry(main)>

Back to top

Command Interpolation

As discussed cursorily in accessing the system shell you can directly interpolate Ruby code into commands through the use of the standard #{} syntax:

pry(main)> dir = File.dirname(log_file)
=> "/var/log"
pry(main)> .cd #{dir}
pry(main)> .pwd
/var/log

This is particularly useful when combined with Pry's special locals:

pry(main)> show-doc Pry#rep
From: /home/conrad/.rvm/gems/ree-1.8.7-2011.03@pry/gems/pry-0.9.8/lib/pry/pry_instance.rb @ line 210:
Number of lines: 5
Owner: Pry
Visibility: public
Signature: rep(*arg1)

Perform a read-eval-print.
If no parameter is given, default to top-level (main).
param [Object, Binding] target The receiver of the read-eval-print
example
  Pry.new.rep(Object.new)

pry(main)> cat #{_file_}
require "pry/indent"

class Pry
...
...

Back to top

Custom commands

It is of course possible to add commands to Pry itself, either at runtime or in your ~/.pryrc, for a full guide to the various possibilities, see the custom commands page. To whet your appetite, here are some simple examples:

First command

For our first command let's replicate the Bash shell syntax for replaying a line of history: !<history_line>

Pry.commands.block_command(/!(\d+)/, "Replay a line of history", :listing => "!hist") do |line|
  run "history --replay #{line}"
end

Let's now use it:

pry(main)> hist --tail 3
893: puts 'midnight, beauty, vision, dies.'
894: ls -m
895: ls -i
pry(main)> !893
midnight, beauty, vision, dies.
=> nil
pry(main)>

Second command

For our second command let's implement the sed tool's s/expr1/expr2 substitution syntax.

Pry.commands.block_command /s\/(.*?)\/(.*?)/ do |source, dest|
  eval_string.gsub!(/#{source}/) { dest }
  run "show-input"
end

Now let's see how it's used:

pry(main)> def hello(friends)
pry(main)*   puts "my friends i have come here to say hello"
pry(main)*   puts "hello is an unusual word, but is appropriate at a time like this"
pry(main)*   puts "when it has been so long since we last met"
pry(main)*   puts "before the dogs were put to sleep"
pry(main)* s/hello/goodbye
1: def goodbye(friends)
2:   puts "my friends i have come here to say goodbye"
3:   puts "goodbye is an unusual word, but is appropriate at a time like this"
4:   puts "when it has been so long since we last met"
5:   puts "before the dogs were put to sleep"
pry(main)* s/dogs/cats
1: def goodbye(friends)
2:   puts "my friends i have come here to say goodbye"
3:   puts "goodbye is an unusual word, but is appropriate at a time like this"
4:   puts "when it has been so long since we last met"
5:   puts "before the cats were put to sleep"
pry(main)* end
=> nil

Back to top

Command sets

Internally, commands are organised into command sets; and once you've mastered the basics of creating your own commands, you'll want to start organising them.

In all the examples before we've used Pry::Commands to define commands, as that is the default command set that is currently active in the REPL. You can also bundle your commands into their own CommandSet:

Example:

command_set = Pry::CommandSet.new do
  block_command "greet" do |name|
    output.puts "hello #{name}"
  end

  block_command "add5" do |num|
    output.puts "#{num.to_i + 5}"
  end
end

Command sets also allow you to define helper modules. These are modules with auxiliary methods for use by all commands in that set:

Example:

command_set = Pry::CommandSet.new do
  block_command "greet" do |name|
    greet_person(name)
  end

  block_command "greet-pair" do |n1, n2|
    greet_person([n1, n2].join(" and "))
  end

  helpers do
    def greet_person(name)
      output.puts "hello #{name}"
    end
  end
end

Once you have created a Commandset, the chances are that you want to make it available to the user. To do this:

Pry::Commands.import my_command_set

CommandSet's have various other methods for renaming, removing, importing and otherwise dicing the commands that they contain, for full information please refer to the YARD documentation.

Back to top