Most Ruby projects have a .ruby-version
file that is used by different version managers to automatically switch Ruby version based on the content of that file. Very useful if you have many projects with different Ruby versions.
But the same Ruby version is also sometimes declared in the project’s Gemfile
.
You might have something like
Your .ruby-version
1
3.2.0
Your Gemfile
1
ruby "3.2.0"
Both are the same values but on a different file, if you need to update your Ruby version, you would need to update both which is a bit tedious and prone to forgetting.
When you somehow got a mismatched version on those files you might get the following error:
1
Your Ruby version is 3.2.0, but your Gemfile specified 3.1.0
How do we improve it?
Gemfile
is just another Ruby script that is executed when running bundle
, you can just treat it as a simple Ruby script.
In your Gemfile
you can do:
1
ruby File.read(File.join(__dir__, ".ruby-version")).strip
I have seen on other sources that they are using a shorter version such as:
1
ruby File.read(".ruby-version").strip
The problem with this is that bundle
stops working if you navigate into a directory.
An example on where this is necessary is on a React Native app, where the Gemfile
and .ruby-version
is on the root directory but you have to run cd ios; bundle exec pod install
, that code raises the following error.
1
2
3
4
5
6
7
8
[!] There was an error parsing `Gemfile`: No such file or directory @ rb_sysopen - .ruby-version. Bundler cannot continue.
# from /Users/davidangulo/myapp/Gemfile:5
# -------------------------------------------
#
> ruby File.read(".ruby-version").strip
#
# -------------------------------------------
Because .ruby-version
is no longer present in my current directory which is ios
.
To make bundle
work on any subdirectory, I used File.join(__dir__, ".ruby-version")
, where __dir__
is the current directory of the Gemfile
, this assumes that the Gemfile
and .ruby-version
are always in the same directory. So instead of executing in the current
directory it executes based on the Gemfiles
directory.
Conclusion
We have now DRYed our Ruby version declaration and only needs to be changed in one place instead of multiple.
You can use the shorter version if you don’t need to run bundle
on a subdirectory.
Use the longer version to make it path agnostic and works everywhere on your project.