4

How do I find out whether a gem is installed in the system or not?

%x('gem' 'list').split.find{|i| i == "capybara"}

Is there a shorter method?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
pankajdoharey
  • 1,562
  • 19
  • 30

4 Answers4

15

If you're trying to do this from within ruby, you can use a built-in RubyGem method. Older versions provide a Gem.available?('capybara') method that returns a boolean, but this has been deprecated. The recommended way now is to use (assuming you're using a version that supports it):

Gem::Specification::find_by_name('capybara')

http://rubygems.rubyforge.org/rubygems-update/Gem/Specification.html

Update

If you want a boolean result, you could use .find_all_by_name() and check if the resulting array is empty:

if Gem::Specification::find_all_by_name('capybara').any?
  # Gem is available
end
Peter Brown
  • 50,956
  • 18
  • 113
  • 146
  • If it doesn't find the given gem it gives ton of error how do i handle that ? i was looking for something simple like TRUE or nil. – pankajdoharey Dec 13 '11 at 13:57
  • 2
    +1 RubyGems is a *Ruby* library. Shelling out to `gem` from Ruby is so many different kinds of wrong. Just use the API. – Jörg W Mittag Dec 13 '11 at 13:57
  • True even i want to use the Library but it gives so much error when it doesn't find the gem – pankajdoharey Dec 13 '11 at 13:59
  • @pankajdoharey Gem::Specification::find_all_by_name returns an empty array if the gem isn't found. You could tack `empty?` on the end to get a boolean. – Peter Brown Dec 13 '11 at 16:21
  • @Beerlington actually, find_all_by_name raises `Gem::LoadError` if the gem isn't found (as of Dec 2012). It's a little mysterious to me why `Gem.available?` was deprecated. – Eric Drechsel Dec 04 '12 at 20:50
  • @Beerlington oops, your last comment is correct. I'm going to update your answer above. Also answered [here](http://stackoverflow.com/a/13711828/114581). – Eric Drechsel Dec 04 '12 at 21:22
  • @EricDrechsel looks like your change got rejected, I will update the answer though. – Peter Brown Dec 04 '12 at 22:24
  • For the record, find_all_by_name is only supported since 1.9.3 : http://ruby-doc.org/stdlib-1.9.3/libdoc/rubygems/rdoc/Gem/Specification.html ----VS---- 1.9.2: http://ruby-doc.org/stdlib-1.9.2/libdoc/rubygems/rdoc/Gem/Specification.html – inger Oct 21 '13 at 15:30
3

I stick this at the beginning of my Gemfile:

def gem_available?(gemname)
  if Gem::Specification.methods.include?(:find_all_by_name) 
    not Gem::Specification.find_all_by_name(gemname).empty?
   else
     Gem.available?(gemname)
   end
 end

then just use:

if (gem_available?('gem_i_need'))

and everything works nicely!

Peter Krnjevic
  • 1,070
  • 15
  • 20
3
%x('gem' 'list' | 'grep' 'capybara').empty?
pankajdoharey
  • 1,562
  • 19
  • 30
clyfe
  • 23,695
  • 8
  • 85
  • 109
1

Here's some code that works for me. It also properly handles the Gem::LoadError that gets thrown when you try to load a gem that could not be found.

require 'rubygems'

def can_we_find_gem(gem_name)
  found_gem = false
  begin
    found_gem = Gem::Specification.find_by_name(gem_name)
  rescue Gem::LoadError
    puts "Could not find gem '#{gem_name}'"
  else
    puts "Found gem '#{gem_name}'"
  end
end

can_we_find_gem('chef')
can_we_find_gem('not-chef')
Dylan Northrup
  • 161
  • 1
  • 9
  • Designing code around throwing and catching errors isn't good. – Automatico Apr 25 '14 at 10:10
  • Throwing and catching errors is pretty basic error handling. I do the same thing when I attempt to open files to see if they were opened successfully. I think there might be something additional behind your comment and would be happy if you wanted to clarify or expand on it. – Dylan Northrup Apr 25 '14 at 12:59
  • Catching errors is good when you don't know the cause of the error, but to design the system to rely on catching errors isn't good design. You should rather make methods that verifies that the function won't throw an error. If you for instance use some automatic error-logging system you will end up with a huge amount of junk-errors that does not mean anything. – Automatico Apr 25 '14 at 13:10
  • We will have to agree to disagree. I know when I try to load a gem it will either load successfully or fail and throw an Exception. If I need to make a decision based on whether a gem's methods and data are available, the best way is to base that decision on whether or not the gem loaded successfully. I don't think it's necessary to re-invent the wheel to make that success determination... if there was an exception, the gem didn't load; if no exception, it loaded. The `puts` statements in there are because this is example code. Feel free to omit them in production code. – Dylan Northrup Apr 28 '14 at 13:06
  • I do think it is a matter of taste too, and is totally dependent on the domain which you work in. But I feel that in general you should move towards fewer try-catches rather than more. However I do know quite a few that prefer to do the opposite. My thoughts though: Because ruby is often used with Rails many tools will be filled with meaningless errors and probably make it harder to spot the actual errors you should focus on. – Automatico Apr 28 '14 at 13:30