Ruby Version Changes
Each version of Ruby includes a set of new features and methods. This documentation list out the new changes that were introduced from Ruby version 2.5 onwards.
New Features and Functions added to Ruby 2.5
Features
#1 Reverse Stack Trace:
One of the major feature that was introduced in Ruby 2.5.0 is Reverse Stack Trace.
Before Ruby 2.5, the printed backtrace contained the exception class and the error message at the top. Next lines will contain the location of the various cascaded method calls. This made it difficult to read the error message as it is difficult to display the whole backtrace in the visible viewport of the terminal.
So from Ruby 2.5 onwards, the backtrace was printed in reverse order. That is an error message and exception class is printed last at the backtrace. Also, a frame number was also added with each line.
Example
irb(main):001:0>1/0
Traceback (most recent call last):
5: from /home/arun/.rbenv/versions/2.5.3/bin/irb:23:in `<main>’
4: from /home/arun/.rbenv/versions/2.5.3/bin/irb:23:in `load’
3: from /home/arun/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.3/gems/irb-1.0.0/exe/irb:11:in `<top (required)>’
2: from (irb):1
1: from (irb):1:in `/’
ZeroDivisionError (divided by 0)
#2 Allows rescue/else/ensure inside do/end blocks:
Before Ruby 2.5.0 it was not possible to add rescue/else/ensure blocks inside do/end blocks. If it was added an error will be thrown.
SyntaxError: (irb):4: syntax error, unexpected keyword_rescue,
expecting keyword_end
This was fixed in 2.5.0 and the rescue/else/ensure can be written in a do/end block.
Example Code
array.each do |number|
p 10 / number
rescue ZeroDivisionError => exception
p exception
next
end
end
#3. Significant Performance Improvement
According to docs Ruby 2.5,0 brought about 5–10% performance improvement. Some observations related are
- String interpolation will be around 72% faster when a large string is created
- String#prepend will be around 42% faster if only one argument is given
- Enumerable#sort_by, Enumerable#min_by & Enumerable#max_by will be about 50% faster
- Mutex is rewritten to be smaller and faster
- ERB now generates code from a template twice as fast as Ruby 2.4
One of the optimizations done is to use OPTIMIZED_CMP() to compare the objects instead of <=> method.
Functions
#1 Kernel#yield_self
Kernel#yield_self works similarly to the method Object#tap, but they return different values.
Object#tap yields self to the block and then returns self.
Example
(1..10).tap { |x| puts “original: #{x}” }
.to_a.tap { |x| puts “array: #{x}” }
Returns
# => original: 1..10
# => array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Kernel#yield_self yields self to the block and then returns the result of the block execution.
(1..10).yield_self{|x| puts “original: #{x}”
Returns
original: 1..10
=> nil
#2 Hash#transform_keys/Hash#transform_keys!
Hash#transform_keys is added for transforming keys of the hash., which is similar to the transform_values function present in Ruby 2.4.
Example
h = { name: “arun”, email: “arun@example.com” }
=> {:name=>”arun”, :email=>”arun@example.com”}
h.transform_keys { |k| k.to_s }
=> {“name”=>”arun”, “email”=>”arun@example.com”}
Hash#transform_keys! is also added which changes the hash in place.
#3 Hash#slice
Hash#slice is a simple method to select key-value pairs from a hash with specified keys.
Example
blog = { id: 1, name: ‘Ruby 2.5’, description: ‘Blog’ }
To get name and description from this hash.
Before 2.5
blog.select { |key, value| [:name, :description].include?(key) }
=> {:name=>”Ruby 2.5", :description=>”Blog”}
After
blog.slice(:name, :description)
=> {:name=>”Ruby 2.5", :description=>”Blog”}
#4 String#delete_prefix / String#delete_suffix
Earlier in Ruby inorder to delete suffix part we were using the method chomp. However there was no method to delete prefix part this was fixed by adding two methods String#delete_prefix and String#delete_suffix
Usage
Projects::CategoriesController”.delete_prefix(“Projects::”) => “CategoriesController”Projects::CategoriesController”.delete_suffix(“Controller”)
=> “Projects::Categories”
#5 Enumerable#any?, all?, none?, and one? accept a pattern argument
Ruby has sequence predicates such as all?, none?, one? and any? which take a block and evaluate that by passing every element of the sequence to it.
The usage before 2.5 was
queries.any? { |sql| /LEFT OUTER JOIN/i =~ sql }
Ruby 2.5 introduced a shorthand for this, which is as follows.
queries.any?(/LEFT OUTER JOIN/i)
Internally case equality operator(===) is used against every element of the sequence and the pattern argument.
So this translates to
queries.any? { |sql| /LEFT OUTER JOIN/i === sql }
This feature is applicable to all?, none?, one? and any? Methods.
#6 Struct.new can create classes that accept keyword arguments
Before Ruby 2.5 it was not possible to declare Ruby Structs using keyword params. With Ruby 2.5 this can be done using the keyword_init option
Usage:
Struct.new(:fname, :lname, keyword_init: true)my_struct = MyStruct.new(fname: ‘first’, lname: ‘last’)
New Features and Functions added to Ruby 2.6
Features
#1 Just In Time Compiler
Ruby 2.6 introduces an initial implementation of a JIT (Just-In-Time) compiler.
The JIT compiler aims to improve the performance of Ruby programs. Unlike traditional JIT compilers which operate in-process, Ruby’s JIT compiler writes out C code to disk and spawns a common C compiler to generate native code
In order to enable the JIT compiler, specify — jit on the command line or in the $RUBYOPT environment variable. Specifying — jit-verbose=1 will cause the JIT compiler to print additional information
#2 Performance Improvement
Transient Heap support added for ruby reduces the footprint of short-living memory objects which reduced the memory consumption of short living Hash objects by about 7%.
Also, it has been noted that Proc#call is now around 1.4x faster. This is done by removing the temporary allocation for $SAFE. $SAFE is now a process global state and it can be set back to 0
Combined with improvements around block handling introduced in Ruby 2.5, block evaluation now performs 2.6x faster in a micro-benchmark in Ruby 2.6.
#3 Range#=== now uses cover? rather than include?
This makes it possible for case statements like
case DateTime.now
when Date.today..Date.today + 1
‘win!’
else
‘fail’
End
#4 Bundler is now installed as a default gem.
#5 Syntax Error when else without rescue
In exception handling blocks, else without rescue now causes a syntax error
#6 Constant names may start with a non-ASCII capital letter
Functions
#1 Endless Ranges
Ruby introduces the (0..) range.
ary[1..] # identical to ary[1..-1]
(1..).each {|index| … } # infinite loop from index 1
#2 Array#union and Array#difference
An easier way to find the difference and union multiple arrays.
[1, 1, 2, 2, 3, 3, 4, 5 ].difference([1, 2, 4])
#=> [ 3, 3, 5 ]
[“a”, “b”, “c”].union([“c”, “d”, “a”])
#=> [ “a”, “b”, “c”, “d” ]
#3 Array#filter is a new alias for Array#select
[:foo, :bar].filter { |x| x == :foo } # => [:foo]
#4 Enumerable#to_h now accepts a block that maps keys to values
Before 2.6 in order to convert an array into hash, an intermediate array was required.
(1..5).each_with_object({}) { |x, h| h[x] = x ** 2 }(1..5).map { |x| [x, x ** 2] }.to_h
From 2.6 onwards the to_h allow to use a block which eliminates the intermediate array,
(1..5).to_h { |x| [x, x ** 2] } #=> {1=>1, 2=>4, 3=>9, 4=>16, 5=>25}
#5 Hash#merge, merge! now accept multiple arguments
A variable amount of arguments when merging hashes
hash1.merge(hash2, hash3)
#6 The #then method
The then method is an alias to yield_self. This was introduced to improve readability.
Usage
events = Event.upcoming
events = events.limit(params[:limit]) if params[:limit]
events = events.where(status: params[:status]) if params[:status]
Events
becomes
Event.upcoming
.then { |events| params[:limit] ? events.limit(params[:limit]) : events }
.then { |events| params[:status] ? events.where(status: status) : events }
# or
Event.upcoming
.then(&method(:with_limit))
.then(&method(:with_status))
#7 Random.bytes
This function can be used to generate random bytes
Usage
Random.bytes(8) # => “\xAA\xC4\x97u\xA6\x16\xB7\xC0\xCC”
#8 Binding#source_location
This method returns the source location of the binding, a 2-element array of __FILE__ and __LINE__. It is recommended to use Binding#source_location instead of Kernel#eval
References
https://www.ruby-lang.org/en/news/2018/12/25/ruby-2-6-0-released/
https://www.ruby-lang.org/en/news/2017/12/25/ruby-2-5-0-released/
https://ruby-doc.org/core-2.6.0.preview2/
https://www.reddit.com/r/ruby/comments/9wmpqk/whats_new_in_ruby_26/e9oe3q3/
https://www.rubyguides.com/ruby-version-changes/
https://blog.bigbinary.com/2018/01/02/ruby-2-5-enumerable-predicates-accept-pattern-argument.html
https://blog.bigbinary.com/2017/11/28/ruby-2-5-added-delete_prefix-and-delete_suffix-methods.html
https://bogdanvlviv.com/posts/ruby/new-method-kernel-yield_self-since-ruby-2_5_0.html
https://medium.com/@k0kubun/the-method-jit-compiler-for-ruby-2-6-388ee0989c13