How to rescue from a require gem_name when the gem is not installed
require
raises a LoadError
exception if it can't load the required library. However, you never rescue from LoadError
anywhere, you rescue from StandardError
.
If you want to rescue from LoadError
, you have to say so:
begin
require 'some_gem'
rescue LoadError
puts 'please install some_gem first!'
end
Even better yet, make sure that you are actually printing the correct missing dependency:
begin
require 'some_gem'
rescue LoadError => e
raise unless e.message =~ /some_gem/
puts 'please install some_gem first!'
end
(This re-raises the exact same exception that was rescued from, in case that the exception was actually caused by some other missing library somewhere else. You wouldn't want to print misleading information, right?)
Depending on what the intended target audience for the library is and whether or not they might be scared away by a backtrace being dumped to their console, you might want to re-raise the exception in any case, instead of just swallowing it:
begin
require 'some_gem'
rescue LoadError => e
puts 'please install some_gem first!' if e.message =~ /some_gem/
raise
end
Or, you could skip the puts
and instead raise an exception with the message set to what you want to say:
begin
require 'some_gem'
rescue LoadError => e
raise e.exception('please install some_gem first!') if e.message =~ /some_gem/
raise
end
Except now the exception is raised in the wrong place and thus has the wrong line number and stacktrace and thus is misleading, but that is easily fixed:
begin
require 'some_gem'
rescue LoadError => e
raise unless e.message =~ /some_gem/
friendly_ex = e.exception('please install some_gem first!')
friendly_ex.set_backtrace(e.backtrace)
raise friendly_ex
end
Now you print pretty much the same thing that you would have printed with the puts
, but you have a "proper" exception that for example allows better debugging or allows a consumer of your library to rescue that exception and handle it their way, both of which would have been impossible or at least hard with your solution that just swallows the exception.
Install ruby gem in rescue block when 'LoadError' occurs
After rigorous searching, I found an answer. If we use Gem.clear_paths
after installing the gem, it will now available to the script. Total updated code is :
begin
require '<gem name here>'
rescue LoadError
puts `gem install <gem name here>`
Gem.clear_paths
require '<gem name here>'
end
ruby: code to install gem if missing
Checking availability is covered in this previous StackOverflow Quesiton
begin
gem "somegem"
# with requirements
gem "somegem", ">=2.0"
rescue Gem::LoadError
# not installed
end
or
matches = Gem.source_index.find_name(gem.name, gem.version_requirements)
As for the install, it looks like rails uses the system for gem install also
puts %x(#{cmd})
Ruby: How to REQUIRE an installed GEM programmatically?
You can require the gem if it's present and also install the gem if it's not already installed the following way (Look for the comments in the code):
def checkGemColorize(gemName, versionLimit=nil)
isAvailable = false
begin
if versionLimit == nil
gem_present = gem gemName # this will return true if the gem is present
if gem_present
puts "Yes the GEM is installed"
require gemName # here you are requiring the gem
puts "#{gemName} GEM is required just now"
end
else
gem gemName, versionLimit
puts "Yes the GEM is installed with correct version number"
#also if version number is used.
end
isAvailable = true
rescue LoadError
# I added this block of code to install the gem when it's missing
puts "#{gemName} is missing, Installing now...."
`gem install #{gemName}` # installing the missing gem
puts "installed the #{gemName} gem just now!"
isAvailable = true
end
isAvailable
end
#testing IF TRUE on colorize
puts "checking for colorize GEM"
puts checkGemColorize('colorize')
ERROR: Gem bundler is not installed, run `gem install bundler` first
I think this is the problem: You have bundler installed to a specific gemset, which is why it's only available when you're in your app's directory (I'm assuming there's a .rvmrc
file in there).
You have a few options:
- Install
bundler
to a global gemset.rvm gemset use global && gem install bundler
- If you have Homebrew installed, just do
brew install ruby
and avoid rvm altogether. (There's also rbenv and ry as alternatives to rvm, but I just use 1.9.3 across all my apps, so Homebrew is fine.)
For reference, $PATH
is a shell environmental variable containing a list of directories that hold executables (e.g., echo
, ls
, vim
, etc.). It's intrinsic to shells.
Safely require gems in Ruby
It would probably be done like this:
begin
require 'hirb'
rescue LoadError => e
puts "could not find hirb"
end
Check for Ruby Gem availability
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.
programmatically determine if a certain gem is installed, then install it if not
# The version requirements are optional.
# You can also specify multiple version requirements, just append more at the end
gem_name, *gem_ver_reqs = 'json', '~> 1.8.0'
gdep = Gem::Dependency.new(gem_name, *gem_ver_reqs)
# find latest that satisifies
found_gspec = gdep.matching_specs.max_by(&:version)
# instead of using Gem::Dependency, you can also do:
# Gem::Specification.find_all_by_name(gem_name, *gem_ver_reqs)
if found_gspec
puts "Requirement '#{gdep}' already satisfied by #{found_gspec.name}-#{found_gspec.version}"
else
puts "Requirement '#{gdep}' not satisfied; installing..."
# reqs_string will be in the format: "> 1.0, < 1.2"
reqs_string = gdep.requirements_list.join(', ')
# multi-arg is safer, to avoid injection attacks
system('gem', 'install', gem_name, '-v', reqs_string)
end
More recent rubygems versions provide an installer API, so instead of shelling out to the gem
command you could also use:
# using the same "gdep" variable as above
Gem.install gem_name, gdep.requirement
However, I'm not sure if Gem.install
respects your .gemrc
file.
There are a lot of useful methods for querying your installed gems (see rdocs). Some that might be helpful:
Gem::Specification.find_all_by_name
Gem::Requirement#satisfied_by?(gem_version_instance)
Gem::Specification#satisfies_requirement?(gem_dependency_instance)
Gem.loaded_specs
- hash of the gems you've actually loaded via thegem
method, or byrequire
sudo gem install' or 'gem install' and gem locations
Contrary to all the other posts I suggest NOT using sudo
when installing gems.
Instead I recommend you install RVM and start a happy life with portable gem homes and different version of Ruby all living under one roof.
For the uninitiated, from the documentation:
RVM is a command line tool which allows us to easily install, manage and work with multiple ruby environments and sets of gems.
The reason why installing gems with sudo
is worse than just gem install
is because it installs the gems for ALL USERS as root
. This might be fine if you're the only person using the machine, but if you're not it can cause weirdness.
If you decide you want to blow away all your gems and start again it's much easier, and safer, to do so as a non-root user.
If you decide you want to use RVM
then using sudo
will cause all kinds of weirdness because each Ruby version you install through RVM
has its own GEM_HOME.
Also, it's nice if you can make your development environment as close to your production environment as possible, and in production you'll most likely install gems as a non-root user.
Related Topics
Error Install Rubyracer with Error "Invalid Gem: Package Is Corrupt"
How to Remove Duplicates in a Hash in Ruby on Rails
How to Fix an Accidental 'Sudo Bundle Install Dir_Name'
Using Compass from Ruby (Not Shell)
What Does +@ Mean as a Method in Ruby
How to Stringize/Serialize Ruby Code
How to Memoize a Method That May Return True, False, or Nil in Ruby
Error Installing SQLite3 Gem via Bundler
Ruby on Linux Pty Goes Away Without Eof, Raises Errno::Eio
How to Convert Ppt to Images in Ruby
How to Mark a Cucumber Scenario as Pending
How to Convert Boolean Values to Integers
Rails 5 Db Migration: How to Fix Activerecord::Concurrentmigrationerror
How to Give a Sub-Module the Same Name as a Top-Level Class
Command for Displaying a Gem's Dependencies