Nithin Bekal About

What's new in Ruby 2.5?

27 Dec 2017

The Ruby core team has traditionally released a new version of Ruby on Christmas day, and this Christmas, we got Ruby 2.5. A couple of years ago, I started posting a summary of Ruby changes (2.4, 2.3), and this year’s version is here.

(This is only a list of things I found most interesting about this release, so if you want a complete list, take a look at the changelog.)

Rescue in do/end blocks

If you needed to rescue an exception in a block, the only way to do that was to put it in a begin/end block. Now, you can rescue exceptions inside all do/end blocks.

(1..5).each do |n|
  do_something(n)
rescue SomeError => e
  puts e
  next
end

Top level constant lookup is removed

In previous versions, if Ruby couldn’t find a constant in the current scope, it would fallback to the top level constant, and emit a warning. This has changed in 2.5, and this will now cause an exception.

class Foo; end
class Bar; end

# Ruby 2.4
Foo::Bar
# warning: toplevel constant Bar referenced by Foo::Bar
#=> Bar

# Ruby 2.5
Foo::Bar
# NameError

Backtrace in reverse order

When printing to console, Ruby will display the backtrace in reverse order. You will also see the error message in bold and underlined. This is an experimental feature, and the order won’t be changed when printing to logs.

When working on Rails projects, it is common to have to scroll a long way back to find the line in the backtrace that shows the line where the exception happened. By reversing the backtrace, you get the context on the line causing the exception without having to scroll back.

Kernel#yield_self

This method passes an object to a block and returns the value returned by the block. The use of pipelines is common in Elixir, so I’ll translate some code from one of my Elixir packages to Ruby to demonstrate this feature.

isbn = "0-306-40615-2"

isbn.gsub('-', '')
  .yield_self { |isbn| URI("#{API_URL}?q=isbn:#{isbn}") }
  .yield_self { |uri| Net:HTTP.get(uri) }
  .yield_self { |json_response| JSON.parse(json_response) }
  .yield_self { |response| response.dig('items', 'volumeInfo') }

The Ruby community has many people who are interested in Elixir, so this could end up being a popular feature. I wonder if this could have been an operator, but it’s still an interesting addition to Ruby.

Standard Gems

Ruby comes with a lot of things bundled into the standard library, and this makes it hard to push bug fixes after a Ruby version is released. To solve this, many libraries are being gemified, and released independently of Ruby. Libraries like cmath and webrick have been extracted this way.

This doesn’t mean you can’t use Webrick the next time you install Ruby, though. The gems being extracted will be shipped with Ruby as default gems, but you also have the option of installing the latest version through Rubygems.

String methods

String#-@: deduplicates unfrozen strings.

s = - 'foo'  #=> 'foo'
s.frozen?    #=> true

delete_prefix and delete_suffix (along with the bang ! versions)

'Mr. Smith'.delete_prefix('Mr. ')      #=> 'Smith'
'Wellington St.'.delete_suffix(' St.') #=> 'Wellington'

grapheme_clusters

s = "a\u0300"       #=> "à"
s.grapheme_clusters #=> ["à"]
s.codepoints        #=> [97, 768]

Array methods

#append and #prepend methods have been added, which are aliases for #push and #unshift respectively. These aliases were already introduced in Rails via ActiveSupport, but it’s nice to see them introduced into Ruby.

list = ['b', 'c']  #=> ['b', 'c']
list.prepend('a')  #=> ['a', 'b', 'c']
list.append('d')   #=> ['a', 'b', 'c', 'd']
list               #=> ['a', 'b', 'c', 'd']

Hash methods

#slice and #transform_keys have been added, which are also originally from ActiveSupport.

h = { a: 1, b: 2, c: 3, d: 4 }

h.slice(:a, :b)
#=> { a: 1, b: 2 }

h.transform_keys(&:to_s)
#=> {"a"=>1, "b"=>2, "c"=>3, "d"=>4}

Goodbye, ubygems.rb!

This change will have zero impact on how you use Ruby, but I was curious why we had an ubygems.rb file in stdlib, so I wanted to mention it now that it’s been removed.

Ruby has a -r flag that lets you require a library, e.g. ruby -rmath to require 'math'. The rubygems file was named ubygems.rb so that the flag could be used as -rubygems instead of -rrubygems. This file hasn’t been needed since Ruby 1.9, and has now been removed from stdlib.

This article is part of the What's New in Ruby series. To read about a different version of Ruby, pick the version here:

2.3    2.4    2.5    2.6    2.7    3.0    3.1    3.2    3.3

Hi, I’m Nithin! This is my blog about programming. Ruby is my programming language of choice and the topic of most of my articles here, but I occasionally also write about Elixir, and sometimes about the books I read. You can use the atom feed if you wish to subscribe to this blog or follow me on Mastodon.