# 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

```ruby
# 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

```ruby
# 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 using `require`.
    

### 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.

```ruby
# 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.

```ruby
# 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 using `require`.
