Merge Pry::CommandContext and Pry::CommandSet::Command into Pry::Command

This commit is contained in:
Conrad Irwin 2011-12-31 11:50:04 +00:00
parent b6c01c92c4
commit d221a22d02
10 changed files with 202 additions and 207 deletions

View File

@ -184,9 +184,9 @@ require "pry/wrapped_module"
require "pry/history_array"
require "pry/helpers"
require "pry/history"
require "pry/command"
require "pry/command_set"
require "pry/commands"
require "pry/command_context"
require "pry/custom_completions"
require "pry/completion"
require "pry/plugins"

191
lib/pry/command.rb Normal file
View File

@ -0,0 +1,191 @@
class Pry
# Command contexts are the objects runing each command.
# Helper modules can be mixed into this class.
class Command
# represents a void return value for a command
VOID_VALUE = Object.new
# give it a nice inspect
def VOID_VALUE.inspect() "void" end
class << self
attr_accessor :name
attr_accessor :description
attr_accessor :options
attr_accessor :block
end
attr_accessor :command_name
attr_accessor :output
attr_accessor :target
attr_accessor :target_self
attr_accessor :captures
attr_accessor :eval_string
attr_accessor :arg_string
attr_accessor :opts
attr_accessor :command_set
attr_accessor :command_processor
attr_accessor :_pry_
def initialize(&block)
instance_exec(&block) if block
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"'
def run(command_string, *args)
complete_string = "#{command_string} #{args.join(" ")}"
command_processor.process_commands(complete_string, eval_string, target)
end
def commands
command_set.commands
end
def text
Pry::Helpers::Text
end
def void
VOID_VALUE
end
include Pry::Helpers::BaseHelpers
include Pry::Helpers::CommandHelpers
attr_accessor :context
%w(name description options block).each do |attribute|
define_method(attribute) { self.class.send(attribute) }
end
class << self
def inspect
"#<class(Pry command #{name.inspect})>"
end
def subclass(name, description, options, helpers, &block)
klass = Class.new(self)
klass.send(:include, helpers)
klass.name = name
klass.description = description
klass.options = options
klass.block = block
klass
end
def hooks
@hooks ||= {:before => [], :after => []}
end
end
def initialize(context)
self.context = context
self.target = context[:target]
self.target_self = context[:target].eval('self')
self.output = context[:output]
self.captures = context[:captures]
self.eval_string = context[:eval_string]
self.arg_string = context[:arg_string]
self.command_set = context[:command_set]
self.command_name = self.class.options[:listing]
self._pry_ = context[:pry_instance]
self.command_processor = context[:command_processor]
end
def call_safely(*args)
if dependencies_met?
call_with_hooks(*args)
else
gems_needed = Array(command_options[:requires_gem])
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 "-"
output.puts "Type `install-command #{name}` to install the required gems and activate this command."
end
end
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
command_options[:keep_retval] ? ret : void
end
def command_options; self.class.options; end
def dependencies_met?
@dependencies_met ||= command_dependencies_met?(command_options)
end
end
class BlockCommand < Command
# backwards compatibility
alias_method :opts, :context
def call(*args)
if options[:argument_required] && args.empty?
raise CommandError, "The command '#{command.name}' requires an argument."
end
instance_exec(*correct_arg_arity(block.arity, args), &block)
end
private
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
end
class ClassCommand < Command
attr_accessor :opts
attr_accessor :args
def call(*args)
setup
self.opts = slop
self.args = self.opts.parse!(args)
if opts.present?(:help)
output.puts slop.help
else
run
end
end
def setup; end
def options(opt); end
def run; raise CommandError, "command '#{name}' not implemented" end
def slop
Slop.new do |opt|
options(opt)
opt.on(:h, :help, "Show this message.")
end
end
end
end

View File

@ -1,57 +0,0 @@
class Pry
# Command contexts are the objects runing each command.
# Helper modules can be mixed into this class.
class CommandContext
# represents a void return value for a command
VOID_VALUE = Object.new
# give it a nice inspect
def VOID_VALUE.inspect() "void" end
attr_accessor :command_name
attr_accessor :output
attr_accessor :target
attr_accessor :target_self
attr_accessor :captures
attr_accessor :eval_string
attr_accessor :arg_string
attr_accessor :opts
attr_accessor :command_set
attr_accessor :command_processor
attr_accessor :_pry_
def initialize(&block)
instance_exec(&block) if block
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"'
def run(command_string, *args)
complete_string = "#{command_string} #{args.join(" ")}"
command_processor.process_commands(complete_string, eval_string, target)
end
def commands
command_set.commands
end
def text
Pry::Helpers::Text
end
def void
VOID_VALUE
end
include Pry::Helpers::BaseHelpers
include Pry::Helpers::CommandHelpers
end
end

View File

@ -22,7 +22,7 @@ class Pry
# (one that does not return a value)
# @return [Boolean]
def void_command?
(command? && !keep_retval?) || retval == CommandContext::VOID_VALUE
(command? && !keep_retval?) || retval == Command::VOID_VALUE
end
# Is the return value kept for this command? (i.e :keep_retval => true)

View File

