Ruby Gems - Require Trouble - FreeBSD 8.0 + Ruby 1.9.1

Hi,

I'm running a fresh install of FreeBSD 8-STABLE (installed then updated to STABLE as of 27 Jan. 2010). All ports are freshly built and installed.

THE PROBLEM:
After installing Ruby 1.9.1 and several gems via the Ports collection, ruby scripts that use the gems fail to load:

Code:
#!/usr/local/bin/ruby19

require 'rubygems'
require 'net/ssh'

...

The script fails with:
Code:
user@host:/home/user% ./script.rb
./script.rb:4:in `require': no such file to load -- net/ssh (LoadError)
        from ./script.rb:4:in `<main>'

So of course I check my gems install:
Code:
user@host:/home/user% gem list --local

*** LOCAL GEMS ***

activerecord (2.3.4)
activesupport (2.3.4)
net-ssh (2.0.15)
pg (0.8.0)
sqlite3-ruby (1.2.5)
user@host:/home/user# gem19 environment
RubyGems Environment:
  - RUBYGEMS VERSION: 1.3.1
  - RUBY VERSION: 1.9.1 (2009-12-07 patchlevel 376) [amd64-freebsd8]
  - INSTALLATION DIRECTORY: /usr/local/lib/ruby/gems/1.9
  - RUBY EXECUTABLE: /usr/local/bin/ruby19
  - EXECUTABLE DIRECTORY: /usr/local/bin
  - RUBYGEMS PLATFORMS:
    - ruby
    - amd64-freebsd-8
  - GEM PATHS:
     - /usr/local/lib/ruby/gems/1.9
     - /home/user/.gem/ruby/1.9
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :benchmark => false
     - :backtrace => false
     - :bulk_threshold => 1000
  - REMOTE SOURCES:
     - http://gems.rubyforge.org/
user@host:/home/user% pkg_info | grep ruby
ruby-1.9.1,1        An object-oriented interpreted scripting language
ruby19-iconv-1.9.1,1 An iconv wrapper class for Ruby
ruby19-mysql-2.8.1  Ruby module for accessing MySQL databases with a C API like
rubygem-activerecord-2.3.4_1 Object-relational mapping layer for Rails MVC Framework
rubygem-activesupport-2.3.4_1 Utility classes and extension that are required by Rails MV
rubygem-net-ssh-2.0.15 Non-interactive SSH processing
rubygem-pg-0.8.0    Ruby interface to PostgreSQL library
rubygem-sqlite3-1.2.5 Ruby interface to the SQLite DB engine version 3
user@host:/home/user% uname -av
FreeBSD host.example.org 8.0-STABLE FreeBSD 8.0-STABLE #0: Wed Jan 27 19:46:39 MST 2010     root@host.example.com:/usr/obj/usr/src/sys/GENERIC  amd64
user@host:/home/user%

ALL installed gems fail to load with the exact same error. So I think, perhaps it's the FreeBSD port system gems that are bad. I download a new gem and install it with the gem command (bypassing ports). But when I try to require it, it fails with the exact same error.

All of the installed gems (whether by ports or by direct gem install) are in the correct install location (/usr/local/lib/ruby/gems/1.9/) and are present.

Then I learn this:

Code:
user@host:/home/user% irb19
irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'net/ssh'
LoadError: no such file to load -- net/ssh
        from (irb):2:in `require'
        from (irb):2
        from /usr/local/bin/irb:12:in `<main>'
irb(main):003:0> require 'active_record'
LoadError: no such file to load -- active_record
        from (irb):3:in `require'
        from (irb):3
        from /usr/local/bin/irb:12:in `<main>'
irb(main):004:0> gem 'net-ssh'
=> true
irb(main):005:0> require 'net/ssh'
=> true
irb(main):006:0> require 'active_record'
LoadError: no such file to load -- active_record
        from (irb):6:in `require'
        from (irb):6
        from /usr/local/bin/irb:12:in `<main>'
irb(main):007:0> gem 'activerecord'
=> true
irb(main):008:0> require 'active_record'
=> true
irb(main):009:0>

Now THAT's interesting. If I use the gem method before the require, the gem is found. But ONLY after.

Anyone have any ideas?

Puzzled,
Aaron out.
 
Solved: Patch for Ruby 1.9.1's gem_preload.rb file

Please not that this applies to those who are using Ruby 1.9 as the default (i.e. RUBY_VERSION=1.9.1 is set in /etc/make.conf). The patch makes gems work without LoadError exceptions under 1.9.

After much exploration, discovering things like this:
Code:
% ruby19 -e 'p Gem.default_dir'
"/usr/local/lib/ruby19/gems/1.9"
% ls -ld /usr/local/lib/ruby/gems/1.9
drwxr-xr-x  6 root  wheel  6 Jan 28 21:44 /usr/local/lib/ruby/gems/1.9/

Notice that Gem.default_dir was wrong. Gem.default_dir is set in the gem_preload.rb file.

The relevant code section is:
Code:
def self.default_dir
    File.join File.dirname(ConfigMap[:sitedir]), 'Gems',
                           ConfigMap[:ruby_version]
  elsif RUBY_VERSION > '1.9' then
    File.join(ConfigMap[:libdir], ConfigMap[:ruby_install_name], 'gems',
              ConfigMap[:ruby_version])
  else
    File.join(ConfigMap[:libdir], ruby_engine, 'gems',
              ConfigMap[:ruby_version])
  end
end


The problem path element is:
Code:
ConfigMap[:ruby_install_name]

The value of that is 'ruby19' but the path expects only 'ruby' with no version suffix.

ONE POSSIBLE FIX is this patch to gem_prelude.rb (in /usr/ports/lang/ruby19/files/patch-gem_prelude.rb):
Code:
--- gem_prelude.rb.orig	2010-01-28 21:22:27.307910440 -0700
+++ gem_prelude.rb	2010-01-28 21:22:43.177946726 -0700
@@ -116,7 +116,7 @@
         File.join File.dirname(ConfigMap[:sitedir]), 'Gems',
                   ConfigMap[:ruby_version]
       elsif RUBY_VERSION > '1.9' then
-        File.join(ConfigMap[:libdir], ConfigMap[:ruby_install_name], 'gems',
+        File.join(ConfigMap[:libdir], 'ruby', 'gems',
                   ConfigMap[:ruby_version])
       else
         File.join(ConfigMap[:libdir], ruby_engine, 'gems',

That cures the path problem.

It works. Building/installing gems under 1.9.1 (with RUBY_VERSION=1.9.1 in /etc/make.conf) did not break (still works), but this time, no LoadErrors during require. AT LAST!

Code:
user@host:/home/user% irb19
irb(main):001:0> require 'net/ssh'
=> true
irb(main):002:0>

And that makes [cmd=]ruby19 -e 'p Gem.default_dir'[/cmd] output "/usr/local/lib/ruby/gems/1.9" like it should.

Aaron out.
 
If you set
Code:
RUBY_DEFAULT_VER=1.9
in /etc/make.conf it will install hardlink: ruby1.9 -> ruby.
 
Back
Top