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.
Constants
- VOID_VALUE
represents a void return value for a command
Attributes
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
Properties of one execution of a command (passed by {Pry#run_command} as a hash of context and expanded in `#initialize`
Public Class Methods
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 266 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._pry_ = context[:pry_instance] end
Public Instance Methods
# File lib/pry/command.rb, line 58 def block @block || instance_method(:process) end
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 412 def call_safely(*args) unless dependencies_met? gems_needed = Array(command_options[:requires_gem]) gems_not_installed = gems_needed.select { |g| !Rubygem.installed?(g) } output.puts "\nThe command '#{command_name}' is #{text.bold("unavailable")} because it requires the following gems to be installed: #{(gems_not_installed.join(", "))}" output.puts "-" output.puts "Type `install-command #{command_name}` to install the required gems and activate this command." return void end if command_options[:argument_required] && args.empty? raise CommandError, "The command '#{command_name}' requires an argument." end ret = call_with_hooks(*args) command_options[:keep_retval] ? ret : void end
Display a warning if a command collides with a local/method in the current scope.
# File lib/pry/command.rb, line 305 def check_for_command_collision(command_match, arg_string) collision_type = target.eval("defined?(#{command_match})") collision_type ||= 'local-variable' if arg_string.match(%r{\A\s*[-+*/%&|^]*=}) if collision_type output.puts "#{text.bold('WARNING:')} Calling Pry command '#{command_match}'," + "which conflicts with a #{collision_type}.\n\n" end rescue Pry::RescuableException end
# File lib/pry/command.rb, line 105 def command_name; self.class.command_name; end
Define or get the command's options
# File lib/pry/command.rb, line 43 def command_options(arg=nil) @command_options ||= default_options(match) @command_options.merge!(arg) if arg @command_options end
# File lib/pry/command.rb, line 177 def command_regex pr = defined?(Pry.config.command_prefix) ? Pry.config.command_prefix : "" prefix = convert_to_regex(pr) prefix = "(?:#{prefix})?" unless options[:use_prefix] /^#{prefix}#{convert_to_regex(match)}(?!\S)/ end
# File lib/pry/command.rb, line 249 def commands command_set.commands end
Generate completions for this command
@param [String] search The line typed so far @return [Array<String>] Completion words
# File lib/pry/command.rb, line 441 def complete(search); Bond::DefaultMission.completions; end
# File lib/pry/command.rb, line 185 def convert_to_regex(obj) case obj when String Regexp.escape(obj) else obj end end
# File lib/pry/command.rb, line 85 def default_options(match) { :requires_gem => [], :keep_retval => false, :argument_required => false, :interpolate => true, :shellwords => true, :listing => (String === match ? match : match.inspect), :use_prefix => true, :takes_block => false } end
Are all the gems required to use this command installed?
@return Boolean
# File lib/pry/command.rb, line 433 def dependencies_met? @dependencies_met ||= command_dependencies_met?(command_options) end
Define or get the command's description
# File lib/pry/command.rb, line 37 def description(arg=nil) @description = arg if arg @description end
# File lib/pry/command.rb, line 67 def doc new.help end
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.
# File lib/pry/command.rb, line 197 def group(name=nil) @group ||= if name name else case Pry::Method(block).source_file when %r{/pry/.*_commands/(.*).rb} $1.capitalize.gsub(/_/, " ") when %r{(pry-\w+)-([\d\.]+([\w\d\.]+)?)} name, version = $1, $2 "#{name.to_s} (v#{version.to_s})" when /pryrc/ "~/.pryrc" else "(other)" end end end
Store hooks to be run before or after the command body. @see {Pry::CommandSet#before_command} @see {Pry::CommandSet#after_command}
# File lib/pry/command.rb, line 173 def hooks @hooks ||= {:before => [], :after => []} end
# File lib/pry/command.rb, line 114 def inspect name end
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 294 def interpolate_string(str) dumped_str = str.dump if dumped_str.gsub!(/\\#\{/, '#{') target.eval(dumped_str) else str end end
# File lib/pry/command.rb, line 27 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 end
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 162 def match_score(val) if command_regex =~ val Regexp.last_match.size > 1 ? Regexp.last_match.begin(1) : Regexp.last_match.end(0) else -1 end end
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 142 def matches?(val) command_regex =~ val end
Make those properties accessible to instances
# File lib/pry/command.rb, line 100 def name; self.class.name; end
Process a line that #matches? this command. @param [String] line The line to process @return [Object, Command::VOID_VALUE]
# File lib/pry/command.rb, line 360 def process_line(line) command_match, arg_string, captures, args = tokenize(line) check_for_command_collision(command_match, arg_string) if Pry.config.collision_warning self.arg_string = arg_string self.captures = captures call_safely(*(captures + args)) end
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 244 def run(command_string, *args) complete_string = "#{command_string} #{args.join(" ")}".rstrip command_set.process_line(complete_string, context) end
# File lib/pry/command.rb, line 62 def source file, line = block.source_location strip_leading_whitespace(Pry::Code.from_file(file).expression_at(line)) end
# File lib/pry/command.rb, line 75 def source_file Array(block.source_location).first end
# File lib/pry/command.rb, line 80 def source_line Array(block.source_location).last end
# File lib/pry/command.rb, line 71 def source_location block.source_location end
@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 285 def state _pry_.command_state[match] ||= OpenStruct.new end
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 129 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
@return [Object] The value of `self` inside the `target` binding.
# File lib/pry/command.rb, line 276 def target_self; target.eval('self'); end
# File lib/pry/command.rb, line 253 def text Pry::Helpers::Text end
Extract necessary information from a line that #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 330 def tokenize(val) val.replace(interpolate_string(val)) if command_options[:interpolate] self.class.command_regex =~ val # please call Command.matches? before Command#call_safely raise CommandError, "fatal: called a command which didn't match?!" unless Regexp.last_match 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] if arg_string args = command_options[:shellwords] ? Shellwords.shellwords(arg_string) : arg_string.split(" ") else args = [] end [val[0..pos].rstrip, arg_string, captures, args] end
# File lib/pry/command.rb, line 257 def void VOID_VALUE end
Private Instance Methods
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 448 def call_with_hooks(*args) self.class.hooks[:before].each do |block| instance_exec(*args, &block) end ret = call(*args) self.class.hooks[:after].each do |block| ret = instance_exec(*args, &block) end ret end
Fix the number of arguments we pass to a block to avoid arity warnings. @param [Fixnum] arity The arity of the block @param [Array] args The arguments to pass @return [Array] A (possibly shorter) array of the arguments to pass
# File lib/pry/command.rb, line 466 def correct_arg_arity(arity, args) case when arity < 0 args when arity == 0 [] when arity > 0 args.values_at(*(0..(arity - 1)).to_a) end end
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 378 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 = $~ && $~.offset(0)[0] return if !block_index block_init_string = arg_string.slice!(block_index..-1)[1..-1] prime_string = "proc #{block_init_string}\n" if !Pry::Code.complete_expression?(prime_string) block_string = _pry_.r(target, prime_string) else block_string = prime_string end begin self.command_block = target.eval(block_string) rescue Pry::RescuableException raise CommandError, "Incomplete block definition." end end