It’s beginning to feel like tradition –– for the second year now, the Ruby core team has shipped a minor point update on Christmas Day. This year gifting the world Ruby 2.3.

After reading up on this release, it feels more more like a major point update, just for the sheer amount of work that must have been involved. Part of the release seems to be paving the way for immutability in Ruby 3.0 and a large chunk of the release provided new syntax and language features.

Let’s take a look at a few of the new features. I was most looking forward to both the Hash#dig and Array#dig methods. The “safe navigation” operator was added, which apparently is a favorite of Matz. Additionally, the did_you_mean gem is now built into the language, a breakthrough for typo-driven-development of which I am so fond.

Install Ruby 2.3.0

Using ruby-install we can quickly grab the latest version of ruby.

ruby-install -M https://ftp.ruby-lang.org/pub/ruby ruby 2.3.0

Once that’s done downloading and compiling, I like chruby for switching to the new version.

chruby 2.3

Hash#dig and Array#dig

Both of these methods are great if you’re dealing with unwieldy data sets that you may or may not have control over. Think complex API responses, legacy system interfaces, etc. They allow you to safely traverse into the data structure without raising an error if a single node in the lookup doesn’t exist.

Hash#dig

Given a hash that looks like this:

data = {
  people: [
    {
      first_name: "Jamie",
      last_name: "Jackson",
      team: "Blue Squad",
      qualifications: [
        {
          skill: "Oil Change",
          type: "primary"
        },
        {
          skill: "Alignment",
          type: "advanced"
        }
      ]
    },
    {
      first_name: "Jordan",
      last_name: "Jacobs",
      team: "Red Squad",
      qualifications: []
    }
  ]
}

The dig method allows you to pull out data or simply get nil if the piece of data doesn’t exist at the path you’ve “dug” to. For instance:

data[:people][0][:qualifications][0][:skill]
# => Oil Change
data[:people][1][:qualifications][0][:skill]
# => NoMethodError: undefined method `[]' for nil:NilClass
# thrown since data[:people][1][:qualifications][0] is nil

data.dig(:people, 0, :qualifications, 0, :skill)
# => Oil Change
data.dig(:people, 1, :qualifications, 0, :skill)
# => nil

Array#dig

The dig method for Array works similarly:

data = [
  [10, [10, 4]],
  [15, [15, 3]],
  [20]
]

data[0][1][0]
# => 10
data[1][1][0]
# => 15
data[2][1][0]
# => NoMethodError: undefined method `[]' for nil:NilClass

data.dig(0, 1, 0)
# => 10
data.dig(1, 1, 0)
# => 15
data.dig(2, 1, 0)
# => nil

Safe Navigation Operator

This is something that I hope people will use sparingly since it seems like it would be a smell otherwise. The “safe navigation” operator allows you to call a method on a variable that might be nil. Other languages, such as C# and Swift, have a similar feature.

In Ruby it looks like this: &.

# assume nilly is nil because User was not found
nilly = User.find_by(username: "nilly")

# Before Ruby 2.3
nilly.notify!           # NoMethodError error because nilly is nil!
nilly && nilly.notify!  # avoid NoMethodError using short-circuit conditional

# After Ruby 2.3
nilly&.notify!          # will only call notify! if nilly is not nil
# => nil                # just returns nil when object is nil

I can see this coming in handy in some situations, but I would consider using a null object pattern if I frequently found myself calling methods on something that is possibly nil.

did_you_mean

The did_you_mean gem is a nice little tool that provides helpful suggestions when you mispell or tpyo a word. It’s also nice when you might have a good idea of a method name, but need a little help.

Check it out:

data = [1, 2, 3, 4]

data.puhs(5)
# NoMethodError: undefined method `puhs' for [1, 2, 3, 4]:Array
# Did you mean?  push
#                puts
data.push(5)

data.sliver(2,5)
# NoMethodError: undefined method `sliver' for [1, 2, 3, 4, 5]:Array
# Did you mean?  slice
#                slice!

data.slice(2,5)
# => [3, 4, 5]

What do you like about this release?

Sources and Info