viraptor
viraptor

Reputation: 34145

Check for Ruby Gem availability

Is there a way to check if some gem is currently installed, via the Gem module? From ruby code, not by executing 'gem list'...

To clarify - I don't want to load the library. I just want to check if it's available, so all the rescue LoadError solutions don't help me. Also I don't care if the gem itself will work or not, only whether it's installed.

Upvotes: 42

Views: 24713

Answers (7)

foz
foz

Reputation: 5290

In Ruby 1.9.3 only there is also:

Gem.available?('somegem')

You can use regex expressions too. Handy if I want to allow 'rcov' and GitHub variants like 'relevance-rcov':

Gem.available?(/-?rcov$/)

Upvotes: 39

lobati
lobati

Reputation: 10195

Didn't see this anywhere here, but you can also pass fuzzy version strings to find_by_name and find_all_by_name:

Gem::Specification.find_all_by_name('gemname', '>= 4.0').any?

Upvotes: 0

androidyue
androidyue

Reputation: 1112

I use this code and it works smoothly.

def gem_available?(gem_name, version = nil)
  version.nil? gem(gem_name) : gem(gem_name, version)
rescue Gem::LoadError
  false
end

Examples to use

Let's assume you have rack 1.9.1 installed.

puts gem_available?('rack') # => true
puts gem_available?('rack', '>=2') => # false

Upvotes: 1

Eric Drechsel
Eric Drechsel

Reputation: 2744

Looking at the Gem API documentation, using Gem::Specification::find_all_by_name to test for gem availability seems reasonable.

if Gem::Specification::find_all_by_name('gemname').any?
  do stuff
end

find_all_by_name always returns an array (of Specification objects), as opposed to find_by_name which raises an exception if no match is found.

Upvotes: 37

Simone Carletti
Simone Carletti

Reputation: 176352

IMHO the best way is to try to load/require the GEM and rescue the Exception, as Ray has already shown. It's safe to rescue the LoadError exception because it's not raised by the GEM itself but it's the standard behavior of the require command.

You can also use the gem command instead.

begin
  gem "somegem"
  # with requirements
  gem "somegem", ">=2.0"
rescue Gem::LoadError
  # not installed
end

The gem command has the same behavior of the require command, with some slight differences. AFAIK, it still tries to autoload the main GEM file.

Digging into the rubygems.rb file (line 310) I found the following execution

matches = Gem.source_index.find_name(gem.name, gem.version_requirements)
report_activate_error(gem) if matches.empty?

It can provide you some hints about how to make a dirty check without actually loading the library.

Upvotes: 32

foz
foz

Reputation: 5290

Since Gem.available? is deprecated (argh!), you have to rescue again (double aaargh). Yes, find_by_name throws an exception if the gem is not found. So to be backwards-compatible with older rubygems, the common solution seems to be :

def gem_available?(name)
   Gem::Specification.find_by_name(name)
rescue Gem::LoadError
   false
rescue
   Gem.available?(name)
end

Note that the new method allows you to pass a specific version to see if that's loaded:

Gem::Specification.find_by_name('rails', '3.0.4')

Upvotes: 30

Ray Vernagus
Ray Vernagus

Reputation: 6150

You could:

begin
  require "somegem"
rescue LoadError
  # not installed
end

This wouldn't, however, tell you if the module was installed through gem or some other means.

Upvotes: 6

Related Questions