1
0
Fork 0
mirror of https://github.com/pry/pry.git synced 2022-11-09 12:35:05 -05:00

Rename Command#name -> Command#match

The problem with using "name" for this is that several tools expect
Class#name to return a String, and Commands are classes.

This could cause some subtle breakage, but the tests seem ok™
This commit is contained in:
Conrad Irwin 2012-04-01 16:00:59 -07:00
parent c2f06f3da2
commit 4fe5f70447
3 changed files with 88 additions and 82 deletions

View file

@ -15,9 +15,14 @@ class Pry
# {CommandSet#command} or {CommandSet#create_command}). # {CommandSet#command} or {CommandSet#create_command}).
class << self class << self
attr_accessor :block attr_accessor :block
attr_accessor :name
attr_writer :description attr_writer :description
attr_writer :command_options attr_writer :command_options
attr_writer :match
def match(arg=nil)
@match = arg if arg
@match
end
# Define or get the command's description # Define or get the command's description
def description(arg=nil) def description(arg=nil)
@ -44,19 +49,23 @@ class Pry
# Make those properties accessible to instances # Make those properties accessible to instances
def name; self.class.name; end def name; self.class.name; end
def match; self.class.match; end
def description; self.class.description; end def description; self.class.description; end
def block; self.class.block; end def block; self.class.block; end
def command_options; self.class.options; end def command_options; self.class.options; end
def command_name; command_options[:listing]; end def command_name; command_options[:listing]; end
class << self class << self
def name
super.to_s == "" ? "#<class(Pry::Command #{match.inspect})>" : super
end
def inspect def inspect
"#<class(Pry::Command #{name.inspect})>" name
end end
# Create a new command with the given properties. # Create a new command with the given properties.
# #
# @param String name the name of the command # @param String/Regex match the thing that triggers this command
# @param String description the description to appear in {help} # @param String description the description to appear in {help}
# @param Hash options behavioural options (@see {Pry::CommandSet#command}) # @param Hash options behavioural options (@see {Pry::CommandSet#command})
# @param Module helpers a module of helper functions to be included. # @param Module helpers a module of helper functions to be included.
@ -64,10 +73,10 @@ class Pry
# #
# @return Class (a subclass of Pry::Command) # @return Class (a subclass of Pry::Command)
# #
def subclass(name, description, options, helpers, &block) def subclass(match, description, options, helpers, &block)
klass = Class.new(self) klass = Class.new(self)
klass.send(:include, helpers) klass.send(:include, helpers)
klass.name = name klass.match = match
klass.description = description klass.description = description
klass.command_options = options klass.command_options = options
klass.block = block klass.block = block
@ -117,7 +126,7 @@ class Pry
prefix = convert_to_regex(Pry.config.command_prefix) prefix = convert_to_regex(Pry.config.command_prefix)
prefix = "(?:#{prefix})?" unless options[:use_prefix] prefix = "(?:#{prefix})?" unless options[:use_prefix]
/^#{prefix}#{convert_to_regex(name)}(?!\S)/ /^#{prefix}#{convert_to_regex(match)}(?!\S)/
end end
def convert_to_regex(obj) def convert_to_regex(obj)
@ -232,12 +241,12 @@ class Pry
# the current scope. # the current scope.
# @param [String] command_name_match The name of the colliding command. # @param [String] command_name_match The name of the colliding command.
# @param [Binding] target The current binding context. # @param [Binding] target The current binding context.
def check_for_command_name_collision(command_name_match, arg_string) def check_for_command_collision(command_match, arg_string)
collision_type = target.eval("defined?(#{command_name_match})") collision_type = target.eval("defined?(#{command_match})")
collision_type ||= 'local-variable' if arg_string.match(%r{\A\s*[-+*/%&|^]*=}) collision_type ||= 'local-variable' if arg_string.match(%r{\A\s*[-+*/%&|^]*=})
if collision_type if collision_type
output.puts "#{Pry::Helpers::Text.bold('WARNING:')} Calling Pry command '#{command_name_match}'," + output.puts "#{Pry::Helpers::Text.bold('WARNING:')} Calling Pry command '#{command_match}'," +
"which conflicts with a #{collision_type}.\n\n" "which conflicts with a #{collision_type}.\n\n"
end end
rescue Pry::RescuableException rescue Pry::RescuableException
@ -247,8 +256,8 @@ class Pry
# #
# @param String the line of input # @param String the line of input
# @return [ # @return [
# String the command name used, or portion of line that matched the command_regex # String the portion of the line that matched with the Command match
# String a string of all the arguments (i.e. everything but the name) # String a string of all the arguments (i.e. everything but the match)
# Array the captures caught by the command_regex # Array the captures caught by the command_regex
# Array args the arguments got by splitting the arg_string # Array args the arguments got by splitting the arg_string
# ] # ]
@ -284,9 +293,9 @@ class Pry
# @param String the line to process # @param String the line to process
# @return Object or Command::VOID_VALUE # @return Object or Command::VOID_VALUE
def process_line(line) def process_line(line)
command_name, arg_string, captures, args = tokenize(line) command_match, arg_string, captures, args = tokenize(line)
check_for_command_name_collision(command_name, arg_string) if Pry.config.collision_warning check_for_command_collision(command_match, arg_string) if Pry.config.collision_warning
self.arg_string = arg_string self.arg_string = arg_string
self.captures = captures self.captures = captures
@ -334,14 +343,14 @@ class Pry
unless dependencies_met? unless dependencies_met?
gems_needed = Array(command_options[:requires_gem]) gems_needed = Array(command_options[:requires_gem])
gems_not_installed = gems_needed.select { |g| !gem_installed?(g) } gems_not_installed = gems_needed.select { |g| !gem_installed?(g) }
output.puts "\nThe command '#{name}' is #{Helpers::Text.bold("unavailable")} because it requires the following gems to be installed: #{(gems_not_installed.join(", "))}" output.puts "\nThe command '#{command_name}' is #{Helpers::Text.bold("unavailable")} because it requires the following gems to be installed: #{(gems_not_installed.join(", "))}"
output.puts "-" output.puts "-"
output.puts "Type `install-command #{name}` to install the required gems and activate this command." output.puts "Type `install-command #{command_name}` to install the required gems and activate this command."
return void return void
end end
if command_options[:argument_required] && args.empty? if command_options[:argument_required] && args.empty?
raise CommandError, "The command '#{name}' requires an argument." raise CommandError, "The command '#{command_name}' requires an argument."
end end
ret = call_with_hooks(*args) ret = call_with_hooks(*args)
@ -506,6 +515,6 @@ class Pry
# gist_method # gist_method
# end # end
# end # end
def process; raise CommandError, "command '#{name}' not implemented" end def process; raise CommandError, "command '#{command_name}' not implemented" end
end end
end end

