Last active
January 1, 2016 18:59
-
-
Save timuruski/8187571 to your computer and use it in GitHub Desktop.
Nested exception mixin for Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Adapted from from: http://nestegg.rubyforge.org/ | |
module NestedException | |
# Public: Initializes a new nested error, the original error defaults | |
# to the global error variable so that it doesn't need to be explicity | |
# provided when re-raising an exception. | |
def initialize(message = nil, cause = $!) | |
@cause = cause | |
super(message || cause && cause.message) | |
end | |
attr_reader :cause | |
def set_backtrace(new_backtrace) | |
if cause | |
last_line = new_backtrace.last | |
cause_lines = cause.backtrace.take_while { |line| line != last_line } | |
cause_lines << last_line | |
new_backtrace << "cause: #{cause.class.name}: #{cause}" | |
new_backtrace.concat(cause_lines) | |
end | |
super(new_backtrace) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'nested_exception' | |
describe NestedException do | |
# Helper to test re-raising a nested exception, it returns the result | |
# of the block so it can be examined with assertions. | |
def raise_nested(cause) | |
begin | |
fail cause | |
rescue => original_error | |
raise yield original_error | |
end | |
rescue => yielded_error | |
return yielded_error | |
end | |
let(:original) { RuntimeError.new('Born to fail ') } | |
let(:nested_exception) { | |
Class.new(StandardError) do | |
include NestedException | |
end | |
} | |
it 'defaults to details about the original exception' do | |
reraised = raise_nested(original) do |_| | |
nested_exception.new | |
end | |
expect(reraised.message).to eq original.message | |
expect(reraised.cause).to eq original | |
end | |
it 'includes part of the original backtrace' do | |
reraised = raise_nested(original) do |_| | |
nested_exception.new | |
end | |
expect(reraised.backtrace).to include(*original.backtrace) | |
end | |
it 'accepts a specific error message' do | |
reraised = raise_nested(original) do |_| | |
nested_exception.new('Alternate message') | |
end | |
expect(reraised.message).to eq 'Alternate message' | |
end | |
it 'does not prevent overriding params for initialize' do | |
nested_exception = Class.new(StandardError) do | |
attr_reader :user | |
def initialize(user, original) | |
super(original.message) | |
@user = user | |
end | |
end | |
reraised = raise_nested(original) do |error| | |
nested_exception.new('Alice', error) | |
end | |
expect(reraised.user).to eq 'Alice' | |
expect(reraised.message).to eq original.message | |
expect(reraised.cause).to eq original | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment