Loading External Files in Ruby

The Difference Between load, autoload, require, and require_relative in Ruby πŸ“–

Loading external files can get tricky in Ruby, but it doesn't have to be. This post explains the usage of Ruby's load, require, and require_relative methods, and when to use each.

6 min read

Ruby provides a few different ways to load another Ruby program or external library. You can load it, autoload it, require it, or require it relative to the current directory using require_relative. Although they look and sound quite similar, there're a few important differences between them that can be confusing to understand.

After a year and a half of programming in Ruby, I still didn't quite understand all the nuances and differences between these methods. So after a few hours of study last night, here's everything I learned about loading external Ruby scripts in your programs. This post explains how they differ from each other and when you should use each. I hope you find this information helpful.

TL;DR: Use load to pick up any changes you made to a file while the program is running. Use autoload to speed up the initialization of your library by lazily loading the modules. Use require when you want to use external gems. Use require_relative for local files relative to the current working directory.

Let's dig deeper.

The 'load' Method

The load method takes the filename as input. When the Ruby interpreter comes across the load method, it will load and execute the Ruby program in the file filename. If it comes across it again, it will load and execute it again, picking any new changes in the file.

The filename can be either an absolute path or a relative path using . or .. , and Ruby will load and run that Ruby file. If it can't find the file, Ruby will search for it in the directories listed in $LOAD_PATH variable.

Let's create two Ruby files (in the same directory) with the following code.

# script.rb

puts "Inside script"
load "loaded_script.rb"

puts "Inside script"
load "loaded_script.rb"


# loaded_script.rb

puts "Loaded file"

Running the first script gives the following output.

~ ruby script.rb

Inside script
Loaded file
Inside script
Loaded file

Notice that each call to the load method executes the loaded script. Hence the output Loaded file was printed twice.

A call to the load method always loads that file. It doesn't matter if you had already loaded it earlier.

If you load a file, make a change to that file, and load it again, load will pick your new changes, which will override the original contents of the file. This is useful for making changes when a program is running and examining them immediately without reloading the application.

Remember: load will run the code every time, so if you are loading a Ruby script in multiple locations, you're doing lots of unnecessary work.

The 'autoload' method

This method takes two arguments: a module (it can be either a string or a symbol) and a filename (string), and registers the filename to be loaded the first time that module is accessed.

autoload(:TestModule, "lib/modules/test_module.rb")

Using autoload allows you to speed up the initialization of your library by lazily loading the modules that your code depends on. It won't load the library or framework code you aren't using.

# script.rb

puts "Inside script"
autoload :LoadedScript, "./loaded_script.rb"
puts "Inside script"

LoadedScript.new

# loaded_script.rb

puts "Loaded file"

class LoadedScript
end

Running the first script outputs the following:

~ ruby script.rb

Inside script
Inside script
Loaded file

Note that the loaded_script was executed only when I created an instance of LoadedScript, not when I autoloaded it.

Additionally, Ruby on Rails overrides Ruby's autoload method to use Rails' naming conventions, which lets you skip the second argument, i.e. the filename. To learn more about it, check out the following article.

Autoloading Modules in Rails
Autoloading modules allows you to speed up the initialization of your library by lazily loading the code you need. This post explores how autoload method works.

The 'require' method

The require method also loads the given file, similar load. However, it won't load the file if it's already loaded. Any constants, classes, modules, or global variables within the required file will be available to the calling program.

If the filename neither resolves to an absolute path nor starts with ./ or ../, the file will be searched for in the library directories listed in $LOAD_PATH.

Requiring a library a second time won't execute it again.

# script.rb

puts "Inside script"
require "./required_script"
puts "Inside script"
require "./required_script"

# required_script.rb
puts "Required file"

Running script.rb provides the following output.

Inside script
Required file
Inside script

Note that requiring the script again didn't execute it, unlike the load method. Also, the file extension .rb is optional in require, whereas load will loudly complain about it and crash. Β 

When using require, you can use the ./ format for a file in the current directory, e.g. require "./script". However, it's not a common practice. Instead, you should use the require_relative method. Reserve require for loading the external gems.

Use require for loading Ruby gems

When you require a gem, really you’re just placing that gem’s lib directory onto your $LOAD_PATH.

The require method uses the $LOAD_PATH to locate the mentioned file. As the Ruby gems are installed in a directory present in $LOAD_PATH, this allows you to require them without providing the path.

require 'minitest'

Once you've required minitest, RubyGems automatically places its lib directory on the $LOAD_PATH.

That's how Ruby gems work. You write the gem's Ruby code into the lib directory containing a Ruby file with the same as your gem. For the minitest gem, the file will be minitest.rb. Additionally, the lib directory contains a directory with the same name as the gem containing the rest of the files.

% tree minitest/
minitest/
└── lib/
    β”œβ”€β”€ minitest/
    β”‚   β”œβ”€β”€ code.rb
    β”‚   β”œβ”€β”€ app.rb
    β”‚   └── ...
    └── minitest.rb

Since the lib directory is placed into $LOAD_PATH, you can require the gem without providing the path. Ruby will know where to load it from.

The 'require_relative' method

In the previous example, we provided the path to the required file as ./required_script, that is, using the . to indicate the current directory. The require_relative method loads the external file by searching relative to the file from which it's called. This allows you to write:

require_relative "required_script"

The code will result in the same output as require; they work in the same way.

require_relative is useful when you want to navigate the local directory hierarchy as follows:

require_relative "lib/rails/server"

Use require_relative for local files relative to the current working directory.

Confused?

At this point, you might be really confused about the exact difference between require and require_relative. It feels like they both are doing the same thing. I was confused, too. So I did some further digging and came across this excellent StackOverflow answer that elegantly explains how they differ and how to choose one over the other.

Ruby β€˜require’ error: cannot load such file
I’ve one file, main.rb with the following content: require β€œtokenizer.rb” The tokenizer.rb file is in the same directory and its content is: class Tokenizer def self.tokenize(string)

I highly recommend reading the full answer, but here's a gist of it.

  1. require_relative 'script' assumes that the relative path between the two Ruby source files will stay the same.
  2. require 'script' assumes that script is inside one of the directories on the load path ($LOAD_PATH). This generally requires extra setup, since you have to add something to the load path.
  3. require './script' assumes that the relative path from the Ruby process's current working directory to script is going to stay the same.

Hope that clears things a bit.

Conclusion

  1. Use load to pick up any changes you made to a file while the program is running.
  2. Use autoload to speed up the initialization of your library by lazily loading the modules.
  3. Use require when you want to use external gems.
  4. Use require_relative for local files relative to the current working directory.

I hope you found this article useful and that you learned something new.

If you have any questions or feedback, didn't understand something, or found a mistake, please leave a comment below or send me an email. I look forward to hearing from you.

Please subscribe to my blog if you'd like to receive future articles directly in your email. If you're already a subscriber, thank you.