0

I'm working on an application that I had been failing out of using raise, like this:

raise 'Some error happened!'

This caused caused an unsightly stack trace to be displayed, so I adjusted the code to use abort, like this:

abort 'Some error happened!'

Perfect! Now I can exit with a clear message and no stacktrace.


The problem comes in because, in one instance I need to rescue from this situation. I can do something like:

begin
  abort 'Some error happened!'
rescue SystemExit
  puts 'Rescued'
end

puts 'Moving on...'

# Outputs:
# Some error happened!
# Rescued
# Moving on...

This has the disadvantages of displaying the abort message despite being rescued and rescuing a fairly vague error. What I would really like to do, is something like this:

class MySuperFancyCustomError < StandardError
  def initialize
    super
    abort 'Some error happened!'
  end
end


begin
  raise MySuperFancyCustomError
rescue MySuperFancyCustomError
  puts 'Rescued'
end

puts 'Moving on...'

# Outputs:
# Some error happened!

But I haven't been able to figure out a way to set this up so that I can rescue from it. I just need it to keep running and output:

Rescued
Moving on...

Instead of failing with:

Some error happened!

Does anyone know of an elegant way to make this happen?

Brad Werth
  • 17,411
  • 10
  • 63
  • 88
  • See if this answer helps: https://stackoverflow.com/questions/2823748/how-do-i-add-information-to-an-exception-message-in-ruby/4789702#4789702 – Ryenski Apr 06 '17 at 18:24
  • Oh I see you _don't_ want the stacktrace... never mind – Ryenski Apr 06 '17 at 18:26
  • Thanks - it does, somewhat. I've seen that approach, and variations of it, but I was really hoping to find a way to keep it all "self-contained" in the exception itself, if possible. – Brad Werth Apr 06 '17 at 18:26
  • You might do this by encapsulating your risky operation into a service object. Then in your service object catch the exception and return a failure message, or return a success message if no exception. – Ryenski Apr 06 '17 at 18:29
  • Yeah, that's kinda what I'm doing now, this is a super simplified example. I just couldn't get it to do it, I wondered if anyone could think of a way. Think of it as an academic exercise: a catchable error that aborts if not caught... – Brad Werth Apr 06 '17 at 20:50

1 Answers1

0

I'd strongly advise against using abort for flow control. Instead try this:

class CustomException < StandardError
end

class Example
  def explode
    raise CustomException, "Michael Bay here!"
  end
end

begin
  Example.new.explode
rescue CustomException => e
  puts "This happened: %s" % e
end

Here you define your own exception type, and then explicitly catch it.

Now you'll get this output, but you have full control over how, if, and when it's displayed:

This happened: Michael Bay here!
tadman
  • 208,517
  • 23
  • 234
  • 262
  • I'm sorry, I had inadvertently selected the Rails tag out of habit, which was misleading. This is not for flow control, but legitimate termination at the end of a process. I consume a bunch of random 3rd party things with this, and abort works perfectly for 99% of the cases. Unfortunately, I have to use the same method for 1 that I know will 'fail' and I have to keep going through. I was looking for a simpler way to handle all possible eventualities. (Currently, the consumer looks a lot like your example, FWIW) I just wondered if this could be done... – Brad Werth Apr 06 '17 at 20:47
  • This is just generic Ruby code, and it's how most Ruby code deals with a hard failure state. It's typical to raise an exception with a specific class so you can catch and recover as necessary at a higher level. There's no "simple way" unless you can better articulate your use case. – tadman Apr 06 '17 at 20:57
  • I thought maybe my rails tag was making you think I was using it for flow control. Basically, this is meant to abort if various process run with popen return a non-zero exit code. It should always treat that as a failure, except in 1 spot, that I already handle. I actually have a pretty good solution for it, even to get it to not output the message, but I don't like rescuing SystemExit, so I wanted a different error I could rescue that still does an abort, but I can actually catch. I figured there would be some way to make the example above work, but I couldn't get it. – Brad Werth Apr 06 '17 at 21:05
  • Now I'm more interested in making an abort that can be caught with a user-defined exception, that solving any real problem, I guess. – Brad Werth Apr 06 '17 at 21:06
  • Again, try to avoid using `abort`. It's not like `raise`. It's basically asking to force-quit the program with a message and it's not intended to be caught. It's normal to catch and `raise` an exception of your own design to remap things like I/O errors and interpret them with your own names and labels. – tadman Apr 07 '17 at 02:55
  • Remember it's only *uncaught* exceptions that show a stack trace. If you catch them you won't see that. – tadman Apr 07 '17 at 03:18