Passing multiple error classes to ruby's rescue clause in a DRY fashion
You can use an array with the splat operator *
.
EXCEPTIONS = [FooException, BarException]
begin
a = rand
if a > 0.5
raise FooException
else
raise BarException
end
rescue *EXCEPTIONS
puts "rescued!"
end
If you are going to use a constant for the array as above (with EXCEPTIONS
), note that you cannot define it within a definition, and also if you define it in some other class, you have to refer to it with its namespace. Actually, it does not have to be a constant.
Splat Operator
The splat operator *
"unpacks" an array in its position so that
rescue *EXCEPTIONS
means the same as
rescue FooException, BarException
You can also use it within an array literal as
[BazException, *EXCEPTIONS, BangExcepion]
which is the same as
[BazException, FooException, BarException, BangExcepion]
or in an argument position
method(BazException, *EXCEPTIONS, BangExcepion)
which means
method(BazException, FooException, BarException, BangExcepion)
[]
expands to vacuity:
[a, *[], b] # => [a, b]
One difference between ruby 1.8 and ruby 1.9 is with nil
.
[a, *nil, b] # => [a, b] (ruby 1.9)
[a, *nil, b] # => [a, nil, b] (ruby 1.8)
Be careful with objects on which to_a
is defined, as to_a
will be applied in such cases:
[a, *{k: :v}, b] # => [a, [:k, :v], b]
With other types of objects, it returns itself.
[1, *2, 3] # => [1, 2, 3]
multiple assignment in rescue clause?
I found the code above at http://phrogz.net/programmingruby/tut_exceptions.html. Was that your source?
In any event, the local variable in that code is assigned whichever error is raised; it's just specified after the last one.
And yes, it's throwing TypeError
because the errors do not implicitly coerce to a string in today's Ruby. Perhaps they used to when the book was initially published. You need to add .message
to the local variable reference to get the error message (e.g. + boom.message
).
TypeError (class or module required for rescue clause)
The line number in the error is a little misleading, the error is actually coming from this:
rescue e
I think you meant
rescue => e
What is wrong with this rescue example?
I just want to add something to the table: OP code suggests that the two exceptions are the same but they are not - furthermore i want to illustrate what OP meant with:
So it seems like that after doing raise x, x == y and x === y no longer hold. It seems to because x and y no longer have the same backtrace.
x = StandardError.new(:hello)
y = StandardError.new(:hello)
class Object
def all_equals(o)
ops = [:==, :===, :eql?, :equal?]
Hash[ops.map(&:to_s).zip(ops.map {|s| send(s, o) })]
end
end
puts x.all_equals y # => {"=="=>true, "==="=>true, "eql?"=>false, "equal?"=>false}
begin
raise x
rescue
puts "ok" # gets printed
end
puts x.all_equals y # => {"=="=>false, "==="=>false, "eql?"=>false, "equal?"=>false}
DRY-ing up begin-rescue-end
DRYing this up is a great idea and a good lesson in rails design (and Test Driven Development/TDD) if you can do so.
Ideally, you'd do something like this:
def create
...
grid = Tag.find_by_id(story[:tag_id]) or raise GridNotFoundError
...
event = Event.find_by_id(story[:event_id]) or raise EventNotFoundError
...
rescue GridNotFoundError
flash.now[:error] = "Please select a category"
process_grid_not_found(item, story, race, etc...)
rescue EventNotFoundError
flash.now[:error] = "Please select an event or create a new one if you don't find your event"
process_event_not_found(item, story, race, etc...)
rescue CreateEventError
flash.now[:error] = "There has been a problem creating your event."
process_event_create_error(item, story, race, etc...)
rescue ActiveRecord::RecordNotSaved, ActiveRecord::RecordInvalid, ActiveRecord::RecordNotFound
flash.now[:error] = item.errors.full_messages.join(" ,")
process_other_error(item, story, race, etc...)
end
render 'home/race_updates'
Then you should create the relavent new methods (process_event_not_found
, etc) as separate (probably private
) methods in the model.
This both makes the code much more readable, but has the great advantage be being much easier to write test code for.
So then you should write test code (using Test::Unit
or rspec
or whatever) that tests the isolated functionality required by each of the individual exception methods. What you'll find is that this both yields better code, as well as it also will likely break-down the exception methods into smaller, more modular methods themselves.
When you hear Ruby and Rails developers talk about the benefits of Test Driven Development, one of the main benefits of that approach is that it is much less likely to result in long, complex methods like the one you've got here. It's much more likely that you'll have code that is much DRYer, with smaller, simpler methods.
I'd also recommend that once you get through this you take another look and try to simplify it further. There will be more room for simplification, but I'd recommend refactoring it iteratively and starting with breaking it down as I've described and getting tests in place to start.
Multiple Rescue Statements in Rails Create Not Working
Found the problem. There is a patch to the open-uri.rb file in the ruby library.
Replace:
(/\A(?:http|ftp)\z/i =~ uri1.scheme && /\A(?:http|ftp)\z/i =~ uri2.scheme)
With:
(/\A(?:https?|ftp)\z/i =~ uri1.scheme && /\A(?:https?|ftp)\z/i =~ uri2.scheme)
in the open-uri.rb file. The problem is with http -> https redirects. This file was found for me in:
/Users/MyName/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/open-uri.rb
Rescue from an error that may not be defined
The exception list of a rescue-clause doesn't have to be a literal/static list:
excs = [EOFError]
defined?(AWS) && excs << AWS::SES::Response
# ...
rescue *excs => e
The splat operator *
is used here to convert an array into a list.
Related Topics
In Rails - Is There a Rails Method to Convert Newlines to <Br>
Problems with the Rails Console, Rvm and Readline
Ruby Hash Default Value Behavior
Rails with Ruby-Debugger Throw 'Symbol Not Found: _Ruby_Current_Thread (Loaderror)'
How to Convert a Ruby Hash So That All of Its Keys Are Symbols
Ruby: How to Convert a String to Boolean
Simple Way of Turning Off Observers During Rake Task
Ruby Read CSV File as Utf-8 And/Or Convert Ascii-8Bit Encoding to Utf-8
Best Way to Highlight Current Page in Rails 3? - Apply a CSS Class to Links Conditionally
Finding Out Current Index in Each Loop (Ruby)
How to Compare Strings Ignoring the Case
Given an Array of Arguments, How to Send Those Arguments to a Particular Function in Ruby