The letter A styled as Alchemists logo. lchemists
Published December 30, 2020 Updated December 20, 2022
Cover
Ruby 3.0.0

As has been a yearly tradition, the new 3.0.0 version of Ruby was released this Christmas. Not only did we get a new version but a major version, the first in ~7 years since Ruby 2.0.0 came out!

This holiday release is also my favorite present to receive each year. While I am fully aware playing with a new version of Ruby might be an odd thing to look forward to during the holidays, I enjoy exploring the new features. The following are the results of my exploration thus far.

Table of Contents

Overview

Before you ramp up learning about Ruby’s new feature set, you might want to take advantage of articles written earlier, including:

  • Ruby 3.0.0 Release Notes - The official notes from the Ruby Core team.

  • Ruby 3.0.0 Version Notes - Highly recommend bookmarking or macro’ing this great resource for all of your Ruby version needs. I’ve been using this site for years, via an Alfred macro, for quickly looking up Ruby version related information.

  • Ruby 3.0.0 Feature List - Provides a high level overview of what’s new in Ruby 3.0.0.

Upgrade

Upgrading from Ruby 2.7.2 to 3.0.0 was fairly straight forward. Even dealing with a major version bump, the endeavor took less than a couple of days.

I’m happy to report that all ~30 projects hosted on this site, including this site itself, are now running on Ruby 3.0.0. šŸŽ‰ I noticed a few interesting issues while upgrading, though:

  • Download - The Ruby 3.0.0 tar file is no longer in a bzip2 format but uses gzip now instead. This tripped me up, initially, as I’ve configured my continuous integration builds to automatically install the latest version of Ruby based off of the .ruby-version of each project so I had CI build failures until I noticed the format had changed.

  • Keyword Arguments - Prior versions to 3.0.0 have warned about the use of keyword arguments so had done the work to upgrade all projects to explicitly define positional and keyword arguments. Despite the pre-planning, there were a few surprises:

    • If you are passing a Hash through several methods, ensure you are explicit in splatting the hash out in all messaging (i.e. **arguments). For more, see the official documentation on positional and keyword arguments.

    • If you are metaprogramming, and use a combination of positional and keyword arguments you’ll need to explicitly splat the positional and keyword arguments too. Example: def method_missing *positionals, **keywords, &block.

  • Frozen Regular Expressions and Ranges - These are frozen by default now, so you can happily avoid adding #freeze to object definitions. I still wish strings would have been frozen in 3.0.0 but that decision was vetoed a couple years ago. We’ll have to continue using the # frozen_string_literal: true pragma in the meantime. By the way, you can use the Pragmater gem to manage frozen strings as well as other pragmas if you like.

  • Endless Methods - In order to define endless methods, you are now forced to use parentheses which is a major bummer. I’ve always loved that parentheses can be avoided, for the most part, in Ruby. Still, being able to collapse several lines of code is handy. If using Rubocop, you might need to wait for a fix because endless methods will cause Lint/Syntax errors.

  • Pattern Matching - I’ve been using pattern matching in several projects so was happy to remove use of Warning[:experimental] = false from source code that would effect downstream users.

  • Refinements - I’ve been maintaining the Refinements gem for several years now, supporting Hash#except and Hash#transform_keys(also known as Hash#rekey). I was happy to delete code I no longer have to maintain.

  • Syndication - The RSS gem, used to power the syndication of this site, is no longer packaged with Ruby and is now a separate install. For more on this, here is the full list of Ruby 3.0.0 Default and Bundled gems.

Next Actions

There is still much to learn and use within Ruby 3.0.0. In particular, I’ll be spending a bunch of time with the following:

  • Type Checking - I need to start digging into using RBS, TypeProf, and Steep as mentioned during RubyConf.

  • Concurrency - I’m interested in both Fibers and Ractors and planning to spend time with them in the weeks to come.

Happy holidays! I’m looking forward to a better year ahead, with Ruby 3.0.0 leading the way. šŸš€