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

added some integration tests for class based commands && renamed Pry::CommandContext:Command#block to #callable

This commit is contained in:
John Mair 2011-12-30 00:07:49 +13:00
parent 1cbe7d4c9c
commit f52626e169
6 changed files with 160 additions and 74 deletions

View file

@ -161,17 +161,19 @@ class Pry
# Execute a Pry command. # Execute a Pry command.
# This method should not need to be invoked directly. # This method should not need to be invoked directly.
# @param [Binding] target The target of the Pry session. # @param [Binding] target The target of the Pry session.
# @param [String] command The name of the command to be run. # @param [Pry::CommandSet::Command] command The command object.
# @param [Hash] options The options to set on the Commands object. # @param [Hash] options The options to set on the Commands object.
# @param [Array] args The command arguments. # @param [Array] args The command arguments.
# @return [Object] The value returned by the command # @return [Object] The value returned by the command
def execute_command(target, command, options, *args) def execute_command(target, command, options, *args)
ret = nil ret = nil
if command.block.is_a?(Proc) if command.callable.is_a?(Proc)
context = CommandContext.new context = CommandContext.new
else else
context = command.block
# in the case of non-procs the callable *is* the context
context = command.callable
end end
# set some useful methods to be used by the action blocks # set some useful methods to be used by the action blocks
@ -187,19 +189,19 @@ class Pry
end end
def setup_context(target, command, context, options) def setup_context(target, command, context, options)
context.opts = options context.opts = options
context.target = target context.target = target
context.target_self = target.eval('self') context.target_self = target.eval('self')
context.output = output context.output = output
context.captures = options[:captures] context.captures = options[:captures]
context.eval_string = options[:eval_string] context.eval_string = options[:eval_string]
context.arg_string = options[:arg_string] context.arg_string = options[:arg_string]
context.command_set = commands context.command_set = commands
context.command_name = command.options[:listing] context.command_name = command.options[:listing]
context._pry_ = @pry_instance context._pry_ = @pry_instance
context.command_processor = self context.command_processor = self
end end
end end
end end

View file

@ -8,17 +8,19 @@ class Pry
# This class is used to create sets of commands. Commands can be imported from # This class is used to create sets of commands. Commands can be imported from
# different sets, aliased, removed, etc. # different sets, aliased, removed, etc.
class CommandSet class CommandSet
class Command < Struct.new(:name, :description, :options, :block) class Command < Struct.new(:name, :description, :options, :callable)
def call(context, *args) def call(context, *args)
if stub_block = options[:stub_info] if stub_block = options[:stub_info]
context.instance_eval(&stub_block) context.instance_eval(&stub_block)
else else
if block.is_a?(Proc) if callable.is_a?(Proc)
ret = context.instance_exec(*correct_arg_arity(block.arity, args), &block) ret = context.instance_exec(*correct_arg_arity(callable.arity, args), &callable)
else else
ret = block.call(*correct_arg_arity(block.method(:call).arity, args))
# in the case of non-procs the callable *is* the context
ret = callable.call(*correct_arg_arity(callable.method(:call).arity, args))
end end
if options[:keep_retval] if options[:keep_retval]
@ -157,13 +159,18 @@ class Pry
# end # end
def before_command(name, &block) def before_command(name, &block)
cmd = find_command_by_name_or_listing(name) cmd = find_command_by_name_or_listing(name)
prev_block = cmd.block prev_callable = cmd.callable
wrapper_block = proc do |*args| wrapper_block = proc do |*args|
instance_exec(*args, &block) instance_exec(*args, &block)
instance_exec(*args, &prev_block)
if prev_callable.is_a?(Proc)
instance_exec(*args, &prev_callable)
else
prev_callable.call(*args)
end
end end
cmd.block = wrapper_block cmd.callable = wrapper_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
@ -177,13 +184,18 @@ class Pry
# end # end
def after_command(name, &block) def after_command(name, &block)
cmd = find_command_by_name_or_listing(name) cmd = find_command_by_name_or_listing(name)
prev_block = cmd.block prev_callable = cmd.callable
wrapper_block = proc do |*args| wrapper_block = proc do |*args|
instance_exec(*args, &prev_block) if prev_callable.is_a?(Proc)
instance_exec(*args, &prev_callable)
else
prev_callable.call(*args)
end
instance_exec(*args, &block) instance_exec(*args, &block)
end end
cmd.block = wrapper_block cmd.callable = wrapper_block
end end
def each &block def each &block
@ -279,6 +291,8 @@ class Pry
# @raise [NoCommandError] If the command is not defined in this set # @raise [NoCommandError] If the command is not defined in this set
def run_command(context, command_name, *args) def run_command(context, command_name, *args)
command = commands[command_name] command = commands[command_name]
context.extend helper_module context.extend helper_module
if command.nil? if command.nil?

