Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set GEM_HOME/PATH or Gem.path programmatically

Tags:

ruby

rubygems

I'm using a gem that comes with my program, and I simply do

Gem.path.insert(0, basedir + '/packages/lib')

and it works (basedir is set already). Now this works with the older ruby we have (ruby 2.0.0p247 on rhel5, not in /usr/bin).

We have other machines with rhel7 where /usr/bin/ruby is ruby 2.0.0p353, and there the same code does not work - some gems fail to be required.

There (and on the old machs as well)

ENV['GEM_HOME'] = basedir + '/packages/lib'
Gem.clear_paths

works, but this is totally ugly.

Why doesn't the Gem.path.insert work here, and what would be portable? (Neither GEM_PATH nor GEM_HOME are set.)

like image 384
Andreas Krey Avatar asked Feb 23 '26 23:02

Andreas Krey


1 Answers

You should use Gem.paths=. It calls Gem.clear_paths for you and initializes the needed variables.

Gem.paths = {
    'GEM_HOME' => '/opt/rubygems/ruby',
    'GEM_PATH' => '/opt/rubygems/ruby:/opt/rubygems/2.0'
}
# for your example
Gem.paths = { 'GEM_HOME' => "#{basedir}/packages/lib" }

If you only need one Gem or a Ruby library that is not shipped as a Gem, then just include it's lib folder to $LOAD_PATH.

$LOAD_PATH << '/opt/rubygems/ruby/gems/name-0.1.2/lib'
# for your example
$LOAD_PATH.unshift "#{basedir}/packages/lib"

A workaround for you would be the following, but I recommend setting Gem.paths or adding to $LOAD_PATH.

Gem.path.insert(0, basedir + '/packages/lib')
Gem::Specification.dirs << "#{basedir}/packages/lib/specifications'

I have tested Gem.path.insert with ruby-2.0.0p247, ruby-2.0.0p353 (both self compiled) and ruby-2.0.0p353 (CentOS RPM 2.0.0.353-20.el7). The self compiled and Ruby 2.1.3p242 from openSUSE 13.2 works. The CentOS Ruby doesn't work for me eather, because it calls Gem::Specification.dirs before the interpreter reaches the Gem.path.insert line. Don't know why the CentOS and RHEL RPMs behaves different from a clean build or openSUSE RPMs.

ruby compiled from source calls:
--------------------------------
Gem.clear_paths

ruby from CentOS7 calls:
-----------------
Gem.clear_paths
Gem::Specification.dirs
Gem.path
Gem.paths

The following is a list of what gets called on a require.

  • at some point require calls Gem::Specification.dirs
  • Gem::Specification.dirs calls Gem.path to set it's @@dirs, because it isn't initialized at first call
  • Gem.path calls Gem.paths.path
  • Gem.paths sets it's @path to Gem::PathSupport.new, because it isn't initialized at first call

So, if Gem::Specification.dirs is called before the custom path is inserted to Gem.path, the Rubygem library doesn't know to look at the custom folder's specifications path.

like image 189
xoryves Avatar answered Feb 27 '26 01:02

xoryves



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!