Photo by Vlad Hilitanu on Unsplash
What’s the relationship between require, $LOAD_PATH and $LOADED_FEATURES in Ruby?
It is common to see require 'something'
in a Rails application. But what exactly does require
do?
What is require
used for in Ruby?
require
is used to load external libraries or modules into your program. For example,
Before you require
the JSON
module
# in irb
JSON
#=> Traceback (most recent call last):
4: from /Users/lynnbright/.rvm/rubies/ruby-2.7.8/bin/irb:23:in `<main>'
3: from /Users/lynnbright/.rvm/rubies/ruby-2.7.8/bin/irb:23:in `load'
2: from /Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/gems/2.7.0/gems/irb-1.2.6/exe/irb:11:in `<top (required)>'
1: from (irb):3
NameError (uninitialized constant JSON)
After you require
the JSON
module
# in irb
require 'JSON'
#=> true
JSON
#=> JSON
data = '{"name": "John", "age": 30}'
#=> => "{\"name\": \"John\", \"age\": 30}"
JSON.parse(data)
#=> {"name"=>"John", "age"=>30}
What’s the relationship between require
, $LOAD_PATH
and $LOADED_FEATURES
in Ruby?
Before the file is loaded, there are some steps that Ruby will do.
First, when we use require
, it means that we ask Ruby to load the file. However, it is needless to load the same file again and again, right? This is how the $LOAD_PATH
and $LOADED_FEATURES
play important roles.
$LOAD_PATH
: It is a global variable used to locate the file.$LOADED_FEATURES
: It is a global variable, too. It’s used to keep tracking of which files have been loaded successfully usingrequire
.
Search for the file
When require
is called, Ruby looks for a specific file from $LOAD_PATH
which contains an array of directories.
If the file is found, Ruby loads and executes it.
If the file is not found listed in the $LOAD_PATH
, LoadError
is raised.
# in irb
require 'abc'
#=> Traceback (most recent call last):
6: from /Users/lynnbright/.rvm/rubies/ruby-2.7.8/bin/irb:23:in `<main>'
5: from /Users/lynnbright/.rvm/rubies/ruby-2.7.8/bin/irb:23:in `load'
4: from /Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/gems/2.7.0/gems/irb-1.2.6/exe/irb:11:in `<top (required)>'
3: from (irb):9
2: from /Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:83:in `require'
1: from /Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:83:in `require'
LoadError (cannot load such file -- abc)
Check if the file already loaded:
If the file is found, before actually loading it, Ruby uses $LOADED_FEATURES
, which contains an array of files, to check if the file is already included in the array.
If it is included in the array, that means the file has been loaded. If not, it will be added to $LOADED_FEATURES
to prevent it from loaded again.
Let’s see a real example.
# in irb
$LOAD_PATH
#=> ["/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/timeout-0.4.1/lib", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/site_ruby/2.7.0", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/site_ruby/2.7.0/x86_64-darwin21", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/site_ruby", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/vendor_ruby/2.7.0", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/vendor_ruby/2.7.0/x86_64-darwin21", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/vendor_ruby", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/2.7.0", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/2.7.0/x86_64-darwin21"]
$LOADED_FEATURES
#=> ["enumerator.so", "thread.rb", "rational.so", "complex.so",....]
$LOADED_FEATURES.length
#=> 171
require 'json'
#=> true
# You can see that the "json" directory has been included into the $LOAD_PATH.
$LOAD_PATH
#=> ["/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/timeout-0.4.1/lib", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/extensions/x86_64-darwin-21/2.7.0/json-2.7.1", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/site_ruby/2.7.0", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/site_ruby/2.7.0/x86_64-darwin21", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/site_ruby", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/vendor_ruby/2.7.0", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/vendor_ruby/2.7.0/x86_64-darwin21", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/vendor_ruby", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/2.7.0", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/2.7.0/x86_64-darwin21"]
# The array elements increased from 171 to 180, indicating that new elements have been added.
$LOADED_FEATURES.length
#=> 180
$LOADED_FEATURES
#=> [...., "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib/json/version.rb", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/2.7.0/ostruct/version.rb", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/2.7.0/ostruct.rb", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib/json/generic_object.rb", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib/json/common.rb", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib/json/ext/parser.bundle", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib/json/ext/generator.bundle", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib/json/ext.rb", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib/json.rb"]
# Attempting to require 'json' again returns false because it is already included in $LOADED_FEATURES.
require 'json'
#=> false
In summary:
require
is used to load the specific file.$LOAD_PATH
is used to locate where the file is.$LOADED_FEATURES
is used to keep tracking of which files have been loaded successfully usingrequire
.