[Rubygems-developers] Gem autoloading problems

Eric Hodel drbrain at segment7.net
Thu Apr 17 23:23:47 EDT 2008

On Apr 16, 2008, at 20:11 PM, Donavan Pantke wrote:
> On Wednesday 16 April 2008 10:05:01 pm Donavan Pantke wrote:
>> So, we were messing around with Passenger for rails recently, and  
>> ran into
>> some behavior that I think needs to be addressed, but I'm not sure  
>> how.
>> Gems, I think as of 1.0, automatically activates a gem's  
>> dependencies based
>> on what its spec says.

AFAIK, this has always been true.  I checked back to 0.9.0 as that's  
the oldest tag I have checked out.

>> However, the gem itself has no control over this. This
>> makes life really hard on systems that need specific handling. In  
>> the case
>> of Passenger, the rails gem is loaded based on the version  
>> requested, and more
>> than one can be loaded (the process forks before rails gets loaded,  
>> allowing
>> multiple versions to be in memory and accessible). However, if the  
>> gemspec
>> has rails in it, activating passenger means that rails  
>> automatically gets
>> activated, and so any further rails activation with a different  
>> version
>> fails. However, the gemspec is entirely correct in that it needs
>> _some_version of rails, but it really needs to do the activating of  
>> the
>> dependency itself.

Can it not fork and exec if it is going through the setup of Rails for  
each child anyway?

>> The first question I have is, what mechanism can be made available  
>> to avert
>> activating a dependent gem until the gem actually needs it?
> I took a look back, and prior RubyGems had an autorequire option,  
> that was
> false by default. However, this behavior is not only true by  
> default, but
> there's no longer even a way of disabling it.

autorequire is a separate feature from before RubyGems hooking into  
Kernel#require.  It has nothing to do with activation of dependencies.

> I'm thinking that given the new codebase, the best way of carrying  
> forward
> this behavior is by extending Gem::Dependency and add_dependency to  
> allow for
> disabling autoloading.

Even with such a feature it is too easy to run into the same problem.

Given gems a-1, a-2 and b-1 that depends on any version of a, and a/ 
some_file.rb existing in both versions of gem a.

In b/some_file.rb:

require 'a/some_file'

In myapp.rb:

gem_but_not_dependencies 'b'

# at this point, only b-1 is activated.

require 'b/some_file'

# at this point, b-1 and a-2 are both activated,
# because b/some_file.rb required a/some_file.rb

gem 'a', '1' # raises exception

> This way the developer could control autoloading on a
> per-dependency basis.

A user of RubyGems can already control which gem gets activated with  
Kernel#gem.  However, it is up to the user to activate the gems they  
need in dependency order.  `gem lock` can help with this.

> This handles especially well the case where a gem has
> to turn off certain dependencies, but more often than not  
> autoloading is
> fine.

AFAIK, this case has never come up before...

More information about the Rubygems-developers mailing list