Ruby’s New Exception Keyword Arguments
exception: false and exception: true
In Ruby 2.6, a variety of Kernel methods get a new exception: false
or exception: true
keyword argument. When Kernel methods fail, some raise an error and some just return nil
. This new feature lets you override that default behavior.
TL;DR: In Ruby 2.6 these examples will all work:
system 'not-a-command', exception: true
#!> Errno::ENOENT: No such file or directory - not-a-command
Integer('not-a-number', exception: false)
#=> nil
Float('not-a-number', exception: false)
#=> nil
Complex('not-a-number', exception: false)
#=> nil
Rational('not-a-number', exception: false)
#=> nil
Background
What should Ruby do when unexpected things occur? Fail loudly? Carry on silently? It depends. There are reasons you may prefer to handle errors differently.
Many methods have a default behavior to either return nil
or raise an error when something goes wrong. Ruby chooses what’s most appropriate as a default on a method-by-method basis.
One example of Ruby having various default behaviors is string-to-number conversion. For example,'nope'.to_i
is permissive and returns0
, since 'nope'
isn’t a number. On the other hand, Integer('nope')
is strict, and raises an error. Here are a few examples of how this works:
'42'.to_i
#=> 42
'42x'.to_i
#=> 42
'Square'.to_i
#=> 0
Integer('42')
#=> 42
Integer('42x')
#!> ArgumentError: invalid value for Integer(): "42x"
Integer('Square')
#!> ArgumentError: invalid value for Integer(): "Square"
The permissive String#to_i method is lax about detecting a number. When one can’t be found it just provides a default value of zero. Alternately, the strict Kernel#Integer method raises an error. If you want strict parsing but no error in Ruby 2.5 and earlier, it’s up to you to manually rescue:
Integer('nope') rescue nil
#=> nil
Exception False with Numeric Conversion
The problem with rescuing manually is that it’s slow and noisy. On my machine, it’s almost three times faster to use exception: false
:
In Ruby 2.6, you’ll be able to use Integer('nope', exception: false)
instead of Integer('nope') rescue nil
for much better performance. The same applies to Float
, Rational
and Complex
.
Float('nope', exception: false)
instead ofFloat('nope') rescue nil
Exception True with System
The new exception keyword arguments are also available for Kernel#system. If command execution fails, the #system method’s default behavior is to fail silently and return nil:
system 'nope'
#=> nil
Before, you had to write the message and raise the error yourself if you wanted to have #system raise an error on execution failure. Now you can simply add exception: true
and you’ll get an error raised with a nicely formatted message:
system 'nope', exception: true
#!> Errno::ENOENT: No such file or directory - nope
When command execution succeeds but there’s a non-zero exit status, exception: true
will also cause an error to be raised instead of the false
return value.
Conclusion
Thanks to Aaron Patterson for proposing this feature for numeric conversion. And thanks to Takashi Kokubun for proposing this feature for #system. The new exception:
keyword arguments will ship with Ruby 2.6 when it’s released on Dec 25, 2018. These changes didn’t make it into ruby-2.6.0-preview1 but they will be part of the upcoming ruby-2.6.0-preview2 release and are available now on the nightly snapshots.
We use Ruby for lots of things here at Square — including our Square Connect Ruby SDKs and open source Ruby projects. We’re eagerly awaiting the release of Ruby 2.6!
The Ruby logo is Copyright © 2006, Yukihiro Matsumoto, distributed under CC BY-SA 2.5.
Want more? Sign up for your monthly developer newsletter or drop by the Square dev Slack channel and say “hi!”