# Pessimistic Prerelease Peculiarities

> We show that a commonly held assumption about the pessimistic requirement operator isn't necessarily always true, specifically when dealing with prerelease gem versions

- URL: https://velocitylabs.io/blog/2015/05/08/pessimistic-prerelease-peculiarities/
- Published: May 8, 2015
- Author: Dave Tapley

### The assumption

There seems to be an [assumption](https://robots.thoughtbot.com/rubys-pessimistic-operator) that the pessimistic requirement operator (aka `~>`, aka the _twiddle-wakka_) is short hand for a pairing of `>=` and `<`.

e.g: in a `Gemfile` we see `~> 1.1` as equivalent to: `'>= 1.1' '< 2.0'`.

That seems reasonable, but be warned, it breaks down when [prerelease](https://guides.rubygems.org/patterns/#prerelease-gems) gems are involved.

### The code

Firstly, here’s a method to check a gem’s version against some requirements:

```ruby
def check(version, *requirements)
  requirements.map { |v| Gem::Requirement.new(v).satisfied_by? Gem::Version.new(version) }.all?
end
```

We can use this to check if `~> 1.2` does behave indeed the same as `'>= 1.1' '< 2.0'`. Let’s check both a good version (which meets the requirements) and a bad version (which does not):

```ruby
> good_version = '1.8'
> [check(good_version, '~> 1.1'), check(good_version, '>= 1.1', '< 2.0')
 => [true, true]
```

```ruby
> bad_version = '2.0'
> [check(bad_version, '~> 1.1'), check(bad_version, '>= 1.1', '< 2.0')]
 => [false, false]
```

So far, so good.

### The peculiarity with prerelease

However, this equivalence doesn’t hold when the version being checked is a [prerelease](https://guides.rubygems.org/patterns/#prerelease-gems):

```ruby
> pre_version = '2.0.pre'
> [check(pre_version, '~> 1.1'), check(pre_version, '>= 1.1', '< 2.0')]
 => [false, true]
```

We can see that the pessimistic operator doesn’t think this prerelease gem meets the requirement, but our supposedly ‘equivalent’ version does. What gives?

It happens because a _less than 2.0_ requirement is _true_ if the version is a prerelease of 2.0:

```ruby
> check '2.0.pre', '< 2.0'
 => true
```

However a _pessimistic 1.1_ requirement is false if the version is a prerelease of 2.0:

```ruby
> check '2.0.pre', '~> 1.1'
 => false
```

### Making sense of it

Rephrasing those two versions as questions, it’s clear that both these answers make sense:

- Should a prerelease of N be considered a lower version N? **Yes.**
- Should a prerelease of N+1 be pessimistically compatible with version N? **No.**

It is in fact our initial assumption that `~> 1.1` is equivalent to: `'>= 1.1', '< 2.0'` that is incorrect.

So it seems in the absence of anyway to express _“less than version 2.0 and any prerelease thereof”_ that the pessimistic operator is more than just a convenient short hand, it’s the only correct way to specify a requirement pessimistically.
