custom exceptions

J

Joe Van Dyk

Hi,

When should you define your own exceptions? Any rules of thumb?

I'm writing an application that runs on a computer and listens for
requests to start, kill, and view log files for other applications on
that computer. Say I get a request to start an application on that
computer and the requested executable doesn't exist. Should I throw a
custom exception then? Or, say an application dies unexpectedly.=20
What should I use for an exception then?

Thanks,
Joe
 
J

Joe Van Dyk

Hi,
=20
When should you define your own exceptions? Any rules of thumb?
=20
I'm writing an application that runs on a computer and listens for
requests to start, kill, and view log files for other applications on
that computer. Say I get a request to start an application on that
computer and the requested executable doesn't exist. Should I throw a
custom exception then? Or, say an application dies unexpectedly.
What should I use for an exception then?

The start function follows:

class Application
...
def start
raise "No executable given!" if not @executable
if @pid =3D fork
Process.detach @pid
@status =3D :running
else
@options.each do |option_name, option_value|
ENV[option_name] =3D option_value
end
args =3D @arguments.join " "=20
exec "#{ basedir }/#{ version }/#{ executable } #{ args }"
end
end
...
end

So, if there's no valid executable, then the exec call will fail.=20
What's the best way of transmitting that information to the rest of
the system?
 
E

Eric Hodel

When should you define your own exceptions? Any rules of thumb?

I define custom exceptions when I need to differentiate them from the
built-in exceptions.
I'm writing an application that runs on a computer and listens for
requests to start, kill, and view log files for other applications on
that computer. Say I get a request to start an application on that
computer and the requested executable doesn't exist. Should I throw a
custom exception then? Or, say an application dies unexpectedly.
What should I use for an exception then?

Sometimes an exception with a message is enough. Other times I need
to know the difference between two RuntimeErrors with different
messages.

I create my own exceptions for the second case because rescue
FooError is easier than reading exception messages.
 
J

Joe Van Dyk

Hi,

When should you define your own exceptions? Any rules of thumb?

I'm writing an application that runs on a computer and listens for
requests to start, kill, and view log files for other applications on
that computer. Say I get a request to start an application on that
computer and the requested executable doesn't exist. Should I throw a
custom exception then? Or, say an application dies unexpectedly.
What should I use for an exception then?
=20
The start function follows:
=20
class Application
...
def start
raise "No executable given!" if not @executable
if @pid =3D fork
Process.detach @pid
@status =3D :running
else
@options.each do |option_name, option_value|
ENV[option_name] =3D option_value
end
args =3D @arguments.join " "
exec "#{ basedir }/#{ version }/#{ executable } #{ args }"
end
end
...
end
=20
So, if there's no valid executable, then the exec call will fail.
What's the best way of transmitting that information to the rest of
the system?

Eeek. So, I was trying to do a test like:

def test_start_bad_application
a =3D Application.new invalid_application_executable
assert_raise(RuntimeError) { a.start }
assert !a.running?
assert_equal :failed, a.status
end

But since it forks into a new process, I don't catch the exception. I
could check to see if the executable exists (and is executable) before
going into the fork, and if it's not valid, throw an exception. Is
that my best bet?
 
R

Robert Klemme

I'd go with Eric's rule of thumb. It's not an exact science but you there
is a minimal criterium: if you need to catch this exception separately
from others you should introduce a new exception type.

Btw, here's a nice short script to print a class hierarchy of all
exceptions:

require 'pp'
tree = (cr = lambda {|h,k| h[k] = Hash.new &cr})[{},nil]
ObjectSpace.each_object(Class) {|cl| if cl.ancestors.include? Exception
then cl.ancestors.reverse.inject(tree){|tr,cl| tr[cl]} end}
pp tree

The start function follows:

class Application
...
def start
raise "No executable given!" if not @executable
if @pid = fork
Process.detach @pid
@status = :running
else
@options.each do |option_name, option_value|
ENV[option_name] = option_value
end
args = @arguments.join " "
exec "#{ basedir }/#{ version }/#{ executable } #{ args }"
end
end
...
end

So, if there's no valid executable, then the exec call will fail.
What's the best way of transmitting that information to the rest of
the system?

Eeek. So, I was trying to do a test like:

def test_start_bad_application
a = Application.new invalid_application_executable
assert_raise(RuntimeError) { a.start }
assert !a.running?
assert_equal :failed, a.status
end

But since it forks into a new process, I don't catch the exception. I
could check to see if the executable exists (and is executable) before
going into the fork, and if it's not valid, throw an exception. Is
that my best bet?

I guess so.

Kind regards

robert
 
J

Joe Van Dyk

On 30 Aug 2005, at 10:52, Joe Van Dyk wrote:
=20
=20
I define custom exceptions when I need to differentiate them from the
built-in exceptions.
=20
=20
Sometimes an exception with a message is enough. Other times I need
to know the difference between two RuntimeErrors with different
messages.
=20
I create my own exceptions for the second case because rescue
FooError is easier than reading exception messages.

Should the custom exception be in its own class? Or in a module?

Say I have the following class

class NodeManager
def start_application args
end
end=20

There are a few different ways start_application could fail:
- bad arguments
- user attempted to start the same application twice (which is an
error for us)
- not enough resources available

I want to distinguish between those different reasons. So, would I
want to have something like this:

module JoesExceptions # figure out some name
class BadArgumentsForApplication < Exception
end

class ApplicationStartedTwice < Exception
end

class NotEnoughResourcesForApplication < Exception
end
end

And then, in start_application:

def start_application args
# if arguments are bad
raise BadArgumentsForApplication
# and so on
end
 
J

Joe Van Dyk

=20
Should the custom exception be in its own class? Or in a module?
=20
Say I have the following class
=20
class NodeManager
def start_application args
end
end
=20
There are a few different ways start_application could fail:
- bad arguments
- user attempted to start the same application twice (which is an
error for us)
- not enough resources available
=20
I want to distinguish between those different reasons. So, would I
want to have something like this:
=20
module JoesExceptions # figure out some name
class BadArgumentsForApplication < Exception
end
=20
class ApplicationStartedTwice < Exception
end
=20
class NotEnoughResourcesForApplication < Exception
end
end
=20
And then, in start_application:
=20
def start_application args
# if arguments are bad
raise BadArgumentsForApplication

I guess that would be:
raise JoesApplication::BadArgumentsForApplication
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top