@ -1,4 +1,3 @@
require 'pry/command_context'
class Pry
class NoCommandError < StandardError
def initialize(name, owner)
@ -9,142 +8,6 @@ class Pry
# This class is used to create sets of commands. Commands can be imported from
# different sets, aliased, removed, etc.
class CommandSet
class Command < Pry::CommandContext
class << self
attr_accessor :name
attr_accessor :description
attr_accessor :options
attr_accessor :block
end
attr_accessor :context
%w(name description options block).each do |attribute|
define_method(attribute) { self.class.send(attribute) }
end
class << self
def inspect
"#<class(Pry command #{name.inspect})>"
end
def subclass(name, description, options, helpers, &block)
klass = Class.new(self)
klass.send(:include, helpers)
klass.name = name
klass.description = description
klass.options = options
klass.block = block
klass
end
def hooks
@hooks ||= {:before => [], :after => []}
end
end
def initialize(context)
self.context = context
self.target = context[:target]
self.target_self = context[:target].eval('self')
self.output = context[:output]
self.captures = context[:captures]
self.eval_string = context[:eval_string]
self.arg_string = context[:arg_string]
self.command_set = context[:command_set]
self.command_name = self.class.options[:listing]
self._pry_ = context[:pry_instance]
self.command_processor = context[:command_processor]
end
def call_safely(*args)
if dependencies_met?
call_with_hooks(*args)
else
gems_needed = Array(command_options[:requires_gem])
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 "-"
output.puts "Type `install-command #{name}` to install the required gems and activate this command."
end
end
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
command_options[:keep_retval] ? ret : CommandContext::VOID_VALUE
end
def command_options; self.class.options; end
def dependencies_met?
@dependencies_met ||= command_dependencies_met?(command_options)
end
end
class BlockCommand < Command
# backwards compatibility
alias_method :opts, :context
def call(*args)
if options[:argument_required] && args.empty?
raise CommandError, "The command '#{command.name}' requires an argument."
end
instance_exec(*correct_arg_arity(block.arity, args), &block)
end
private
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
end
class ClassCommand < Command
attr_accessor :opts
attr_accessor :args
def call(*args)
setup
self.opts = slop
self.args = self.opts.parse!(args)
if opts.present?(:help)
output.puts slop.help
else
run
end
end
def setup; end
def options(opt); end
def run; raise CommandError, "command '#{name}' not implemented" end
def slop
Slop.new do |opt|
options(opt)
opt.on(:h, :help, "Show this message.")
end
end
end
include Enumerable
include Pry::Helpers::BaseHelpers
@ -229,7 +92,7 @@ class Pry
:use_prefix => true
}.merge!(options)
commands[name] = BlockCommand.subclass(name, description, options, helper_module, &block)
commands[name] = Pry::BlockCommand.subclass(name, description, options, helper_module, &block)
end
def command_class(name, description="No description.", options={}, &block)
@ -243,7 +106,7 @@ class Pry
:use_prefix => true
}.merge!(options)
commands[name] = ClassCommand.subclass(name, description, options, helper_module)
commands[name] = Pry::ClassCommand.subclass(name, description, options, helper_module)
commands[name].class_eval(&block)
commands[name]
end

View File

@ -55,8 +55,6 @@ class Pry
EOS
end
require 'pry/command_context'
command_class "gist", "Gist a method or expression history to github. Type `gist --help` for more info.", :requires_gem => "gist", :shellwords => false do
attr_accessor :content
attr_accessor :code_type

View File

@ -1,7 +1,7 @@
class Pry
module Helpers
# The methods defined on {Text} are available to custom commands via {Pry::CommandContext#text}.
# The methods defined on {Text} are available to custom commands via {Pry::Command#text}.
module Text
COLORS =

View File

@ -378,12 +378,12 @@ class Pry
# @param [String] val The command (and its params) to execute.
# @param [String] eval_string The current input buffer.
# @param [Binding] target The binding to use..
# @return [Pry::CommandContext::VOID_VALUE]
# @return [Pry::Command::VOID_VALUE]
# @example
# pry_instance.run_command("ls -m")
def run_command(val, eval_string = "", target = binding_stack.last)
@command_processor.process_commands(val, eval_string, target)
Pry::CommandContext::VOID_VALUE
Pry::Command::VOID_VALUE
end
# Set the last result of an eval.

View File

@ -162,9 +162,9 @@ describe Pry::CommandSet do
@set.desc('foo').should == 'bar'
end
it 'should return Pry::CommandContext::VOID_VALUE for commands by default' do
it 'should return Pry::Command::VOID_VALUE for commands by default' do
@set.command('foo') { 3 }
@set.run_command(@ctx, 'foo').should == Pry::CommandContext::VOID_VALUE
@set.run_command(@ctx, 'foo').should == Pry::Command::VOID_VALUE
end
it 'should be able to keep return values' do
@ -187,7 +187,7 @@ describe Pry::CommandSet do
end
@set.run_command(@ctx, 'foo')
Pry::CommandContext.new.should.not.respond_to :my_helper
Pry::Command.subclass('foo', '', {}, Module.new).new({:target => binding}).should.not.respond_to :my_helper
end
it 'should not recreate a new helper module when helpers is called' do

View File

@ -43,7 +43,7 @@ describe Pry do
# bug fix for https://github.com/banister/pry/issues/93
it 'should not leak pry constants into Object namespace' do
input_string = "CommandContext"
input_string = "Command"
str_output = StringIO.new
o = Object.new
pry_tester = Pry.new(:input => StringIO.new(input_string),