Cognito Broadcast
New Features in Ruby 2.3
Yesterday ruby 2.3-preview1 was released. This update brings several new additions to core classes in ruby as well as some new syntax. Here are a few of the new additions coming in ruby 2.3:
Extract values with Array#dig
and Hash#dig
The new #dig
instance methods provide concise syntax for accessing deeply nested data. For example:
user = { user: { address: { street1: '123 Main street' } } } user.dig(:user, :address, :street1) # => '123 Main street' results = [[[1, 2, 3]]] results.dig(0, 0, 0) # => 1
Both of these methods will return nil
if any access attempt in the deeply nested structure returns nil
:
user.dig(:user, :adddresss, :street1) # => nil user.dig(:user, :address, :street2) # => nil
Grep out the inverse of a pattern with Enumerable#grep_v
This method is the inverse of the Enumerable#grep
method. The grep method and its inverse provide several powerful ways to filter enumerables:
Filtering by regular expression
friends = %w[John Alain Jim Delmer] j_friends = friends.grep(/^J/) # => ["John", "Jim"] others = friends.grep_v(/^J/) # => ["Alain", "Delmer"]
Filtering by types
items = [1, 1.0, '1', nil] nums = items.grep(Numeric) # => [1, 1.0] others = items.grep_v(Numeric) # => ['1', nil]
Fetching multiple values with Hash#fetch_values
Sometimes Hash#fetch
is a better choice than Hash#[]
when you want to write more strict code. You can also access multiple values from a hash using Hash#values_at
, but there wasn’t a strict equivalent to values_at
until ruby 2.3:
values = { foo: 1, bar: 2, baz: 3, qux: 4 } values.values_at(:foo, :bar) # => [1, 2] values.fetch_values(:foo, :bar) # => [1, 2] values.values_at(:foo, :bar, :invalid) # => [1, 2, nil] values.fetch_values(:foo, :bar, :invalid) # => KeyError: key not found: :invalid
Positive and negative predicates for Numeric#positive?
and Numeric#negative?
Numeric values now have predicate methods that check if the subject is positive or negative. This can be useful if you want to filter an enumerable:
numbers = (-5..5) numbers.select(&:positive?) # => [1, 2, 3, 4, 5] numbers.select(&:negative?) # => [-5, -4, -3, -2, -1]
Hash superset and subset operators Hash#<=
, Hash#<
, Hash#>=
, and Hash#>
These methods lets you compare hashes to see if they are subsets or proper subsets of each other. For example:
small = { a: 1 } medium = { a: 1, b: 2 } large = { a: 1, b: 2, c: 3 } different = { totally: :different } { a: 1, b: 2 } > { a: 1 } # => true { a: 1 } > { a: 1 } # => false { b: 1 } > { a: 1 } # => false { a: 1, b: 2 } < { a: 1, b: 2, c: 3 } # => true
Convert a hash to a proc with Hash#to_proc
Now you can use a hash to iterate over an enumerable object:
hash = { a: 1, b: 2, c: 3 } keys = %i[a c d] keys.map(&hash) # => [1, 3, nil]
Honestly, I can’t think of a use case for this yet.
Avoid nil related errors with the safe navigation operator
Ruby 2.3 will introduce new syntax for accessing deeply nested objects safely without accidentally triggering a dreaded NoMethodError
on nil
. The syntax looks like this:
require 'ostruct' user&.address&.street&.first_line
where each instance of &.
is similar to ActiveSupport’s Object#try
method. Basically, if a nil value is encountered, then each method call will not be attempted and instead the nil
value will be returned immediately.
Experimental frozen string pragma
You’ve probably heard that strings will be frozen by default in ruby 3. Ruby 2.3 lets you specify a pragma which enables this by default:
$ ruby -v ruby 2.3.0preview1 (2015-11-11 trunk 52539) [x86_64-darwin14] $ cat default.rb # frozen_string_literal: false puts "Hello world".reverse! $ ruby default.rb dlrow olleH $ cat enabled.rb # frozen_string_literal: true puts "Hello world".reverse! $ ruby enabled.rb enabled.rb:3:in `reverse!': can't modify frozen String (RuntimeError) from enabled.rb:3:in `<main>'
Alternatively, you can also enable and disable this using the command line argument --enable=frozen-string-literal
Further reading
You can read about other new features, performance improvements, compatibility issues, and more here. Remember that this is still a preview of ruby 2.3 and some things might be subject to change.