View file

@ -69,7 +69,7 @@ class Pry
end end
if find_command(command_name) if find_command(command_name)
block = Pry::Method.new(find_command(command_name).block) block = Pry::Method.new(find_command(command_name).callable)
next unless block.source next unless block.source
set_file_and_dir_locals(block.source_file) set_file_and_dir_locals(block.source_file)

View file

@ -0,0 +1,61 @@
require 'helper'
# integration tests
describe "integration tests for class-based commands" do
before do
@set = Pry::CommandSet.new
end
it 'should invoke a class-based command from the REPL' do
c = Class.new(Pry::CommandContext) do
def call
output.puts "yippee!"
end
end
@set.command 'foo', "desc", :definition => c.new
@set.import_from Pry::Commands, "exit-all"
redirect_pry_io(InputTester.new("foo", "exit-all"), out =StringIO.new) do
Pry.start binding, :commands => @set
end
out.string.should =~ /yippee!/
end
it 'should return specified value with :keep_retval => true' do
c = Class.new(Pry::CommandContext) do
def call
:i_enjoyed_the_song_new_flame_by_simply_red_as_a_child_wandering_around_supermarkets
end
end
@set.command 'foo', "desc", :keep_retval => true, :definition => c.new
@set.import_from Pry::Commands, "exit-all"
redirect_pry_io(InputTester.new("foo", "exit-all"), out =StringIO.new) do
Pry.start binding, :commands => @set
end
out.string.should =~ /i_enjoyed_the_song_new_flame_by_simply_red_as_a_child_wandering_around_supermarkets/
end
it 'should NOT return specified value with :keep_retval => false' do
c = Class.new(Pry::CommandContext) do
def call
:i_enjoyed_the_song_new_flame_by_simply_red_as_a_child_wandering_around_supermarkets
end
end
@set.command 'foo', "desc", :keep_retval => false, :definition => c.new
@set.import_from Pry::Commands, "exit-all"
redirect_pry_io(InputTester.new("foo", "exit-all"), out =StringIO.new) do
Pry.start binding, :commands => @set
end
out.string.should !~ /i_enjoyed_the_song_new_flame_by_simply_red_as_a_child_wandering_around_supermarkets/
end
end

View file

