Search code examples
rubyrubygemsrakebundlerrakefile

Where does require pull ruby files that don't exist on the system?


I followed the steps from bundler.io and am creating my own gem.

Now I'm looking into the Rakefile. I see:

require "bundler/gem_tasks"

but as far as I understand I don't have a bundler/gem_tasks. So how is this working? Where is that file expected to be in? How does require find files that aren't in its folder?!

Is it just pointing to this file: https://github.com/rubygems/bundler/blob/master/lib/bundler/gem_tasks.rb? Can you just reference single ruby files with just like

require someGem/someRubyfile

The ruby docs aren't clear about this.

I already looked into this question and also inspected my $LOAD_PATH. It only contains the following:

 "/Library/Ruby/Gems/2.6.0/gems/did_you_mean-1.3.0/lib",
 "/Library/Ruby/Gems/2.6.0/gems/coderay-1.1.3/lib",
 "/Library/Ruby/Gems/2.6.0/gems/method_source-1.0.0/lib",
 "/Library/Ruby/Gems/2.6.0/gems/pry-0.13.1/lib",
 "/Library/Ruby/Site/2.6.0",
 "/Library/Ruby/Site/2.6.0/x86_64-darwin19",
 "/Library/Ruby/Site/2.6.0/universal-darwin19",
 "/Library/Ruby/Site",
 "/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/vendor_ruby/2.6.0",
 "/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/vendor_ruby/2.6.0/x86_64-darwin19",
 "/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/vendor_ruby/2.6.0/universal-darwin19",
 "/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/vendor_ruby",
 "/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0",
 "/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/x86_64-darwin19",
 "/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/universal-darwin19"]

I don't see mention of bundler.

Nor I see anything related to gem_tasks in ~/.bundle. Does this mean that upon rake build the bundler/gem_tasks is going to get downloaded from the internet?


Solution

  • Rubygems overwrites Ruby's own Kernel#require method with its own method which loads gems on demand (i.e. adds the gem to the $LOAD_PATH and then requires the requested file).

    Thus, when you execute require 'bundler/gem_tasks', what happens is that rubygems searches for a gem containing bundler/gem_tasks.rb in its require_paths path (which is specified in the respective gemspec of each gem). If a matching gem is found on your system, its require_paths are added to the $LOAD_PATH and Ruby's original require method is called which will load the requested file.

    In any case, neither Ruby nor Rubygems dynamically loads gems from the internet. It will only use gems installed locally to the configured GEM_PATHS. You can find the configured paths which are searched for installed gems by running gem env on your command line.

    If you start Ruby with the --disable-gems command line argument, it will not automatically load rubygems and thus will not add its custom implementation of Kernel#require. Here, only files in locations you specifically added to the $LOAD_PATH can be required.