All(most all) you need to know about Ruby 2.7
It's Christmas day and as per the tradition the Ruby core team will release has released Ruby 2.7 today. Ruby 2.7 is last release before the big major version upgrade to Ruby 3.0 coming up in 2020. Ruby 2.7 has lot of interesting features, some changes that you may not like, some changes that you will definitely like. It also builds the foundation for Ruby 3 by introducing warnings, deprecations and experimental features. In this post, you will learn everything that you need to know about Ruby 2.7
Improved IRB
The IRB now supports syntax highlighting, inline editing of methods. It also supports auto completion. It auto indents the code as we type.
Numbered parameters
We can access the arguments passed to the block by using _1
_2
etc.
[1, 2, 10].map { _1.to_s(16) } #=> ["1", "2", "a"]
I found out that this feature seems to be really useful when there is only argument being passed to the block.
For eg.
[1,2,3].map { _1 * 3 }
=> [3, 6, 9]
You can also use it with blocks which get multiple arguments.
[1,2].each_with_index { p _1 }
1
2
=> [1, 2]
[1,2].each_with_index { p _2 }
0
1
=> [1, 2]
Discussion -
https://bugs.ruby-lang.org/issues/4475
https://bugs.ruby-lang.org/issues/15723
Pattern matching
Pattern matching is added to Ruby 2.7 as experimental feature. We can use it in the case
statements.
case [0, [1,2,3]]
in [a, [b, *c]]
p a
p b
p c
end
(irb):6: warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!
0
1
[2, 3]
It also supports hash destructuring.
params = { name: "john", email: "john@example.com" }
case params
in { name: a, email: b }
p a
p b
end
(irb):18: warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!
"john"
"john@example.com"
=> "john@example.com"
We get the warning that this feature is experimental :) Also Matz mentioned in his 2019 Rubyconf keynote that pattern matching is slow. But we can still give it a try!
Discussion -
https://bugs.ruby-lang.org/issues/14912
Argument forwarding
This is really cool feature. If you want to just pass all the arguments of the current method to a new method, Ruby 2.7 makes it dead easy with the help (...)
.
def hello(...)
Greeter.new.hello(...)
end
The paranthesis around ...
are mandatory.
Discussion -
https://bugs.ruby-lang.org/issues/16253
Manual compaction of Ruby's GC
A new method GC.compact
is introduced to compact Ruby's GC so as to reduce the heap fragmentation. This operation runs a full GC, compacts the heap and then runs full GC again. The GC.compact
method can be called by library authors to compact the GC. Application developers mostly will not need to call it as part of the application code. For eg. Puma now compacts GC just before the fork.
Aaron's talk linked below on this topic is worth checking out to understand how this feature works and what problems it tries to solve.
Discussion -
https://bugs.ruby-lang.org/issues/15626
Benchmark -
https://gist.github.com/tenderlove/99112e9fcc85d9c6c7d9d0ea40063fc6
Aaron's talk from Rubyconf 2019 -
Introducing FrozenError#receiver
FrozenError is raised when we try to modify a frozen object. The receiver
method will return the object on which modification was attempted. This will help in debugging.
In the docs it is mentioned that when you are raising FrozenError, the second argument can be passed as the receiver
object but I am getting an error if I pass second argument to FrozenError
on Ruby 2.7.0-rc2.
FrozenError.new("error message", "receiver")
Traceback (most recent call last):
5: from (irb):68
4: from (irb):69:in `rescue in irb_binding'
3: from (irb):69:in `new'
2: from (irb):69:in `initialize'
1: from (irb):69:in `initialize'
ArgumentError (wrong number of arguments (given 2, expected 0..1))
Introducing Module#const_source_location
Method#source_location
is my favourite debugging method. It returns the location where a method is defined. Similarly, Module#const_source_location
will return location where the constant is defined.
Repo.const_source_location(:CLASS_FOR_DOC_LANGUAGE)
=> ["/Users/prathamesh/Projects/sources/codetriage/app/models/repo.rb", 23]
Discussion -
https://bugs.ruby-lang.org/issues/10771
Improvements to JIT
There have been improvements made to the JIT compiler which introduced in Ruby 2.6. You can run your Rails application with JIT by adding a flag like this:
Real keyword arguments
Biggest change in Ruby 2.7 which has maximum impact in all of our existing code is with the way keyword arguments will be handled in Ruby going forward.
Before Ruby 2.7, the keyword argument is a normal argument that is a Hash object and is passed as the last argument. In Ruby 3, a keyword argument will be completely separated from normal arguments like a block parameter that is also completely separated from normal arguments. In Ruby 2.7 a warning is displayed when a normal argument is used instead of keyword argument. If you try to run a Rails app on Ruby 2.7, your terminal will be filled with warnings such as:
/Users/prathamesh/.rbenv/versions/2.7.0-rc2/lib/ruby/gems/2.7.0/gems/activerecord-6.0.2/lib/active_record/type.rb:27: warning: The last argument is used as keyword parameters; maybe ** should be added to the call
/Users/prathamesh/.rbenv/versions/2.7.0-rc2/lib/ruby/gems/2.7.0/gems/mustermann-1.0.3/lib/mustermann/ast/compiler.rb:43: warning: The last argument is used as keyword parameters; maybe ** should be added to the call
This change is causing the logs flooded with these warnings. This change is explained here with possible solutions. If you are using Rails, there are lot of warnings related to this change. But they are being fixed one by one. We will have to wait for a Ruby 2.7 compatible Rails release to get rid of all of the warnings.
But if you want, you can get rid of most of these warnings at this very moment as well. Check out how to do it - https://prathamesh.tech/2019/12/26/managing-warnings-emitted-by-ruby-2-7/
And much more..
There are so many changes that I have not covered in this blog post. Honourable mentions are Enumerable#tally
, Enumerable#filter_map
, begin and endless ranges. For full list of changes, checkout this.
Bonus
Here is a list of gems which have fixed the warnings from Ruby 2.7.
If you are on Heroku, you can give Ruby 2.7 try at this very moment because it is already available 🥳 https://blog.heroku.com/ruby-2-7-0-holiday-release
If you are using chruby
or rbenv
or rvm
, Ruby 2.7.0 is available for installation. Ruby core team has provided a docker image for Ruby 2.7.0 as well. You can use it as follows:
docker run -it --rm rubylang/ruby irb
Ruby 2.7.0 is also available on Travis CI and Circle CI.
I am looking for remote work related to Ruby/Rails. Please get in touch with me on csonpatki@gmail.com if you are looking to hire me! More details about me here.