Browse Source

New chapter on RubyGems (first chapter in Markdown)

master
Peter J. Jones 7 years ago
parent
commit
865ff1e0f7
2 changed files with 145 additions and 0 deletions
  1. 138
    0
      chapters/rubygems.md
  2. 7
    0
      notes/rubygems.md

+ 138
- 0
chapters/rubygems.md View File

@@ -0,0 +1,138 @@
# RubyGems

## Version Selection

When writing an application in Ruby it's likely that you'll make use
of several open source libraries that come packaged as [RubyGems].
But do you know which versions of those gems are getting loaded into
your application? Will all versions work with your application?

It doesn't matter if you are loading gems into your application
directly using `require` statements or using a tool like [Bundler],
you should always use version specifiers to future proof your
application.

### Using Version Specifiers

It's often tempting to load a library without regard for which version
you are about to use:

~~~~ {.ruby}
# In your application's source code
require('nokogiri')

# Or, in a Bundler Gemfile
gem('nokogiri')
~~~~

But that's equivalent to using the following version specifiers:

~~~~ {.ruby}
# In your application's source code
gem('nokogiri', '>= 0.0')
require('nokogiri')

# Or, in a Bundler Gemfile
gem('nokogiri', '>= 0.0')
~~~~

As you can see, version specifiers are comprised of a version operator
and a version number. Omitting the version specifier or using the
`>=` version operator is almost always a bad idea.

The code above means that you'll happily use any version of
the Nokogiri gem. But is that a true statement? Will your code
really work with any version? What about really old versions of
Nokogiri? What about the version of Nokogiri that's going to be
released in 2 years?

It's easy to imagine a situation where you upgrade a gem to support a
new application and in the process break an old application. If the
older application had a restrictive version specifier it would keep
working as long as you had a compatible version of the gem installed.

I said it's *almost* always a bad idea to use `>=` because there's at
least one legitimate use for it. RubyGems allows you to give more
than one version specifier and Bundler supports this as well:

~~~~ {.ruby}
gem('nokogiri', '>= 1.0.0', '< 2.0.0')
~~~~

Which means that you'll take any version of Nokogiri starting at 1.0.0
but not 2.0.0 or higher. Combining version specifiers like this gives
you a lot of control over which version is going to be loaded into
your application, but it's a bit cumbersome. If all you want to do is
restrict a gem to a specific major release (e.g. 1.x but not 2.x) then
you can use the pessimistic version operator (`~>`).

### The Pessimistic Version Operator

The pessimistic version operator (`~>`) allows you to state that your
application works with future versions of a gem in a safe way. Of
course this only works if the author of that gem introduces changes
that break backward compatibility in a predictable way (e.g. going
from version 1.0.0 to 1.0.1 doesn't break your application).

For example, if you trust that the authors of the Nokogiri gem won't
break backwards compatibility until version 2.0.0 you can load the gem
using the pessimistic version operator:

~~~~ {.ruby}
gem('nokogiri', '~> 1.0')
~~~~

But, if you only trusted them to maintain backwards compatibility in
the 1.5.x releases you could specify the version as:

~~~~ {.ruby}
gem('nokogiri', '~> 1.5.0')
~~~~

The pessimistic version operator can be controlled by how specific you
make the version number. It works by stripping off the last digit you
specify and incrementing the remaining version. So 1.5.0 becomes 1.6
and 1.0 becomes 2.0. It then restricts the version of the gem
starting with the version you specified up to but not including the
incremented version. Here are some examples:

+-----------------------------------+-----------------------------------------+
|Pessimistic Version |Range Restriction |
+===================================+=========================================+
|`gem('nokogiri', '~> 1.0')` |`gem('nokogiri', '>= 1.0', '< 2.0')` |
+-----------------------------------+-----------------------------------------+
|`gem('nokogiri', '~> 1.5.0')` |`gem('nokogiri', '>= 1.5.0', '< 1.6.0')` |
+-----------------------------------+-----------------------------------------+
|`gem('nokogiri', '~> 1.5.3')` |`gem('nokogiri', '>= 1.5.3', '< 1.6.0')` |
+-----------------------------------+-----------------------------------------+

### Available Operators

RubyGems provides a complete set of version operators that allow you
to specify which versions of a gem your application can work with. If
you don't use an operator and just use a version number you lock your
application to that specific version, it's shorthand for using the
equal (`=`) operator.

Here's a list of the of the operators supported in RubyGems:

+---------+-----------------------------------------+
|Operator |Meaning |
+=========+=========================================+
|`=` |Equal to (default) |
+---------+-----------------------------------------+
|`!=` |Not equal to |
+---------+-----------------------------------------+
|`>` |Greater than |
+---------+-----------------------------------------+
|`<` |Less than |
+---------+-----------------------------------------+
|`>=` |Greater than or equal to |
+---------+-----------------------------------------+
|`<=` |Less than or equal to |
+---------+-----------------------------------------+
|`~>` |Pessimistically greater than or equal to |
+---------+-----------------------------------------+

[rubygems]: http://docs.rubygems.org/
[bundler]: http://gembundler.com/

+ 7
- 0
notes/rubygems.md View File

@@ -0,0 +1,7 @@
% Notes for the RubyGems Chapter

# Links

* [Gemfile Docs](http://gembundler.com/man/gemfile.5.html)
* [Version Specifiers](http://docs.rubygems.org/read/chapter/16)
* [>= Considered Harmfull](http://yehudakatz.com/2010/08/21/using-considered-harmful-or-whats-wrong-with/)

Loading…
Cancel
Save