View file

@ -1,7 +1,7 @@
class Pry class Pry
class NoCommandError < StandardError class NoCommandError < StandardError
def initialize(name, owner) def initialize(match, owner)
super "Command '#{name}' not found in command set #{owner}" super "Command '#{match}' not found in command set #{owner}"
end end
end end
@ -27,8 +27,7 @@ class Pry
end end
# Defines a new Pry command. # Defines a new Pry command.
# @param [String, Regexp] name The name of the command. Can be # @param [String, Regexp] match The start of invocations of this command.
# Regexp as well as String.
# @param [String] description A description of the command. # @param [String] description A description of the command.
# @param [Hash] options The optional configuration parameters. # @param [Hash] options The optional configuration parameters.
# @option options [Boolean] :keep_retval Whether or not to use return value # @option options [Boolean] :keep_retval Whether or not to use return value
@ -43,7 +42,7 @@ class Pry
# executing the command. Defaults to true. # executing the command. Defaults to true.
# @option options [String] :listing The listing name of the # @option options [String] :listing The listing name of the
# command. That is the name by which the command is looked up by # command. That is the name by which the command is looked up by
# help and by show-command. Necessary for regex based commands. # help and by show-command. Necessary for commands with regex matches.
# @option options [Boolean] :use_prefix Whether the command uses # @option options [Boolean] :use_prefix Whether the command uses
# `Pry.config.command_prefix` prefix (if one is defined). Defaults # `Pry.config.command_prefix` prefix (if one is defined). Defaults
# to true. # to true.
@ -80,18 +79,17 @@ class Pry
# # hello john, nice number: 10 # # hello john, nice number: 10
# # pry(main)> help number # # pry(main)> help number
# # number-N regex command # # number-N regex command
def block_command(name, description="No description.", options={}, &block) def block_command(match, description="No description.", options={}, &block)
description, options = ["No description.", description] if description.is_a?(Hash) description, options = ["No description.", description] if description.is_a?(Hash)
options = default_options(name).merge!(options) options = default_options(match).merge!(options)
commands[name] = Pry::BlockCommand.subclass(name, description, options, helper_module, &block) commands[match] = Pry::BlockCommand.subclass(match, description, options, helper_module, &block)
end end
alias_method :command, :block_command alias_method :command, :block_command
# Defines a new Pry command class. # Defines a new Pry command class.
# #
# @param [String, Regexp] name The name of the command. Can be # @param [String, Regexp] match The start of invocations of this command.
# Regexp as well as String.
# @param [String] description A description of the command. # @param [String] description A description of the command.
# @param [Hash] options The optional configuration parameters, see {#command} # @param [Hash] options The optional configuration parameters, see {#command}
# @param &Block The class body's definition. # @param &Block The class body's definition.
@ -113,40 +111,40 @@ class Pry
# end # end
# end # end
# #
def create_command(name, description="No description.", options={}, &block) def create_command(match, description="No description.", options={}, &block)
description, options = ["No description.", description] if description.is_a?(Hash) description, options = ["No description.", description] if description.is_a?(Hash)
options = default_options(name).merge!(options) options = default_options(match).merge!(options)
commands[name] = Pry::ClassCommand.subclass(name, description, options, helper_module, &block) commands[match] = Pry::ClassCommand.subclass(match, description, options, helper_module, &block)
commands[name].class_eval(&block) commands[match].class_eval(&block)
commands[name] commands[match]
end end
# Execute a block of code before a command is invoked. The block also # Execute a block of code before a command is invoked. The block also
# gets access to parameters that will be passed to the command and # gets access to parameters that will be passed to the command and
# is evaluated in the same context. # is evaluated in the same context.
# @param [String, Regexp] name The name of the command. # @param [String, Regexp] search The match or listing of the command.
# @yield The block to be run before the command. # @yield The block to be run before the command.
# @example Display parameter before invoking command # @example Display parameter before invoking command
# Pry.commands.before_command("whereami") do |n| # Pry.commands.before_command("whereami") do |n|
# output.puts "parameter passed was #{n}" # output.puts "parameter passed was #{n}"
# end # end
def before_command(name, &block) def before_command(search, &block)
cmd = find_command_by_name_or_listing(name) cmd = find_command_by_match_or_listing(search)
cmd.hooks[:before].unshift block cmd.hooks[:before].unshift block
end end
# Execute a block of code after a command is invoked. The block also # Execute a block of code after a command is invoked. The block also
# gets access to parameters that will be passed to the command and # gets access to parameters that will be passed to the command and
# is evaluated in the same context. # is evaluated in the same context.
# @param [String, Regexp] name The name of the command. # @param [String, Regexp] search The match or listing of the command.
# @yield The block to be run after the command. # @yield The block to be run after the command.
# @example Display text 'command complete' after invoking command # @example Display text 'command complete' after invoking command
# Pry.commands.after_command("whereami") do |n| # Pry.commands.after_command("whereami") do |n|
# output.puts "command complete!" # output.puts "command complete!"
# end # end
def after_command(name, &block) def after_command(search, &block)
cmd = find_command_by_name_or_listing(name) cmd = find_command_by_match_or_listing(search)
cmd.hooks[:after] << block cmd.hooks[:after] << block
end end
@ -155,11 +153,11 @@ class Pry
end end
# Removes some commands from the set # Removes some commands from the set
# @param [Array<String>] names name of the commands to remove # @param [Array<String>] searches the matches or listings of the commands to remove
def delete(*names) def delete(*searches)
names.each do |name| searches.each do |search|
cmd = find_command_by_name_or_listing(name) cmd = find_command_by_match_or_listing(search)
commands.delete cmd.name commands.delete cmd.match
end end
end end
@ -175,34 +173,34 @@ class Pry
# Imports some commands from a set # Imports some commands from a set
# @param [CommandSet] set Set to import commands from # @param [CommandSet] set Set to import commands from
# @param [Array<String>] names Commands to import # @param [Array<String>] matches Commands to import
def import_from(set, *names) def import_from(set, *matches)
helper_module.send :include, set.helper_module helper_module.send :include, set.helper_module
names.each do |name| matches.each do |match|
cmd = set.find_command_by_name_or_listing(name) cmd = set.find_command_by_match_or_listing(match)
commands[cmd.name] = cmd commands[cmd.match] = cmd
end end
end end
# @param [String, Regexp] name_or_listing The name or listing name # @param [String, Regexp] match_or_listing The match or listing of a command.
# of the command to retrieve. # of the command to retrieve.
# @return [Command] The command object matched. # @return [Command] The command object matched.
def find_command_by_name_or_listing(name_or_listing) def find_command_by_match_or_listing(match_or_listing)
if commands[name_or_listing] if commands[match_or_listing]
cmd = commands[name_or_listing] cmd = commands[match_or_listing]
else else
_, cmd = commands.find { |name, command| command.options[:listing] == name_or_listing } _, cmd = commands.find { |match, command| command.options[:listing] == match_or_listing }
end end
raise ArgumentError, "Cannot find a command with name: '#{name_or_listing}'!" if !cmd raise ArgumentError, "Cannot find a command: '#{match_or_listing}'!" if !cmd
cmd cmd
end end
protected :find_command_by_name_or_listing protected :find_command_by_match_or_listing
# Aliases a command # Aliases a command
# Note that if `desc` parameter is `nil` then the default # Note that if `desc` parameter is `nil` then the default
# description is used. # description is used.
# @param [String, Regex] name The name of the alias (can be a regex). # @param [String, Regex] match The match of the alias (can be a regex).
# @param [String] action The action to be performed (typically # @param [String] action The action to be performed (typically
# another command). # another command).
# @param [Hash] options The optional configuration parameters, # @param [Hash] options The optional configuration parameters,
@ -212,7 +210,7 @@ class Pry
# Pry.config.commands.alias_command "lM", "ls -M" # Pry.config.commands.alias_command "lM", "ls -M"
# @example Pass explicit description (overriding default). # @example Pass explicit description (overriding default).
# Pry.config.commands.alias_command "lM", "ls -M", :desc => "cutiepie" # Pry.config.commands.alias_command "lM", "ls -M", :desc => "cutiepie"
def alias_command(name, action, options={}) def alias_command(match, action, options={})
options = { options = {
:desc => "Alias for `#{action}`", :desc => "Alias for `#{action}`",
}.merge!(options) }.merge!(options)
@ -220,7 +218,7 @@ class Pry
# ensure default description is used if desc is nil # ensure default description is used if desc is nil
desc = options.delete(:desc).to_s desc = options.delete(:desc).to_s
c = block_command name, desc, options do |*args| c = block_command match, desc, options do |*args|
run action, *args run action, *args
end end
@ -229,35 +227,34 @@ class Pry
c c
end end
# Rename a command. Accepts either actual name or listing name for # Rename a command. Accepts either match or listing for the search.
# the `old_name`. #
# `new_name` must be the actual name of the new command. # @param [String, Regexp] new_name The new match for the command.
# @param [String, Regexp] new_name The new name for the command. # @param [String, Regexp] search The command's current match or listing.
# @param [String, Regexp] old_name The command's current name.
# @param [Hash] options The optional configuration parameters, # @param [Hash] options The optional configuration parameters,
# accepts the same as the `command` method, but also allows the # accepts the same as the `command` method, but also allows the
# command description to be passed this way too. # command description to be passed this way too.
# @example Renaming the `ls` command and changing its description. # @example Renaming the `ls` command and changing its description.
# Pry.config.commands.rename "dir", "ls", :description => "DOS friendly ls" # Pry.config.commands.rename "dir", "ls", :description => "DOS friendly ls"
def rename_command(new_name, old_name, options={}) def rename_command(new_match, search, options={})
cmd = find_command_by_name_or_listing(old_name) cmd = find_command_by_match_or_listing(search)
options = { options = {
:listing => new_name, :listing => new_match,
:description => cmd.description :description => cmd.description
}.merge!(options) }.merge!(options)
commands[new_name] = cmd.dup commands[new_match] = cmd.dup
commands[new_name].name = new_name commands[new_match].match = new_match
commands[new_name].description = options.delete(:description) commands[new_match].description = options.delete(:description)
commands[new_name].options.merge!(options) commands[new_match].options.merge!(options)
commands.delete(cmd.name) commands.delete(cmd.match)
end end
# Sets or gets the description for a command (replacing the old # Sets or gets the description for a command (replacing the old
# description). Returns current description if no description # description). Returns current description if no description
# parameter provided. # parameter provided.
# @param [String, Regexp] name The command name. # @param [String, Regexp] match The command match.
# @param [String] description The command description. # @param [String] description The command description.
# @example Setting # @example Setting
# MyCommands = Pry::CommandSet.new do # MyCommands = Pry::CommandSet.new do
@ -265,8 +262,8 @@ class Pry
# end # end
# @example Getting # @example Getting
# Pry.config.commands.desc "amend-line" # Pry.config.commands.desc "amend-line"
def desc(name, description=nil) def desc(search, description=nil)
cmd = find_command_by_name_or_listing(name) cmd = find_command_by_match_or_listing(search)
return cmd.description if !description return cmd.description if !description
cmd.description = description cmd.description = description
@ -308,7 +305,7 @@ class Pry
# @return [Pry::Command, nil] # @return [Pry::Command, nil]
def find_command_for_help(search) def find_command_for_help(search)
find_command(search) || (begin find_command(search) || (begin
find_command_by_name_or_listing(search) find_command_by_match_or_listing(search)
rescue ArgumentError rescue ArgumentError
nil nil
end) end)
@ -339,21 +336,21 @@ class Pry
end end
# @nodoc used for testing # @nodoc used for testing
def run_command(context, name, *args) def run_command(context, match, *args)
command = commands[name] or raise NoCommandError.new(name, self) command = commands[match] or raise NoCommandError.new(match, self)
command.new(context).call_safely(*args) command.new(context).call_safely(*args)
end end
private private
def default_options(name) def default_options(match)
{ {
:requires_gem => [], :requires_gem => [],
:keep_retval => false, :keep_retval => false,
:argument_required => false, :argument_required => false,
:interpolate => true, :interpolate => true,
:shellwords => true, :shellwords => true,
:listing => name, :listing => (String === match ? match : match.inspect),
:use_prefix => true, :use_prefix => true,
:takes_block => false :takes_block => false
} }

