Project

General

Profile

Feature #11148

Updated by nobu (Nobuyoshi Nakada) over 5 years ago

Hi, 

 I'm trying to make is so that RubyGems doesn't need to put directories on $LOAD_PATH (which is why I submitted Feature #11140).    I would like the `require` implemented in RubyGems to look up the file from a cache generated when the gem is installed, then pass a full file path to `require`. 

 The problem is that the user may have manipulated the load path somehow, and RubyGems needs to detect if the file is in the load path.    Today, the algorithm inside RubyGems looks something like this: 

 ~~~ruby ~~~ruby~~~ 
 def require file 
   if file_is_from_a_default_gem?(file) # this is so you can install new versions of default gems 
     add_default_gem_to_loadpath 
   end 
   real_require file 
 rescue LoadError 
   gem = find_gem_that_contains_file(file) 
   add_gem_to_loadpath gem 
   real_require file 
 end 
 ~~~ 

 Instead of adding the directory to the load path, I would like to look up the full file path from a cache that is generated when the gem is installed.    If we had a cache, that means the new implementation would look like this: 

 ~~~ruby ~~~ruby~~~ 
 def require file 
   if file_is_from_a_default_gem?(file) # this is so you can install new versions of default gems 
     add_default_gem_to_loadpath 
   end 
   real_require file # get slower as paths are added to LOAD_PATH 
 rescue LoadError 
   gem = find_gem_that_contains_file(file) # use a cache so lookup is O(1) 
   fully_qualified_path = gem.full_path file 
   real_require fully_qualified_path # send a fully qualified path, so LOAD_PATH isn't searched 
 end 
 ~~~ 

 Unfortunately, that means that every call to require in the system would raise an exception.    I'd like to add a version of `require` that we can call that *doesn't* raise an exception.    Then I could write the code like this: 

 ~~~ruby ~~~ruby~~~ 
 def require file 
   if file_is_from_a_default_gem?(file) # this is so you can install new versions of default gems 
     add_default_gem_to_loadpath 
   end 
   found = try_require file 
   if nil == found 
     gem = find_gem_that_contains_file(file) # use a cache so lookup is O(1) 
     fully_qualified_path = gem.full_path file 
     real_require fully_qualified_path # send a fully qualified path, so LOAD_PATH isn't searched 
   end 
     found 
   end 
 end 
 ~~~ 

 This would keep the load path small, and prevent exceptions from happening during the "normal" case. 

 I've attached a patch that implements `try_require`, but I'm not set on the name.    Maybe doing `require(file, exception: false)` would work too.

Back