[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Does Ruby support exception wrapping (exception chaining)?

Brian Hartin

4/1/2008 5:21:00 PM

I could not find any information about this, except regarding DRb.

It seems like the raise method / Exception class ought to allow me to
pass in a 'causal' exception, e.g.

begin
=20 foo
rescue Exception =3D> e
=20 raise ServiceNotFoundException, "The service could not be contacted",=

e
end

This doesn't work. I can, however, pass in the backtrace, e.g.

raise ServiceNotFoundException, "The service could not be contacted",
e.backtrace

However, doing this I get the stack trace but not the type or message
from the causal exception (unless I manually put them in the message
string). Ideally, I'd be able to use exception chaining such as in
Java, in which my stack traces include causal exceptions:

WebServiceCommunicationException: The WSDL could not be obtained from
http://blah/wsdl.
=20 from (webservice_client.rb):123:in `obtain_wsdl'
=20 from (webservice_client.rb):12:in `request_price'
caused by ParsingError: Unexpected element 'html'
=20 from (other_class.rb):234 in 'some_method'
=20 from (other_class.rb):23 in 'some_other_method'
=20 ...

including a 'cause' field on the Exception class, e.g. e.cause.

Is there some reason why this would not fit the Ruby style? If not, is
this something that would be considered as a patch/change for Ruby?

I realize I could probably monkeypatch Exception, but this seems (to me)
like it would be an improvement to the language.

Thanks,

Brian Hartin
*************************************************************************=
***=20
This email may contain material confidential to
Pearson. If you were not an intended recipient,=20
please notify the sender and delete all copies.=20
We may monitor email to and from our network.=20
*************************************************************************=
***

5 Answers

Joel VanderWerf

4/1/2008 5:49:00 PM

0

Hartin, Brian wrote:
> I could not find any information about this, except regarding DRb.
>
> It seems like the raise method / Exception class ought to allow me to
> pass in a 'causal' exception, e.g.
>
> begin
> foo
> rescue Exception => e
> raise ServiceNotFoundException, "The service could not be contacted",
> e
> end

The second arg to raise (i.e. the message) can be any object:

class ServiceNotFoundException < StandardError; end

begin
begin
raise "foo"
rescue Exception => e
raise ServiceNotFoundException, ["The service could not be contacted",
e]
end
rescue Exception => e_outer
puts e_outer
p e_outer.message
end

__END__

Output:

#<ServiceNotFoundException:0xb7d9b75c>
["The service could not be contacted", #<RuntimeError: foo>]

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Brian Hartin

4/2/2008 6:45:00 PM

0

Joel,

This doesn't really provide the main benefit to exception wrapping
mechanism: the ability to wrap low-level exceptions in an appropriate
higher-level exception and yet not lose the entire stack trace, or the
types and messages of the low-level exceptions. Exception wrapping
(a.k.a. chaining) in Java (a good model for this feature, I think) makes
the idea of a 'causal Exception' part of the class (via a 'cause'
field), and the stack trace: an Exception's stack trace includes the
causal 'chain' of Exceptions automatically.

I think I can write this up for my own use. I just wondered if I was
missing an existing feature.

Thanks for the response!


Joel VanderWerf wrote:
> Hartin, Brian wrote:
>> end
> The second arg to raise (i.e. the message) can be any object:
>
> class ServiceNotFoundException < StandardError; end
>
> begin
> begin
> raise "foo"
> rescue Exception => e
> raise ServiceNotFoundException, ["The service could not be
> contacted",
> e]
> end
> rescue Exception => e_outer
> puts e_outer
> p e_outer.message
> end
>
> __END__
>
> Output:
>
> #<ServiceNotFoundException:0xb7d9b75c>
> ["The service could not be contacted", #<RuntimeError: foo>]

--
Posted via http://www.ruby-....

Joel VanderWerf

4/2/2008 6:59:00 PM

0

Brian Hartin wrote:
> Joel,
>
> This doesn't really provide the main benefit to exception wrapping
> mechanism: the ability to wrap low-level exceptions in an appropriate
> higher-level exception and yet not lose the entire stack trace, or the
> types and messages of the low-level exceptions. Exception wrapping
> (a.k.a. chaining) in Java (a good model for this feature, I think) makes
> the idea of a 'causal Exception' part of the class (via a 'cause'
> field), and the stack trace: an Exception's stack trace includes the
> causal 'chain' of Exceptions automatically.

How about this?

class ServiceNotFoundException < StandardError
attr_reader :cause
def initialize cause
@cause = cause
end
end

begin
begin
raise "foo"
rescue Exception => e
e2 = ServiceNotFoundException.new e
raise e2, "The service could not be contacted: #{e.message}",
e.backtrace
end
rescue Exception => e_outer
puts e_outer
p e_outer.cause
puts e_outer.backtrace.join("\n ")
end

__END__

Output:

The service could not be contacted: foo
#<RuntimeError: foo>
wrapped-exceptions.rb:10


--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Joel VanderWerf

4/2/2008 7:09:00 PM

0

Joel VanderWerf wrote:
> Brian Hartin wrote:
>> Joel,
>>
>> This doesn't really provide the main benefit to exception wrapping
>> mechanism: the ability to wrap low-level exceptions in an appropriate
>> higher-level exception and yet not lose the entire stack trace, or the
>> types and messages of the low-level exceptions. Exception wrapping
>> (a.k.a. chaining) in Java (a good model for this feature, I think)
>> makes the idea of a 'causal Exception' part of the class (via a
>> 'cause' field), and the stack trace: an Exception's stack trace
>> includes the causal 'chain' of Exceptions automatically.

Here's an alternative, perhaps with too much magic:


class ServiceNotFoundException < StandardError
attr_reader :cause
def initialize cause
@cause = cause
end

DEFAULT_MESSAGE = "The service could not be contacted"

def self.[](e, msg = DEFAULT_MESSAGE)
e2 = new(e)
raise e2, "#{msg}: #{e.message}", e.backtrace
end
end

begin
begin
raise "foo"
rescue Exception => e
ServiceNotFoundException[e]
end
rescue Exception => e_outer
puts e_outer
p e_outer.cause
puts e_outer.backtrace.join("\n ")
end

__END__

Output:

The service could not be contacted: foo
#<RuntimeError: foo>
wrapped-exceptions.rb:17

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Francis Fish

1/16/2009 9:57:00 AM

0

Hi guys

I came up with this based on your ideas but it doesn't have the
complexity:

class ParseFailed < Exception ; end
# ...
rescue Exception => e
raise ParseFailed.new("Page generation failed #{e}:
#{e.backtrace.join("\n")}")

This raises my named exception with the text and full backtrace of the
one thrown as the message. Not as good as chaining Exception.new(e) but
it allows you to see the trace in the message without having to do
another backtrace.

It met my needs and seems a little simpler than hacking another
exception class.
--
Posted via http://www.ruby-....