View file

@ -127,7 +127,7 @@ describe Pry::CommandSet do
@set.command('foo', 'stuff') { run = true } @set.command('foo', 'stuff') { run = true }
@set.alias_command 'bar', 'foo' @set.alias_command 'bar', 'foo'
@set.commands['bar'].name.should == 'bar' @set.commands['bar'].match.should == 'bar'
@set.commands['bar'].description.should == 'Alias for `foo`' @set.commands['bar'].description.should == 'Alias for `foo`'
@set.run_command @ctx, 'bar' @set.run_command @ctx, 'bar'
@ -139,7 +139,7 @@ describe Pry::CommandSet do
@set.command('foo', 'stuff') { run = true } @set.command('foo', 'stuff') { run = true }
@set.alias_command 'bar', 'foo', :desc => "tobina" @set.alias_command 'bar', 'foo', :desc => "tobina"
@set.commands['bar'].name.should == 'bar' @set.commands['bar'].match.should == 'bar'
@set.commands['bar'].description.should == "tobina" @set.commands['bar'].description.should == "tobina"
@set.run_command @ctx, 'bar' @set.run_command @ctx, 'bar'
@ -151,7 +151,7 @@ describe Pry::CommandSet do
@set.command(/^foo1/, 'stuff', :listing => 'foo') { run = true } @set.command(/^foo1/, 'stuff', :listing => 'foo') { run = true }
@set.alias_command 'bar', 'foo1' @set.alias_command 'bar', 'foo1'
@set.commands['bar'].name.should == 'bar' @set.commands['bar'].match.should == 'bar'
@set.commands['bar'].description.should == 'Alias for `foo1`' @set.commands['bar'].description.should == 'Alias for `foo1`'
@set.run_command @ctx, 'bar' @set.run_command @ctx, 'bar'