add Pry::LastException.

pry adds behavior(methods) to the exception it returns at _pry_.last_exception
in a repl but when the exception has been passed along as a frozen object ruby
will raise an exception and pry fails to function as usual.

the commit changes that behavior so that the exception is wrapped in an instance of
Pry::LastException who is a subclass of BasicObject. Pry::LastException is a copy&paste
of what was defined dynamically in pry_instance.rb but it allows for frozen exceptions
to remain frozen and still provides the methods pry dynamically defined on an exception
object before. through a wrapper class pry also no longer modifies an exception object
that it doesn't own.
This commit is contained in:
Robert Gleeson 2014-03-10 01:28:12 +01:00
parent 90dacb8f25
commit 24bbe12dc2
4 changed files with 67 additions and 19 deletions

View File

@ -184,3 +184,4 @@ require 'pry/terminal'
require 'pry/editor'
require 'pry/rubygem'
require "pry/indent"
require "pry/last_exception"

35
lib/pry/last_exception.rb Normal file
View File

@ -0,0 +1,35 @@
class Pry::LastException < BasicObject
attr_reader :file, :line
attr_accessor :bt_index
def initialize(e)
@e = e
@bt_index = 0
@file, @line = bt_source_location_for(0)
end
def method_missing(name, *args, &block)
if @e.respond_to?(name)
@e.public_send(name, *args, &block)
else
super
end
end
def respond_to_missing?(name, boolean=false)
@e.respond_to?(name)
end
def pry?
true
end
def bt_source_location_for(index)
backtrace[index] =~ /(.*):(\d+)/
[$1, $2.to_i]
end
def inc_bt_index
@bt_index = (@bt_index + 1) % backtrace.size
end
end

View File

@ -467,27 +467,17 @@ class Pry
self.last_result = result unless code =~ /\A\s*\z/
end
#
# Set the last exception for a session.
# @param [Exception] ex
def last_exception=(ex)
class << ex
attr_accessor :file, :line, :bt_index
def bt_source_location_for(index)
backtrace[index] =~ /(.*):(\d+)/
[$1, $2.to_i]
end
def inc_bt_index
@bt_index = (@bt_index + 1) % backtrace.size
end
end
ex.bt_index = 0
ex.file, ex.line = ex.bt_source_location_for(0)
#
# @param [Exception] e
# the last exception.
#
def last_exception=(e)
last_exception = Pry::LastException.new(e)
@last_result_is_exception = true
@output_array << ex
@last_exception = ex
@output_array << last_exception
@last_exception = last_exception
end
# Update Pry's internal state after evalling code.

View File

@ -67,6 +67,28 @@ describe Pry do
end
end
describe "#last_exception=" do
before do
@pry = Pry.new binding: binding
@e = mock_exception "foo.rb:1"
end
it "returns an instance of Pry::LastException" do
@pry.last_exception = @e
should.satisfy { @pry.last_exception.pry? == true }
end
it "returns a frozen exception" do
@pry.last_exception = @e.freeze
@pry.last_exception.should.be.frozen?
end
it "returns an object who mirrors itself as the wrapped exception" do
@pry.last_exception = @e.freeze
@pry.last_exception.should.be.instance_of?(StandardError)
end
end
describe "open a Pry session on an object" do
describe "rep" do
before do