Requiring a Specific Version of a Gem


Your program depends on an interface or feature of a gem found only in particular versions of the library. If a user tries to run your program with the wrong version installed, you want to tell them which version you require, so they can upgrade.


The rubygems library defines a method, Kernel#require_gem, which is a kind of assertion method for gems. It will raise a Gem::LoadError if the given gem is not installed, or if no installed version of a gem meets your requirements.

The easiest solution is to allow any version of a gem; you don need to use require_gem at all:

	require cmdparse # => true

This is equivalent to requiring a minimum version of 0.0.0:

	# Gem::LoadError: Could not find RubyGem nosuchgem (> 0.0.0)

If you can use just any version of a gem, its usually safe to require a minimum version, relying on future versions to be backwards-compatible:[2]

[2] The first require_gem command in this code snippet returns false not because the cmdparse gem isn there, but because weve already loaded the cmdparse library (in the very first code snippet of this recipe). The require method only returns true the first time it loads a library.

	require_gem cmdparse, >= 1.0 # => false
	require_gem cmdparse, >= 2.0.3
	# Gem::LoadError: RubyGem version error: cmdparse(2.0.0 not >= 2.0.3)


Although you may already be familiar with it, a brief review of the structure of version numbers is useful here. A version number for a Ruby gem (and most other pieces of open source software) has three parts: a major version number, a minor version number, and a revision number or build number (Figure 18-1).

Figure 18-1. Anatomy of a version number

Some packages have only a major and minor version number (such as 2.0 or 1.6), and some have additional numbers after the revision number, but the three-number convention is the accepted standard for numbering Ruby gems.

The revision number is incremented at every new public release of the software. If the revision contains more than minor changes, or changes the public API in a backwards-compatible way, the author increments the minor version and resets the revision number to zero. When a release contains large changes, especially ones that change the public API in backwards-incompatible ways, the author usually increments the major version number, and resets the minor version and revision number to zero.

Version numbers are not decimal numbers: version 1.10 is more recent than version 1.1, not the same. Version numbers should be represented as a string or an array of integers, not as a floating-point number or BigDecimal.

The require_gem method takes the name of a gem and an optional version requirement. A version requirement is a string containing a comparison operator and a version number: for instance, "< 2.4". A version requirement can use any of the comparison operators usable in Ruby code, including =, !=, <, >, <=, and =>.

RubyGems uses the comparison operator to compare the installed version of a gem to the required version. The assertion is met if the installed version has the given relationship with the required version. For instance, if version 1.1.4 is installed, and the version requirement is "> 0.9", the two version numbers are compared with an expression similar to "1.1.4 > 0.9", which evaluates to true (the installed major version, 1, is greater than the required major version, 0).

A version requirement can also use the special ~> comparison operator, which restricts certain parts of the version number while leaving the others alone. Youll usually use it to restrict the installed version of a gem to a particular minor version, but allowing any revision number. For instance, the version requirement ~> 2.0 will match any version with a major number of 2 and a minor number of 0: 2.0, 2.0.1, 2. 0.2, and 2.0.20 will all be accepted. ~> 2 will match any version whose major number is 2; 2.0, 2.1, and 2.10 will all be accepted.

A library is supposed to increment its major or minor version whenever the published API changes, so ~> is designed to let you require a particular version of a librarys API. This is slightly more restrictive than requiring a minimum version, and is useful if the API changes drastically between versions, or if you anticipate incompatible changes in the future.

Since a single Ruby installation can have multiple versions of a single gem installed at once, theres no technical reason (other than disk space) why you can make your users install the exact same versions of the gems you used to develop your program:

	require_gem gem_1 = 1.0.1
	require_gem gem_2 = 2.6
	require_gem gem_3 = 1.3.2

However, its usually not necessary, and such draconian specificity imposes burdens on the programmers as well as the users. Its usually better to use >= or ~>.

If a particular version of a library has an awful bug in it, you can refuse to use it with code like this:

	require_gem uggy !=1.0.3

You can combine comparison operators by making multiple calls to require_gem. For instance, you can simulate ~> with two calls:

	require_gem my_gem >= 2.0
	require_gem my_gem < 3

See Also

  • Recipe 18.2, "Installing and Using a Gem," for information on using the version requirement strings to install the appropriate version of a gem
  • The Facets Core library defines a String#natcmp that can compare version numbers: that is, "1.10.0" will show up as being less than "1.2.0"



Date and Time



Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming


Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration

Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399 © 2008-2020.
If you may any questions please contact us: