|
| 1 | +# New features in ruby 2.3 |
| 2 | + |
| 3 | +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: |
| 4 | + |
| 5 | +### 1. Extract values with Array#dig and Hash#dig |
| 6 | + |
| 7 | +The new #dig instance methods provide concise syntax for accessing deeply nested data. For example: |
| 8 | + |
| 9 | +```ruby |
| 10 | +user = { |
| 11 | + user: { |
| 12 | + address: { |
| 13 | + street1: '123 Main street' |
| 14 | + } |
| 15 | + } |
| 16 | +} |
| 17 | + |
| 18 | +user.dig(:user, :address, :street1) # => '123 Main street' |
| 19 | + |
| 20 | +results = [[[1, 2, 3]]] |
| 21 | + |
| 22 | +results.dig(0, 0, 0) # => 1 |
| 23 | +``` |
| 24 | + |
| 25 | +Both of these methods will return nil if any access attempt in the deeply nested structure returns nil: |
| 26 | +```ruby |
| 27 | +user.dig(:user, :adddresss, :street1) # => nil |
| 28 | +user.dig(:user, :address, :street2) # => nil |
| 29 | +``` |
| 30 | + |
| 31 | +### 2. Grep out the inverse of a pattern with Enumerable#grep_v |
| 32 | + |
| 33 | +This method is the inverse of the Enumerable#grep method. The grep method and its inverse provide several powerful ways to filter enumerables: |
| 34 | +Filtering by regular expression |
| 35 | + |
| 36 | +```ruby |
| 37 | +friends = %w[John Alain Jim Delmer] |
| 38 | + |
| 39 | +j_friends = friends.grep(/^J/) # => ["John", "Jim"] |
| 40 | +others = friends.grep_v(/^J/) # => ["Alain", "Delmer"] |
| 41 | +``` |
| 42 | + |
| 43 | +Filtering by types |
| 44 | +```ruby |
| 45 | +items = [1, 1.0, '1', nil] |
| 46 | + |
| 47 | +nums = items.grep(Numeric) # => [1, 1.0] |
| 48 | +others = items.grep_v(Numeric) # => ['1', nil] |
| 49 | +``` |
| 50 | + |
| 51 | +### 3. Fetching multiple values with Hash#fetch_values |
| 52 | + |
| 53 | +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: |
| 54 | + |
| 55 | +```ruby |
| 56 | +values = { |
| 57 | + foo: 1, |
| 58 | + bar: 2, |
| 59 | + baz: 3, |
| 60 | + qux: 4 |
| 61 | +} |
| 62 | + |
| 63 | +values.values_at(:foo, :bar) # => [1, 2] |
| 64 | +values.fetch_values(:foo, :bar) # => [1, 2] |
| 65 | + |
| 66 | +values.values_at(:foo, :bar, :invalid) # => [1, 2, nil] |
| 67 | +values.fetch_values(:foo, :bar, :invalid) # => KeyError: key not found: :invalid |
| 68 | +``` |
| 69 | + |
| 70 | +### 4. Positive and negative predicates for Numeric#positive? and Numeric#negative? |
| 71 | +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: |
| 72 | +```ruby |
| 73 | +numbers = (-5..5) |
| 74 | + |
| 75 | +numbers.select(&:positive?) # => [1, 2, 3, 4, 5] |
| 76 | +numbers.select(&:negative?) # => [-5, -4, -3, -2, -1] |
| 77 | +``` |
| 78 | + |
| 79 | +### 5. Hash superset and subset operators Hash#<=, Hash#<, Hash#>=, and Hash#> |
| 80 | +These methods lets you compare hashes to see if they are subsets or proper subsets of each other. For example: |
| 81 | +```ruby |
| 82 | +small = { a: 1 } |
| 83 | +medium = { a: 1, b: 2 } |
| 84 | +large = { a: 1, b: 2, c: 3 } |
| 85 | +different = { totally: :different } |
| 86 | + |
| 87 | +{ a: 1, b: 2 } > { a: 1 } # => true |
| 88 | +{ a: 1 } > { a: 1 } # => false |
| 89 | +{ b: 1 } > { a: 1 } # => false |
| 90 | +{ a: 1, b: 2 } < { a: 1, b: 2, c: 3 } # => true |
| 91 | +``` |
| 92 | + |
| 93 | +### 6. Convert a hash to a proc with Hash#to_proc |
| 94 | +Now you can use a hash to iterate over an enumerable object: |
| 95 | +```ruby |
| 96 | +hash = { a: 1, b: 2, c: 3 } |
| 97 | +keys = %i[a c d] |
| 98 | + |
| 99 | +keys.map(&hash) # => [1, 3, nil] |
| 100 | +``` |
| 101 | + |
| 102 | +Avoid nil related errors with the safe navigation operator |
| 103 | + |
| 104 | +### 7. New syntax for accessing deeply nested objects safely without accidentally triggering a dreaded NoMethodError on nil. |
| 105 | +The syntax looks like this: |
| 106 | +```ruby |
| 107 | +require 'ostruct' |
| 108 | +user&.address&.street&.first_line |
| 109 | +``` |
| 110 | + |
| 111 | +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. |
| 112 | +Experimental frozen string pragma |
| 113 | + |
| 114 | +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: |
| 115 | +```ruby |
| 116 | +$ ruby -v |
| 117 | +ruby 2.3.0preview1 (2015-11-11 trunk 52539) [x86_64-darwin14] |
| 118 | +$ cat default.rb |
| 119 | +# frozen_string_literal: false |
| 120 | + |
| 121 | +puts "Hello world".reverse! |
| 122 | +$ ruby default.rb |
| 123 | +dlrow olleH |
| 124 | +$ cat enabled.rb |
| 125 | +# frozen_string_literal: true |
| 126 | + |
| 127 | +puts "Hello world".reverse! |
| 128 | +$ ruby enabled.rb |
| 129 | +enabled.rb:3:in `reverse!': can't modify frozen String (RuntimeError) |
| 130 | + from enabled.rb:3:in '<main>' |
| 131 | +``` |
| 132 | +Alternatively, you can also enable and disable this using the command line argument --enable=frozen-string-literal |
0 commit comments