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

Make all the tests pass again

This commit is contained in:
Conrad Irwin 2011-12-31 11:10:23 +00:00
parent 689e47899b
commit 2b6d0d2149
5 changed files with 85 additions and 280 deletions

View file

@ -145,15 +145,20 @@ class Pry
args = []
end
options = {
context = {
:val => val,
:arg_string => arg_string,
:eval_string => eval_string,
:commands => commands.commands,
:captures => captures
:captures => captures,
:pry_instance => @pry_instance,
:output => output,
:command_processor => self,
:command_set => commands,
:target => target
}
ret = execute_command(target, command, options, *(captures + args))
ret = execute_command(command, context, *(captures + args))
Result.new(true, command.options[:keep_retval], ret)
end
@ -165,40 +170,19 @@ class Pry
# @param [Hash] options The options to set on the Commands object.
# @param [Array] args The command arguments.
# @return [Object] The value returned by the command
def execute_command(target, command, options, *args)
def execute_command(command, context, *args)
ret = nil
# allocate, setup and then call initialize so that authors
# can do their own setup in initialize.
context = command.allocate
setup_context(target, command, context, options)
context.extend commands.helper_module
context.send(:initialize)
instance = command.new(context)
catch(:command_done) do
ret = context.call(*args)
ret = instance.call_with_hooks(*args)
end
# FIXME: wtf?
options[:val].replace("")
context[:val].replace("")
ret
end
def setup_context(target, command, context, options)
context.opts = options
context.target = target
context.target_self = target.eval('self')
context.output = output
context.captures = options[:captures]
context.eval_string = options[:eval_string]
context.arg_string = options[:arg_string]
context.command_set = commands
context.command_name = command.options[:listing]
context._pry_ = @pry_instance
context.command_processor = self
end
end
end

View file

@ -18,23 +18,58 @@ class Pry
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}>"
"#<class(Pry command #{name.inspect})>"
end
def subclass(name, description, options, &block)
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_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
self.class.options[:keep_retval] ? ret : CommandContext::VOID_VALUE
end
end
@ -49,6 +84,9 @@ class Pry
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."
@ -75,6 +113,8 @@ class Pry
attr_accessor :args
def call(*args)
setup
self.opts = slop
self.args = self.opts.parse!(args)
@ -85,7 +125,9 @@ class Pry
end
end
def setup; end
def options(opt); end
def run; raise CommandError, "command '#{name}' not implemented" end
def slop
Slop.new do |opt|
@ -94,7 +136,6 @@ class Pry
end
end
def run; raise CommandError, "command '#{name}' not implemented" end
end
include Enumerable
@ -182,9 +223,9 @@ class Pry
}.merge!(options)
if command_dependencies_met? options
commands[name] = BlockCommand.subclass(name, description, options, &block)
commands[name] = BlockCommand.subclass(name, description, options, helper_module, &block)
else
commands[name] = StubCommand.subclass(name, description, options)
commands[name] = StubCommand.subclass(name, description, options, helper_module)
end
end
@ -200,10 +241,10 @@ class Pry
}.merge!(options)
if command_dependencies_met? options
commands[name] = ClassCommand.subclass(name, description, options)
commands[name] = ClassCommand.subclass(name, description, options, helper_module)
commands[name].class_eval(&block)
else
commands[name] = StubCommand.subclass(name, description, options)
commands[name] = StubCommand.subclass(name, description, options, helper_module)
end
end
@ -218,18 +259,7 @@ class Pry
# end
def before_command(name, &block)
cmd = find_command_by_name_or_listing(name)
prev_callable = cmd.callable
wrapper_block = proc do |*args|
instance_exec(*args, &block)
if prev_callable.is_a?(Proc)
instance_exec(*args, &prev_callable)
else
prev_callable.call(*args)
end
end
cmd.callable = wrapper_block
cmd.hooks[:before].unshift block
end
# Execute a block of code after a command is invoked. The block also
@ -243,18 +273,7 @@ class Pry
# end
def after_command(name, &block)
cmd = find_command_by_name_or_listing(name)
prev_callable = cmd.callable
wrapper_block = proc do |*args|
if prev_callable.is_a?(Proc)
instance_exec(*args, &prev_callable)
else
prev_callable.call(*args)
end
instance_exec(*args, &block)
end
cmd.callable = wrapper_block
cmd.hooks[:after] << block
end
def each &block
@ -382,6 +401,11 @@ class Pry
commands.keys
end
def run_command(context, name, *args)
command = commands[name] or raise NoCommandError.new(name, self)
command.new(context).call_with_hooks(*args)
end
private
def define_default_commands

View file

@ -1,61 +0,0 @@
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.not =~ /i_enjoyed_the_song_new_flame_by_simply_red_as_a_child_wandering_around_supermarkets/
end
end

View file

@ -3,7 +3,10 @@ require 'helper'
describe Pry::CommandSet do
before do
@set = Pry::CommandSet.new
@ctx = Pry::CommandContext.new
@ctx = {
:target => binding,
:command_set => @set
}
end
it 'should call the block used for the command when it is called' do
@ -24,11 +27,11 @@ describe Pry::CommandSet do
@set.run_command @ctx, 'foo', 1, 2, 3
end
it 'should use the first argument as self' do
it 'should use the first argument as context' do
ctx = @ctx
@set.command 'foo' do
self.should == ctx
self.context.should == ctx
end
@set.run_command @ctx, 'foo'
@ -241,8 +244,8 @@ describe Pry::CommandSet do
end
it "should provide a 'help' command" do
@ctx.command_set = @set
@ctx.output = StringIO.new
@ctx[:command_set] = @set
@ctx[:output] = StringIO.new
lambda {
@set.run_command(@ctx, 'help')
@ -255,12 +258,12 @@ describe Pry::CommandSet do
@set.command 'moo', "Mooerizes" do; end
@set.command 'boo', "Booerizes" do; end
@ctx.command_set = @set
@ctx.output = StringIO.new
@ctx[:command_set] = @set
@ctx[:output] = StringIO.new
@set.run_command(@ctx, 'help')
doc = @ctx.output.string
doc = @ctx[:output].string
order = [doc.index("boo"),
doc.index("foo"),
@ -331,15 +334,15 @@ describe Pry::CommandSet do
end
it 'should share the context with the original command' do
@ctx.target = "test target string"
@ctx[:target] = "test target string".__binding__
before_val = nil
orig_val = nil
@set.command('foo') { orig_val = target }
@set.before_command('foo') { before_val = target }
@set.run_command(@ctx, 'foo')
before_val.should == @ctx.target
orig_val.should == @ctx.target
before_val.should == @ctx[:target]
orig_val.should == @ctx[:target]
end
it 'should work when applied multiple times' do
@ -375,15 +378,15 @@ describe Pry::CommandSet do
end
it 'should share the context with the original command' do
@ctx.target = "test target string"
@ctx[:target] = "test target string".__binding__
after_val = nil
orig_val = nil
@set.command('foo') { orig_val = target }
@set.after_command('foo') { after_val = target }
@set.run_command(@ctx, 'foo')
after_val.should == @ctx.target
orig_val.should == @ctx.target
after_val.should == @ctx[:target]
orig_val.should == @ctx[:target]
end
it 'should determine the return value for the command' do
@ -418,149 +421,4 @@ describe Pry::CommandSet do
end
end
describe "class-based commands" do
it 'should pass arguments to the command' do
c = Class.new(Pry::CommandContext) do
def call(*args)
args.should == [1, 2, 3]
end
end
@set.command 'foo', "desc", :definition => c.new
ctx = @set.commands['foo'].callable
@set.run_command ctx, 'foo', 1, 2, 3
end
it 'should set unprovided arguments to nil' do
c = Class.new(Pry::CommandContext) do
def call(x, y, z)
x.should == 1
y.should == nil
z.should == nil
end
end
@set.command 'foo', "desc", :definition => c.new
ctx = @set.commands['foo'].callable
@set.run_command ctx, 'foo', 1
end
it 'should clip provided arguments to expected number' do
c = Class.new(Pry::CommandContext) do
def call(x, y, z)
x.should == 1
y.should == 2
end
end
@set.command 'foo', "desc", :definition => c.new
ctx = @set.commands['foo'].callable
@set.run_command ctx, 'foo', 1, 2, 3, 4
end
it 'should return Pry::CommandContext::VOID by default' do
c = Class.new(Pry::CommandContext) do
def call
:i_have_done_thing_i_regret
end
end
@set.command 'foo', "desc", :definition => c.new
ctx = @set.commands['foo'].callable
@set.run_command(ctx, 'foo').should == Pry::CommandContext::VOID_VALUE
end
it 'should return specific value when :keep_retval => true' do
c = Class.new(Pry::CommandContext) do
def call
:i_have_a_dog_called_tobina
end
end
@set.command 'foo', "desc", :keep_retval => true, :definition => c.new
ctx = @set.commands['foo'].callable
@set.run_command(ctx, 'foo').should == :i_have_a_dog_called_tobina
end
it 'should have access to helper methods' do
c = Class.new(Pry::CommandContext) do
def call
im_helping.should == "butterbum"
end
end
@set.command 'foo', "desc", :definition => c.new
@set.helpers do
def im_helping
"butterbum"
end
end
ctx = @set.commands['foo'].callable
@set.run_command ctx, 'foo'
end
it 'should persist state' do
c = Class.new(Pry::CommandContext) do
attr_accessor :state
def call
@state ||= 0
@state += 1
end
end
@set.command 'foo', "desc", :definition => c.new
ctx = @set.commands['foo'].callable
@set.run_command ctx, 'foo'
@set.run_command ctx, 'foo'
ctx.state.should == 2
end
describe "before_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.before_command('foo') { foo << 2 }
@set.run_command(ctx, 'foo')
foo.should == [2, 1]
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

View file

@ -886,7 +886,7 @@ describe Pry do
klass = Pry::CommandSet.new do
alias_command "help2", "help"
end
klass.commands["help2"].callable.should == klass.commands["help"].callable
klass.commands["help2"].block.should == klass.commands["help"].block
end
it 'should change description of a command using desc' do