class Pry::Command

The super-class of all commands, new commands should be created by calling {Pry::CommandSet#command} which creates a BlockCommand or {Pry::CommandSet#create_command} which creates a ClassCommand. Please don't use this class directly.

N.B. using a regular expresion here so that “raise-up 'foo'” does the right thing.

Constants

VOID_VALUE

represents a void return value for a command

Attributes

block[W]
command_options[W]
description[W]
match[W]
options=[W]
_pry_=[RW]
arg_string[RW]
captures[RW]
command_block[RW]

The block we pass into a command so long as `:takes_block` is not equal to `false` @example

my-command | do
  puts "block content"
end
command_set[RW]
context[RW]
eval_string[RW]
hooks[RW]
output[RW]

Properties of one execution of a command (passed by {Pry#run_command} as a hash of context and expanded in `#initialize`

pry_instance[RW]
target[RW]

Public Class Methods

banner(arg = nil) click to toggle source

Define or get the command's banner

block() click to toggle source
# File lib/pry/command.rb, line 66
def block
  @block || instance_method(:process)
end
command_name() click to toggle source
# File lib/pry/command.rb, line 109
def command_name
  options[:listing]
end
command_options(arg = nil) click to toggle source

Define or get the command's options

# File lib/pry/command.rb, line 51
def command_options(arg = nil)
  @command_options ||= default_options(match)
  @command_options.merge!(arg) if arg
  @command_options
end
Also aliased as: options
command_regex() click to toggle source
# File lib/pry/command.rb, line 165
def command_regex
  prefix = convert_to_regex(Pry.config.command_prefix)
  prefix = "(?:#{prefix})?" unless options[:use_prefix]

  /\A#{prefix}#{convert_to_regex(match)}(?!\S)/
end
convert_to_regex(obj) click to toggle source
# File lib/pry/command.rb, line 172
def convert_to_regex(obj)
  case obj
  when String
    Regexp.escape(obj)
  else
    obj
  end
end
default_options(match) click to toggle source
# File lib/pry/command.rb, line 89
def default_options(match)
  {
    keep_retval: false,
    argument_required: false,
    interpolate: true,
    shellwords: true,
    listing: (match.is_a?(String) ? match : match.inspect),
    use_prefix: true,
    takes_block: false
  }
end
description(arg = nil) click to toggle source

Define or get the command's description

# File lib/pry/command.rb, line 45
def description(arg = nil)
  @description = arg if arg
  @description ||= nil
end
doc() click to toggle source
# File lib/pry/command.rb, line 75
def doc
  new.help
end
file()
Alias for: source_file
group(name = nil) click to toggle source

The group in which the command should be displayed in “help” output. This is usually auto-generated from directory naming, but it can be manually overridden if necessary. Group should not be changed once it is initialized.

# File lib/pry/command.rb, line 185
def group(name = nil)
  @group ||= begin
    name || case Pry::Method(block).source_file
            when %r{/pry/.*_commands/(.*).rb}
              Regexp.last_match(1).capitalize.tr('_', " ")
            when /(pry-\w+)-([\d\.]+([\w\.]+)?)/
              name = Regexp.last_match(1)
              version = Regexp.last_match(2)
              "#{name} (v#{version})"
            when /pryrc/
              "pryrc"
            else
              "(other)"
            end
  end
end
inspect() click to toggle source
# File lib/pry/command.rb, line 105
def inspect
  name
end
line()
Alias for: source_line
match(arg = nil) click to toggle source
# File lib/pry/command.rb, line 35
def match(arg = nil)
  if arg
    @command_options ||= default_options(arg)
    @command_options[:listing] = arg.is_a?(String) ? arg : arg.inspect
    @match = arg
  end
  @match ||= nil
end
match_score(val) click to toggle source

How well does this command match the given line?

Higher scores are better because they imply that this command matches the line more closely.

The score is calculated by taking the number of characters at the start of the string that are used only to identify the command, not as part of the arguments.

@example

/\.(.*)/.match_score(".foo") #=> 1
/\.*(.*)/.match_score("...foo") #=> 3
'hi'.match_score("hi there") #=> 2

@param [String] val A line input at the REPL @return [Fixnum]

# File lib/pry/command.rb, line 153
def match_score(val)
  if command_regex =~ val
    if Regexp.last_match.size > 1
      Regexp.last_match.begin(1)
    else
      Regexp.last_match.end(0)
    end
  else
    -1
  end
end
matches?(val) click to toggle source

Should this command be called for the given line? @param [String] val A line input at the REPL @return [Boolean]

# File lib/pry/command.rb, line 133
def matches?(val)
  command_regex =~ val
end
name() click to toggle source
Calls superclass method
# File lib/pry/command.rb, line 101
def name
  super.to_s == "" ? "#<class(Pry::Command #{match.inspect})>" : super
end
new(context = {}) click to toggle source

Instantiate a command, in preparation for calling it. @param [Hash] context The runtime context to use with this command.

# File lib/pry/command.rb, line 230
def initialize(context = {})
  self.context      = context
  self.target       = context[:target]
  self.output       = context[:output]
  self.eval_string  = context[:eval_string]
  self.command_set  = context[:command_set]
  self.hooks        = context[:hooks]
  self.pry_instance = context[:pry_instance]
end
options(arg = nil)

backward compatibility

Alias for: command_options
source() click to toggle source
# File lib/pry/command.rb, line 70
def source
  file, line = block.source_location
  strip_leading_whitespace(Pry::Code.from_file(file).expression_at(line))
end
source_file() click to toggle source
# File lib/pry/command.rb, line 79
def source_file
  Array(block.source_location).first
end
Also aliased as: file
source_line() click to toggle source
# File lib/pry/command.rb, line 84
def source_line
  Array(block.source_location).last
end
Also aliased as: line
state() click to toggle source
# File lib/pry/command.rb, line 202
def state
  Pry::CommandState.default.state_for(match)
end
subclass(match, description, options, helpers, &block) click to toggle source

Create a new command with the given properties. @param [String, Regex] match The thing that triggers this command @param [String] description The description to appear in `help` @param [Hash] options Behavioral options (see {Pry::CommandSet#command}) @param [Module] helpers A module of helper functions to be included. @yield optional, used for BlockCommands @return [Class] (a subclass of {Pry::Command})

# File lib/pry/command.rb, line 120
def subclass(match, description, options, helpers, &block)
  klass = Class.new(self)
  klass.send(:include, helpers)
  klass.match = match
  klass.description = description
  klass.command_options = options
  klass.block = block
  klass
end

Public Instance Methods

_pry_() click to toggle source
# File lib/pry/command.rb, line 292
def _pry_
  Pry::Warning.warn('_pry_ is deprecated, use pry_instance instead')
  pry_instance
end
block() click to toggle source
# File lib/pry/command.rb, line 253
def block
  self.class.block
end
check_for_command_collision(command_match, arg_string) click to toggle source

Display a warning if a command collides with a local/method in the current scope.

# File lib/pry/command.rb, line 329
def check_for_command_collision(command_match, arg_string)
  collision_type = target.eval("defined?(#{command_match})")
  collision_type ||= 'local-variable' if arg_string =~ %r{\A\s*[-+*/%&|^]*=}

  if collision_type
    output.puts(
      "#{Helpers::Text.bold('WARNING:')} Calling Pry command '#{command_match}', " \
      "which conflicts with a #{collision_type}.\n\n"
    )
  end
rescue Pry::RescuableException # rubocop:disable Lint/HandleExceptions
end
command_name() click to toggle source
# File lib/pry/command.rb, line 261
def command_name
  self.class.command_name
end
command_options() click to toggle source
# File lib/pry/command.rb, line 257
def command_options
  self.class.options
end
commands() click to toggle source
# File lib/pry/command.rb, line 284
def commands
  command_set.to_hash
end
complete(_search) click to toggle source

Generate completions for this command

@param [String] _search The line typed so far @return [Array<String>] Completion words

# File lib/pry/command.rb, line 411
def complete(_search)
  []
end
description() click to toggle source
# File lib/pry/command.rb, line 249
def description
  self.class.description
end
interpolate_string(str) click to toggle source

Revaluate the string (str) and perform interpolation. @param [String] str The string to reevaluate with interpolation.

@return [String] The reevaluated string with interpolations

applied (if any).
# File lib/pry/command.rb, line 318
def interpolate_string(str)
  dumped_str = str.dump
  if dumped_str.gsub!(/\\\#\{/, '#{')
    target.eval(dumped_str)
  else
    str
  end
end
match() click to toggle source
# File lib/pry/command.rb, line 245
def match
  self.class.match
end
name() click to toggle source

Make those properties accessible to instances

# File lib/pry/command.rb, line 241
def name
  self.class.name
end
process_line(line) click to toggle source

Process a line that Command.matches? this command. @param [String] line The line to process @return [Object, Command::VOID_VALUE]

# File lib/pry/command.rb, line 394
def process_line(line)
  command_match, arg_string, captures, args = tokenize(line)

  if Pry.config.collision_warning
    check_for_command_collision(command_match, arg_string)
  end

  self.arg_string = arg_string
  self.captures = captures

  call_safely(*(captures + args))
end
run(command_string, *args) click to toggle source

Run a command from another command. @param [String] command_string The string that invokes the command @param [Array] args Further arguments to pass to the command @example

run "show-input"

@example

run ".ls"

@example

run "amend-line",  "5", 'puts "hello world"'
# File lib/pry/command.rb, line 278
def run(command_string, *args)
  command_string = pry_instance.config.command_prefix.to_s + command_string
  complete_string = "#{command_string} #{args.join(' ')}".rstrip
  command_set.process_line(complete_string, context)
end
source() click to toggle source
# File lib/pry/command.rb, line 265
def source
  self.class.source
end
state() click to toggle source

@return [Hash] Pry commands can store arbitrary state

here. This state persists between subsequent command invocations.
All state saved here is unique to the command, it does not
need to be namespaced.

@example

state.my_state = "my state"  # this will not conflict with any
                             # `state.my_state` used in another command.
# File lib/pry/command.rb, line 309
def state
  self.class.state
end
target_self() click to toggle source

@return [Object] The value of `self` inside the `target` binding.

# File lib/pry/command.rb, line 298
def target_self
  target.eval('self')
end
tokenize(val) click to toggle source

Extract necessary information from a line that Command.matches? this command.

Returns an array of four elements:

“`

[String] the portion of the line that matched with the Command match
[String] a string of all the arguments (i.e. everything but the match)
[Array]  the captures caught by the command_regex
[Array]  the arguments obtained by splitting the arg_string

“`

@param [String] val The line of input @return [Array]

# File lib/pry/command.rb, line 356
def tokenize(val)
  val = interpolate_string(val) if command_options[:interpolate]

  self.class.command_regex =~ val

  # please call Command.matches? before Command#call_safely
  unless Regexp.last_match
    raise CommandError, "fatal: called a command which didn't match?!"
  end

  captures = Regexp.last_match.captures
  pos = Regexp.last_match.end(0)

  arg_string = val[pos..-1]

  # remove the one leading space if it exists
  arg_string.slice!(0) if arg_string.start_with?(" ")

  # process and pass a block if one is found
  pass_block(arg_string) if command_options[:takes_block]

  args =
    if arg_string
      if command_options[:shellwords]
        Shellwords.shellwords(arg_string)
      else
        arg_string.split(" ")
      end
    else
      []
    end

  [val[0..pos].rstrip, arg_string, captures, args]
end
void() click to toggle source
# File lib/pry/command.rb, line 288
def void
  VOID_VALUE
end

Private Instance Methods

after_hooks() click to toggle source
# File lib/pry/command.rb, line 485
def after_hooks
  find_hooks('after')
end
before_hooks() click to toggle source
# File lib/pry/command.rb, line 481
def before_hooks
  find_hooks('before')
end
call_safely(*args) click to toggle source

Run the command with the given `args`.

This is a public wrapper around `#call` which ensures all preconditions are met.

@param [Array<String>] args The arguments to pass to this command. @return [Object] The return value of the `#call` method, or

{Command::VOID_VALUE}.
# File lib/pry/command.rb, line 425
def call_safely(*args)
  if command_options[:argument_required] && args.empty?
    raise CommandError, "The command '#{command_name}' requires an argument."
  end

  ret = use_unpatched_symbol do
    call_with_hooks(*args)
  end
  command_options[:keep_retval] ? ret : void
end
call_with_hooks(*args) click to toggle source

Run the `#call` method and all the registered hooks. @param [Array<String>] args The arguments to `#call` @return [Object] The return value from `#call`

# File lib/pry/command.rb, line 492
def call_with_hooks(*args)
  before_hooks.each { |block| instance_exec(*args, &block) }

  ret = call(*args)

  after_hooks.each do |block|
    ret = instance_exec(*args, &block)
  end

  ret
end
find_hooks(event) click to toggle source
# File lib/pry/command.rb, line 476
def find_hooks(event)
  event_name = "#{event}_#{command_name}"
  (hooks || Pry.hooks || self.class.hooks).get_hooks(event_name).values
end
normalize_method_args(method, args) click to toggle source

Normalize method arguments according to its arity.

@param [Integer] method @param [Array] args @return [Array] a (possibly shorter) array of the arguments to pass

# File lib/pry/command.rb, line 509
def normalize_method_args(method, args)
  case method.arity
  when -1
    args
  when 0
    []
  else
    args.values_at(*(0..(method.arity - 1)).to_a)
  end
end
pass_block(arg_string) click to toggle source

Pass a block argument to a command. @param [String] arg_string The arguments (as a string) passed to the command.

We inspect these for a '| do' or a '| {' and if we find it we use it
to start a block input sequence. Once we have a complete
block, we save it to an accessor that can be retrieved from the command context.
Note that if we find the '| do' or '| {' we delete this and the
elements following it from `arg_string`.
# File lib/pry/command.rb, line 451
def pass_block(arg_string)
  # Workaround for weird JRuby bug where rindex in this case can return nil
  # even when there's a match.
  arg_string.scan(/\| *(?:do|\{)/)
  block_index = $LAST_MATCH_INFO && $LAST_MATCH_INFO.offset(0)[0]

  return unless block_index

  block_init_string = arg_string.slice!(block_index..-1)[1..-1]
  prime_string = "proc #{block_init_string}\n"

  block_string =
    if !Pry::Code.complete_expression?(prime_string)
      pry_instance.r(target, prime_string)
    else
      prime_string
    end

  begin
    self.command_block = target.eval(block_string)
  rescue Pry::RescuableException
    raise CommandError, "Incomplete block definition."
  end
end
use_unpatched_symbol() { || ... } click to toggle source
# File lib/pry/command.rb, line 436
def use_unpatched_symbol
  call_method = Symbol.method_defined?(:call) && Symbol.instance_method(:call)
  Symbol.class_eval { undef :call } if call_method
  yield
ensure
  Symbol.instance_eval { define_method(:call, call_method) } if call_method
end