It has become a tradition to release new Ruby versions on Christmas.

And in this post I want to cover some of the most interesting changes in Ruby 2.4 so you can keep up with the news 🙂

Float#round with keyword

If you are using floats in your app I hope you use floor or ceil for rounding, because the Float#round method is changing its default behavior in Ruby 2.4.

Example:

# Ruby 2.3 (2.5).round 3 # Ruby 2.4 (2.5).round 2

The default behavior is now to “round-to-nearest-even”.

UPDATE: The default behavior for Float#round is back to “rounding up” in the final version of Ruby 2.4 . This was a decision taken by Matz after this post was originally published.

In addition, Float#round now takes an argument which you can use to define the type of rounding you want.

The options are:

:even

:up

:down

Example:

(4.5).round(half: :up) 5

Also Float#floor , Float#ceil & Float#truncate now take an optional argument that lets you set a precision.

Chomp flag for IO methods

If you ever used a method like gets or each_line I’m sure you remember having to deal with those pesky new line characters.

The ones that looks like this:

.

This is something beginners always have trouble with, but this new feature might be able to help!

Here’s an example:

input = gets.chomp # "abc

"

Now in Ruby 2.4 you will be able to set the chomp keyword argument & gets will remove the newline character for you.

Example:

input = gets(chomp: true) # "abc"

This will work with any value that’s not false or nil (the only “falsy” values in Ruby).

So this also works (but not recommended because it can be confusing):

input = gets(chomp: 1234) # "abc"

It’s not a super big deal, but it can save you a method call 🙂

Pathname#empty?

Ruby 2.4 implements Dir#empty? & File#empty? , these methods let you check if a directory or a file is empty (that was pretty obvious, right?).

But Pathname#empty? was also added recently.

In case you are not familiar with Pathname , it’s a class that merges together functionality from both the Dir class & the File class.

In addition, it’s also more “OO” (Object Oriented) in the sense that it returns Pathname objects, instead of strings.

Example:

Pathname.empty?("file or directory name")

Commit: https://github.com/ruby/ruby/commit/9373c5efb993dd8cae0526118805449b19af2c22

Set compare_by_identity

Sets are a data structure that is available as part of the standard library. It helps you keep a collection of unique items.

By default the objects are compared based on their value (or to be more accurate, based on their hash value).

But in Ruby 2.4 it’s possible to have a set of unique objects based on their object id.

Example:

require 'set' # Normal set set = Set.new set << 123 << 123 << "abc" << "abc" # [123, "abc"] # Identity set set = Set.new().compare_by_identity set << 123 << 123 << "abc" << "abc" # [123, "abc", "abc"]

If anyone knows of any interesting use for this feature leave a comment 🙂

Commit: https://github.com/ruby/ruby/commit/76977611dd68e384fdce8c546efda5e1931e67a6

Refinements with Kernel#send, BasicObject#send, Symbol#to_proc

I'm not going to cover refinements in detail here, but the basic idea is to be able to add methods to a class like String , while keeping this change "localized" to one file or class.

Since Ruby 2.4, methods defined via refinements will be available when called via methods like Kernel#send & Symbol#to_proc .

Example:

module TenTimes refine String do def ten_times puts self * 10 end end end class Thing using TenTimes "abc".send(:ten_times) end

If you try this in 2.3 or below you will get an 'undefined method' error.

Commit: https://github.com/ruby/ruby/commit/35a29390197750abf97ef16fa0740e377764daef

Hash#transform_values

Here's another method extracted from Rails & coming directly to Ruby. I'm talking about Hash#transform_values , which works in a similar way to Array#map .

Example:

h = {a: 1, b: 2, c: 3} h.transform_values { |v| v * 10 } # {a: 10, b: 20, c: 30}

There is also Hash#transform_values! if you need in-place mutation.

Kernel#clone now takes an optional keyword argument

As you may know, it's possible to make a copy of a Ruby object. This is useful because most Ruby objects are mutable & you may want to avoid making changes to the original object.

We have two methods for making an object copy:

clone

dup

There are a few small differences between clone & dup, but for this post let's just say that clone keeps the "frozen" status of the original object while dup does not.

New in 2.4 is the ability to call clone with a "freeze" flag.

Example:

foo = "test".freeze boo = foo.clone(freeze: false) boo.frozen? # false

I'm not sure to what extend this is useful, but who doesn't want more options 🙂

Commit: https://github.com/ruby/ruby/commit/320ae01c5fb091eab0926c186f304a9caeda1ace

Thread.report_on_exception

Another feature coming with 2.4 is Thread.report_on_exception. This was proposed because Thread exceptions are silent by default, and this can hide problems with your code.

The default value is false , but if your app is using Threads you should try enabling this when upgrading to Ruby 2.4.

Example:

Thread.report_on_exception = true t1 = Thread.new do puts "In new thread" raise "Exception from thread" end sleep(1) puts "In the main thread"

This will show the exception, but it will not crash your program. The alternative is Thread.abort_on_exception, which has always been available.

Notice that there is also an instance version of this method, so you can set this option per-thread instead of all threads.

Binding#irb

Are you a fan of using binding.pry for debugging? Well now we also have binding.irb which works in a similar way.

But since it's irb you still don't get all the nice things that pry gives you, like the syntax highlighting.

Better than nothing if for some reason you don't have access to pry 🙂

Commit: https://github.com/ruby/ruby/commit/493e48897421d176a8faf0f0820323d79ecdf94a

Conclusion

This new version of Ruby brings in many interesting features, so make sure to check it out when it's available.