130

I often see the following notation(~>) in Gemfile.

gem "cucumber", "~>0.8.5"
gem "rspec", "~>1.3.0"

I know the sign (>=) is just greater or equal to, but what does the (~>) notation mean? Are they both same or has any significant difference?

alxndr
  • 3,851
  • 3
  • 34
  • 35
millisami
  • 9,931
  • 15
  • 70
  • 112

2 Answers2

179

That's a pessimistic version constraint. RubyGems will increment the last digit in the version provided and use that until it reaches a maximum version. So ~>0.8.5 is semantically equivalent to:

gem "cucumber", ">=0.8.5", "<0.9.0"

The easy way to think about it is that you're okay with the last digit incrementing to some arbitrary value, but the ones preceding it in the string cannot be greater than what you provided. Thus for ~>0.8.5, any value is acceptable for the third digit (the 5) provided that it is greater than or equal to 5, but the leading 0.8 must be "0.8".

You might do this, for example, if you think that the 0.9 version is going to implement some breaking changes, but you know the entire 0.8.x release series is just bugfixes.

However, simply using ">=0.8.5" would indicate that any version later than (or equal to) 0.8.5 is acceptable. There is no upper bound.

eldarerathis
  • 35,455
  • 10
  • 90
  • 93
  • How does this behave with gems which use four digits for their versioning such as [backbone-on-rails](https://github.com/meleyal/backbone-on-rails)? – JJD Nov 14 '12 at 17:13
  • 2
    @JJD: It should be basically the same behavior. The last digit of the four can be incremented without bound, but the third would not (so `~>0.9.2.3` would allow for v0.9.2.4 or v0.9.2.23 but not v0.9.3.0). If you only specified 3 digits in the constraint then the fourth would be essentially irrelevant - it would only be constrained based on the first three that you specify (e.g. `~>0.9.2` would accept anything within a 0.9.x.y series, regardless of what `y` is; the constraint is that the 9 can't be incremented). – eldarerathis Nov 14 '12 at 17:17
  • 3
    There is an exception to the rule that "RubyGems will increment the last digit in the version" though: when you supply one digit. You might expect "~> 4" to mean "Any version 4 or higher", but [it doesn't](http://stackoverflow.com/questions/24121960/why-does-the-gemfile-semantic-versioning-operator-produce-inconsistent-resu), so be careful. – hlascelles Jun 11 '14 at 21:20
  • 2
    What about ~>0.1 vs. ~>0.1.0? If we think of it as "you're okay with the last digit incrementing to some arbitrary value", ~>0.1 translates to >=0.1.0 <1.0.0 while ~>0.1.0 translates to >=0.1.0 < 0.2.0. Is that correct? – Wei Jul 15 '14 at 01:29
  • When I see a GitHub project saying it requires ruby >= 2.4.4, can I assume they support all ruby after 2.4.4 including 2.5.1 and even ruby 3? Or should we play safe (i.e. instead of thinking they will support all ruby after 2.4.4 inclusive, I should think they mean they will not support any ruby before 2.4.4)? – Henry Yang Jun 07 '18 at 00:30
  • @Wei You are right, it is correct to say ~>0.1 translates to >=0.1.0 <1.0.0 while ~>0.1.0 translates to >=0.1.0 < 0.2.0. For reference, see https://guides.rubygems.org/patterns/#pessimistic-version-constraint and search for "Pessimistic version constraint" – Henry Yang Jun 07 '18 at 01:19
3

@millisami You can even use to add dependencies with the gemspec using the pessimistic constraint like this:

gem.add_runtime_dependency "thor", "~> 0.18.1"

If you don't know much about gem development or are just getting into it, these are some good references:

  1. Tutorial that teaches you how to make your own RubyGem, the standard practices associated with it, and how to upload it so that others can install it.
  2. How to create a Gem from scratch with Bundler
strangeloops
  • 1,484
  • 2
  • 11
  • 14