Project

General

Profile

Feature #5818 ยป raiseable.diff

kstephens (Kurt Stephens), 12/28/2011 08:17 AM

View differences:

error.c
}
/* exception classes */
VALUE rb_mRaiseable;
VALUE rb_eException;
VALUE rb_eSystemExit;
VALUE rb_eInterrupt;
......
void
Init_Exception(void)
{
rb_eException = rb_define_class("Exception", rb_cObject);
rb_mRaiseable =
rb_eException = rb_define_module("Raiseable");
// rb_eException = rb_define_class("Exception", rb_cObject);
rb_define_singleton_method(rb_eException, "exception", rb_class_new_instance, -1);
rb_define_method(rb_eException, "exception", exc_exception, -1);
rb_define_method(rb_eException, "initialize", exc_initialize, -1);
......
rb_define_method(rb_eException, "backtrace", exc_backtrace, 0);
rb_define_method(rb_eException, "set_backtrace", exc_set_backtrace, 1);
rb_eException = rb_define_class("Exception", rb_cObject);
rb_define_singleton_method(rb_eException, "exception", rb_class_new_instance, -1);
rb_include_module(rb_eException, rb_mRaiseable);
rb_eSystemExit = rb_define_class("SystemExit", rb_eException);
rb_define_method(rb_eSystemExit, "initialize", exit_initialize, -1);
rb_define_method(rb_eSystemExit, "status", exit_status, 0);
eval.c
break;
}
if (argc > 0) {
if (!rb_obj_is_kind_of(mesg, rb_eException))
extern VALUE rb_mRaiseable;
if (!rb_obj_is_kind_of(mesg, rb_mRaiseable))
rb_raise(rb_eTypeError, "exception object expected");
if (argc > 2)
set_backtrace(mesg, argv[2]);
test/ruby/test_raiseable.rb
=begin
Feature: Raiseable
= Proposal
The ability to raise any object that is a Raiseable.
= Problem
* The Exception subclass hierarchy is well-established.
* CRuby does not allow any object that behaves as an Exception to be raised, it must be a subclass of Exception.
* 3rd-party code often rescues Exception; e.g. for error recovery, retry and/or logging.
* Users need the ability to raise objects that would not normally be rescued by *any* code;
e.g.: hard timeouts or custom signal handlers in an application.
= Solution
* A "Raiseable" module implements all of the methods currently defined in Exception.
* Exception class includes Raiseable module.
* ruby/eval.c: make_exception() asserts rb_obj_is_kind_of(mesg, rb_mRaiseable),
instead of rb_obj_is_kind_of(mesg, rb_cException).
* Users should avoid "rescue Raiseable" in usual circumstances.
= Other Ideas not implemented here:
* Remove the obj_is_kind_of(mesg, rb_mRaiseable) restriction to allow pure duck-typing.
* Clean up the ivar names (@bt, @mesg) and method names (set_backtrace).
Sample Usage:
=end
require 'test/unit'
class TestRaiseable < Test::Unit::TestCase
def test_raiseable
raiseable = Class.new do
include Raiseable
def self.exception *args; new *args; end
end
begin
raise raiseable, "this must be handled"
assert(false)
rescue Exception
assert(false)
rescue Raiseable
assert(true)
end
end
class SomeLibraryFromSomebodyElse
def do_it
something_that_takes_too_long
rescue ::Exception
$stderr.puts "Something failed"
42
end
def something_that_takes_too_long
sleep 10
end
end
class MyTimeoutError
include Raiseable
def self.exception *args; new *args; end
end
def test_raiseable_timeout
require 'timeout'
begin
Timeout.timeout(1, MyTimeoutError) do
SomeLibraryFromSomebodyElse.new.do_it
end
assert(false)
rescue MyTimeoutError
# $stderr.puts "TIMEOUT: #{$!.inspect}"
assert(true)
end
end
end
    (1-1/1)