@ -376,7 +376,7 @@ describe Pry::CommandSet do
it 'should share the context with the original command' do it 'should share the context with the original command' do
@ctx.target = "test target string" @ctx.target = "test target string"
after_val = nil after_val = nil
orig_val = nil orig_val = nil
@set.command('foo') { orig_val = target } @set.command('foo') { orig_val = target }
@set.after_command('foo') { after_val = target } @set.after_command('foo') { after_val = target }
@ -429,7 +429,7 @@ describe Pry::CommandSet do
@set.command 'foo', "desc", :definition => c.new @set.command 'foo', "desc", :definition => c.new
ctx = @set.commands['foo'].block ctx = @set.commands['foo'].callable
@set.run_command ctx, 'foo', 1, 2, 3 @set.run_command ctx, 'foo', 1, 2, 3
end end
@ -444,7 +444,7 @@ describe Pry::CommandSet do
@set.command 'foo', "desc", :definition => c.new @set.command 'foo', "desc", :definition => c.new
ctx = @set.commands['foo'].block ctx = @set.commands['foo'].callable
@set.run_command ctx, 'foo', 1 @set.run_command ctx, 'foo', 1
end end
@ -458,7 +458,7 @@ describe Pry::CommandSet do
@set.command 'foo', "desc", :definition => c.new @set.command 'foo', "desc", :definition => c.new
ctx = @set.commands['foo'].block ctx = @set.commands['foo'].callable
@set.run_command ctx, 'foo', 1, 2, 3, 4 @set.run_command ctx, 'foo', 1, 2, 3, 4
end end
@ -471,7 +471,7 @@ describe Pry::CommandSet do
@set.command 'foo', "desc", :definition => c.new @set.command 'foo', "desc", :definition => c.new
ctx = @set.commands['foo'].block ctx = @set.commands['foo'].callable
@set.run_command(ctx, 'foo').should == Pry::CommandContext::VOID_VALUE @set.run_command(ctx, 'foo').should == Pry::CommandContext::VOID_VALUE
end end
@ -484,7 +484,7 @@ describe Pry::CommandSet do
@set.command 'foo', "desc", :keep_retval => true, :definition => c.new @set.command 'foo', "desc", :keep_retval => true, :definition => c.new
ctx = @set.commands['foo'].block ctx = @set.commands['foo'].callable
@set.run_command(ctx, 'foo').should == :i_have_a_dog_called_tobina @set.run_command(ctx, 'foo').should == :i_have_a_dog_called_tobina
end end
@ -503,7 +503,7 @@ describe Pry::CommandSet do
end end
end end
ctx = @set.commands['foo'].block ctx = @set.commands['foo'].callable
@set.run_command ctx, 'foo' @set.run_command ctx, 'foo'
end end
@ -518,7 +518,7 @@ describe Pry::CommandSet do
@set.command 'foo', "desc", :definition => c.new @set.command 'foo', "desc", :definition => c.new
ctx = @set.commands['foo'].block ctx = @set.commands['foo'].callable
@set.run_command ctx, 'foo' @set.run_command ctx, 'foo'
@set.run_command ctx, 'foo' @set.run_command ctx, 'foo'
ctx.state.should == 2 ctx.state.should == 2
@ -535,7 +535,7 @@ describe Pry::CommandSet do
@set.command 'foo', "desc", :definition => c.new @set.command 'foo', "desc", :definition => c.new
ctx = @set.commands['foo'].block ctx = @set.commands['foo'].callable
@set.before_command('foo') { foo << 2 } @set.before_command('foo') { foo << 2 }
@set.run_command(ctx, 'foo') @set.run_command(ctx, 'foo')
@ -543,5 +543,24 @@ describe Pry::CommandSet do
end end
end end
describe "after_command" do
it 'should be called before the original command' do
foo = []
c = Class.new(Pry::CommandContext) do
define_method(:call) do
foo << 1
end
end
@set.command 'foo', "desc", :definition => c.new
ctx = @set.commands['foo'].callable
@set.after_command('foo') { foo << 2 }
@set.run_command(ctx, 'foo')
foo.should == [1, 2]
end
end
end end
end end

View file

@ -2,16 +2,6 @@ require 'helper'
describe Pry do describe Pry do
# if RUBY_PLATFORM !~ /mingw/ && RUBY_PLATFORM !~ /mswin/ && RUBY_PLATFORM != 'java'
# describe 'warning emissions' do
# it 'should emit no warnings' do
# Open4.popen4 'ruby -I lib -rubygems -r"pry" -W -e "exit"' do |pid, stdin, stdout, stderr|
# stderr.read.empty?.should == true
# end
# end
# end
# end
if RUBY_VERSION =~ /1.9/ if RUBY_VERSION =~ /1.9/
describe "Exotic object support" do describe "Exotic object support" do
# regression test for exotic object support # regression test for exotic object support
@ -792,7 +782,7 @@ describe Pry do
str_output = StringIO.new str_output = StringIO.new
Pry.new(:input => StringIO.new("hello\n"), :output => str_output, :commands => klass).rep Pry.new(:input => StringIO.new("hello\n"), :output => str_output, :commands => klass).rep
str_output.string.should =~ /nil/ str_output.string.should =~ /nil/
str_output.string.should =~ /=>/ str_output.string.should =~ /=>/
end end
it 'should define a command that keeps its return value but does not return when value is void' do it 'should define a command that keeps its return value but does not return when value is void' do
@ -806,7 +796,7 @@ describe Pry do
str_output.string.empty?.should == true str_output.string.empty?.should == true
end end
it 'a command (with :keep_retval => false) that replaces eval_string with a valid expression should not have the expression value suppressed' do it 'a command (with :keep_retval => false) that replaces eval_string with a valid expression should not have the expression value suppressed' do
klass = Pry::CommandSet.new do klass = Pry::CommandSet.new do
command "hello", "" do command "hello", "" do
eval_string.replace("6") eval_string.replace("6")
@ -818,45 +808,45 @@ describe Pry do
end end
it 'a command (with :keep_retval => true) that replaces eval_string with a valid expression should overwrite the eval_string with the return value' do it 'a command (with :keep_retval => true) that replaces eval_string with a valid expression should overwrite the eval_string with the return value' do
klass = Pry::CommandSet.new do klass = Pry::CommandSet.new do
command "hello", "", :keep_retval => true do command "hello", "", :keep_retval => true do
eval_string.replace("6") eval_string.replace("6")
7 7
end
end end
end str_output = StringIO.new
str_output = StringIO.new Pry.new(:input => StringIO.new("def yo\nhello\n"), :output => str_output, :commands => klass).rep
Pry.new(:input => StringIO.new("def yo\nhello\n"), :output => str_output, :commands => klass).rep
str_output.string.should =~ /7/ str_output.string.should =~ /7/
str_output.string.should.not =~ /6/ str_output.string.should.not =~ /6/
end end
it 'a command that return a value in a multi-line expression should clear the expression and return the value' do it 'a command that return a value in a multi-line expression should clear the expression and return the value' do
klass = Pry::CommandSet.new do klass = Pry::CommandSet.new do
command "hello", "", :keep_retval => true do command "hello", "", :keep_retval => true do
5 5
end end
end
str_output = StringIO.new
Pry.new(:input => StringIO.new("def yo\nhello\n"), :output => str_output, :commands => klass).rep
str_output.string.should =~ /5/
end
it 'should set the commands default, and the default should be overridable' do
klass = Pry::CommandSet.new do
command "hello" do
output.puts "hello world"
end end
str_output = StringIO.new
Pry.new(:input => StringIO.new("def yo\nhello\n"), :output => str_output, :commands => klass).rep
str_output.string.should =~ /5/
end end
Pry.commands = klass
str_output = StringIO.new it 'should set the commands default, and the default should be overridable' do
Pry.new(:input => InputTester.new("hello"), :output => str_output).rep klass = Pry::CommandSet.new do
str_output.string.should =~ /hello world/ command "hello" do
output.puts "hello world"
end
end
other_klass = Pry::CommandSet.new do Pry.commands = klass
str_output = StringIO.new
Pry.new(:input => InputTester.new("hello"), :output => str_output).rep
str_output.string.should =~ /hello world/
other_klass = Pry::CommandSet.new do
command "goodbye", "" do command "goodbye", "" do
output.puts "goodbye world" output.puts "goodbye world"
end end
@ -896,7 +886,7 @@ describe Pry do
klass = Pry::CommandSet.new do klass = Pry::CommandSet.new do
alias_command "help2", "help" alias_command "help2", "help"
end end
klass.commands["help2"].block.should == klass.commands["help"].block klass.commands["help2"].callable.should == klass.commands["help"].callable
end end
it 'should change description of a command using desc' do it 'should change description of a command using desc' do
@ -1312,7 +1302,7 @@ describe Pry do
str_output = StringIO.new str_output = StringIO.new
Pry.new(:output => str_output, Pry.new(:output => str_output,
:hooks => Pry::Hooks.new. :hooks => Pry::Hooks.new.
add_hook(:before_session, :my_name) { |out,_,_| out.puts "OPEN" } add_hook(:before_session, :my_name) { |out,_,_| out.puts "OPEN" }
).repl ).repl
str_output.string.should =~ /OPEN/ str_output.string.should =~ /OPEN/
@ -1321,7 +1311,7 @@ describe Pry do
str_output = StringIO.new str_output = StringIO.new
Pry.new(:output => str_output, Pry.new(:output => str_output,
:hooks => Pry::Hooks.new. :hooks => Pry::Hooks.new.
add_hook(:after_session, :my_name) { |out,_,_| out.puts "CLOSE" } add_hook(:after_session, :my_name) { |out,_,_| out.puts "CLOSE" }
).repl ).repl
str_output.string.should =~ /CLOSE/ str_output.string.should =~ /CLOSE/