Set GEM_HOME/PATH or Gem.path programmatically

ruby, rubygems

Solution

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.

Problem

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.)

Original source