Rescuing specific exceptions excessively can cause problems, but if you’ve ever had need to rescue within a do/end block, you might have found yourself using wordy syntax. Ruby 2.5 has a solution for you.
In Ruby 2.5, we’ll get a little syntactic sugar for handling exceptions inside do/end blocks. You can see the feature discussion on Ruby’s Redmine instance. If you’ve ever used the shorthand for rescuing inside a method without using begin/end keywords, this is basically that but inside blocks.
Below we’re going to work through a bit of code, but we’re not going to define all the methods.
Imagine a Santa class, and an algorithm for Santa Claus arriving in town. Santa needs some paper to jot down delivery details. If there is no paper, we raise an error.
class Santa
def initialize(good, bad)
@nice_children = good
@naughty_children = bad
end
def make_list
raise NoPaperError if @paper.nil?
@list = nice_children.gifts.map(&:details)
end
def check_list
@list.verify_children(nice_children, naughty_children)
end
# other Santastic behaviour below
end
We’ll define a global prepare method that takes a block. In Ruby 2.4 when we send the make_list message to Santa within the block, we need to use a full begin/rescue/end clause to describe the behaviour:
def song(children)
santa = Santa.new(children.good, children.judged_capriciously_by_society)
prepare do
# must use `begin` here in Ruby 2.4 and earlier
begin
santa.make_list
2.times { santa.check_list }
rescue NoPaperError
santa.request_paper
ensure
music_stops
end
end
end
def prepare(&block)
yield
end
If we try to use the shorthand common in Classes, we hit an exception:
def song(children)
santa = Santa.new(children.good, children.judged_capriciously_by_society)
prepare do
santa.make_list
2.times { santa.check_list }
rescue NoPaperError
santa.request_paper
ensure
music_stops
end
end
end
song(children) #=> SyntaxError: syntax error, unexpected keyword_rescue, expecting keyword_end
In Ruby 2.5 though, we can do this handily:
def song(children)
santa = Santa.new(children.good, children.judged_capriciously_by_society)
prepare do
# no `begin` keyword!
santa.make_list
2.times { santa.check_list }
rescue NoPaperError
santa.request_paper
ensure
music_stops
end
end
end
song(children) # => “music stops”
So that’s nice. See you tomorrow for more Ruby 2.5 news!