How do I determine my gem's required ruby version? - ruby

I am creating a gem and I have the suspicion that it may not work on certain Ruby versions. Is there a way to quickly check which Ruby versions it is compatible with? My current method is using RVM and switching to different Ruby versions to test, but that may be an inefficient way to do it. I was also wondering if I could narrow it down to a specific patch version.

#Matt Schuchard suggested the right way to do this (in the comment)
For example, you can check how to do this with GitHub Actions. You can test it not only for specific ruby version but also on different OSes
https://github.com/metanorma/metanorma/blob/master/.github/workflows/rake.yml

Related

How to check for API compatibility between Ruby versions?

Our team maintains a ruby script that must support any ruby >= 1.9.3 (yes, that's a pretty old ruby version but this is something outside our control at the moment). Recently, we added a change that included the verification of a regexp using match? and everything was going well until one of the users reported that the script was exploding for ruby 2.3 with the message:
undefined method `match?' for #<Regexp:0x000000018471e0> (NoMethodError)
Turns out this happens because the match? method is available in ruby >= 2.4.
We have been running ruby -c script.rb with multiple versions of ruby (1.9.3, 2.0.0, 2.1.10, 2.3.7, 2.5.1, 2.6.3, 2.7.4) as part of our test suite and this didn't show up as a syntax error and I suspect it's because the actual syntax is "correct" but the method is simply not available in some versions of ruby. We also tried rubocop, hoping that it could detect these incompatibility issues but it doesn't report any error either.
So, my question is, what's the best way to check for this API compatibility issues between multiple ruby versions?
Running ruby -c with the oldest Ruby you support is a good start, as it will detect if you are trying to use a newer syntax.
For using methods that are new:
Run your tests suite in both the oldest and newest Ruby versions you want to support.
Consider using my backports gem to make it possible to use newer API even on old Rubies. For example, it includes Regexp.match? among the hundreds of backports...
Do you have an automated test suite? If so, you can set up your CI to test against multiple Ruby versions, e.g.:
https://github.com/actions/setup-ruby#usage
(Edit: I see you did mention a test suite, so it sounds like you have a gap in the test coverage, or you're not running the tests against each Ruby version?).

Do old gems always work on later versions of ruby?

I am using a quite recent version of ruby (2.5.1) but some old gems. I am having some issues. I was wondering, is it correct that some gems work only with certain versions of ruby?
If a gem worked with ruby 2.3.0, is it true that it will definitely work with 2.5.1 (i.e. because 2.5.1 > 2.3.0)? Or is that not always the case?
I guess what I'm asking is are newer ruby versions always backwards compatible with older gems?
If a gem worked with ruby 2.3.0, is it true that it will definitely
work with 2.5.1
This is not correct. Programming languages are evolving while growing. This means language maintainers are doing lots of improvements or refactorings that they are new features or removing old components from the language. When the language community announces for new features or removing old feature such as Fixnum in ruby, the developers should follow the instructions and refactor their codebase accordingly. In other words, developers should have a good test coverage to detect any fail and fix it instantly.
In your scenario, as well as I understand you do not have a test coverage. The only but the simple thing should do is just upgrade your gems' versions to latest.
Gem is simply a plug-in library written in Ruby.
Of course, Ruby is developing, new features are appearing, old ones are disappearing.
It's best practice to specify Ruby version in .gemspec file. For example, like this one.
But if not, then you have to manually check the performance. So you can read gem source code or try to use your gem and check it.
For automation, of course, it is best to use tests.
Starting at Ruby 2.1.0 the version policy has been that a change in the MINOR version may introduce API breaking changes.
Should any gem happen to use an API that changes, an incompatibility will arise.
The MINOR version number has changed twice between 2.3.* and 2.5.* so even if a gem happens to have been written in accordance with the documented API, there's no guarantee that it will continue to work unless the gem's maintainer takes the effort to test the gem (and upgrade it if necessary). Automated test suites help a lot.
A standard way to document version compatiblity that is actually tested against is by providing required_ruby_version in .gemspec files.
Interestingly, if a particular gem is really badly written, I imagine it might break even between compatible versions of Ruby. That's not something I've encountered in the Ruby ecosystem but I've made a similar mistake writing Java code (and Java is famous for its backward compatibility) where my own code accidentally used a class that wasn't part of the API. There are many gems. Who knows what's out there? :)

Can I get rubygems to ignore gem version conflicts?

I have done a bit of digging through the rubygems code and it doesn't look like there is a built-in way to get it to not throw a Gem::ConflictError even if there is one. During development I might be wanting to test something that I know is not going to touch the code from which the conflict is coming or I know that the whatever version of the erstwhile conflicting gem isn't going to cause a problem. I just want to get on with testing what I want to test and I'll worry about version conflicts later.
I know I can hack rubygems to do this. I can think or multiple ways to get it done. I'm just kind of curious if anyone has already done this, how they did it, and maybe if that code has been shared somewhere. I'm also a bit curious as to why this isn't built in to rubygems as a development tool.
You need to worry about version conflicts now before you can get anything done. As Ruby has a singular root namespace and every dependency gets loaded there it's generally not possible to load multiple versions of the same gem. Other systems like NPM for Node.js are significantly more flexible, it's possible to load any number of versions at the same time, so if you're used to that you'll need to adjust your expectations.
If you're trying to do testing and you want to avoid resolving a conflict, just remove that gem requirement from the Gemfile temporarily.
Ultimately you'll have to fix things, there's no way around it, but you can always be selective about what you require.
If you really know what you are doing, try this:
export NOEXEC_DISABLE=1
ruby you-program.rb
This environment variable will disable search and check for Gemfiles and gem versions.

How can I find what version of ruby an app was written for?

I'm using rvm on Ubuntu 12 to manage ruby versions/gemsets. I am testing various projects and some gems won't work with certain versions of Ruby or with each other. Is it possible to find which version of ruby an app was written for, so I can set my rvm to use that version and get the right gems when I run bundle install?
You can lookup the gems on rubygems.org. They are supposed to list what version of ruby they are compatible with, but that may not always be kept up to date.
If that doesn't narrow it down, you can check the gem's CHANGELOG file on github.
In the end, you may have to just try a few. There's only a handful of versions in common use, so it's not like you have to try then all.
in my experience ruby 1.9.3 is most widely supported at the time of this writing. Ruby 2.0 and 2.1 would also be good to try. 1.8.7 is pretty old and will likely give you a good bit of trouble, but it was the standard for a long time.

Benefits of RVM

Why should I/should I not use RVM?
I'm new to the ruby language and servers as a whole. I've had some trouble installing using RVM...so I'm inclined to not use it right now, but it seems like it may make installations down the road easier?
I'm interested to hear about your experience with RVM and your thoughts as it pertains to maintaining a server.
RVM is useful even if you don't want to install multiple versions at the same time. I'm a ruby hobbyist (PHP during the day :(), and I have no reason to want to use old versions, but I still use RVM.
Installing ruby is a pain. Getting it from the package manager (at least in ubuntu) gives you an outdated version that changes installation directories from the defaults. I've had nothing but problems with it.
So you think, "I'll just build it from source". Building from source requires getting a load of dependencies and configuring options. Often times I've built ruby only to find out I forgot to enable SSL support or readline support.
RVM takes care of all of this. In 3 or so commands, you have a perfectly built version of ruby.
And I didn't even cover how RVM manages multiple ruby installations for you, which is its killer feature. If you have that need, there is really no other sane solution.
RVM is great as this allows your to install different versions without touching your system's default Ruby install. It is rather similar to virtualenv's in Python.
Another great advantage to having RVM are the gemsets - you can create as many gemsets that are unique to the version, and patch level, of ruby.
I've extolled some of its virtues here and you should also see this blog post.
In terms of maintaining a server - let's take a Passenger install for example; do remember that Passenger is installed as a gem, so with rvm the benefit here is that you can have multiple installs of passenger, tied to a different version of ruby. Of course, typically, you'll have Passenger running on one version at a time, although there are ways to have Passenger, in particular, running on different ruby versions.
I use different Ruby versions for different projects (that's where .rvmrc is really handy). Some deployment environments are happy with 1.9, while there are a couple of legacy servers using 1.8 for some reasons. Also, occasionally I want to launch a specific version of ruby to compare how they work. RVM does all that for me.
When you are first getting used to Ruby, it may not entirely be necessary. That said, what it does is set you up for success in the future. Because once you get hooked, you may end up playing with projects that need to move from, say, MRI 1.8.x to 1.9.x. Or from 1.9.x, to JRuby 1.6.x. My experience is that this happens irregularly, but when it does, there's no substitute for RVM.
Outside of that, the other biggest feature that I use regularly, is the ability to segment one particular release. So I can have an environment for 'stable' gems, and an environment for 'unstable' gems. For instance, while Rails 3.1 has been in release candidate mode, I've had one main workspace for 1.9.2 and a separate space for Rails 3.1.rc? gems on 1.9.2. That makes it possible for me to keep developing my main Rails 3.0 stuff (with one command at the CLI), without having to specify full file paths to the appropriate rails bin files in order to use the older files.
If you're using a Debian based platform where the packagers/policy leads to a really bad default installation you'll have a way better experience using rvm.

Resources