Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does load differ from require in Ruby?

Is there any major difference between load and require in the Ruby on Rails applications? Or do they both have the same functionality?

like image 877
Arpit Vaishnav Avatar asked Jul 03 '10 07:07

Arpit Vaishnav


People also ask

What is the use of require in Ruby?

In Ruby, the require method is used to load another file and execute all its statements. This serves to import all class and method definitions in the file.

What is the purpose of load Auto_load and Require_relative in Ruby?

-Auto_load: this initiates the method that is in hat file and allows the interpreter to call the method. -require_relative: allows the loading to take place of the local folders and files.

What is require in Ruby on Rails?

In Ruby to reuse any existing files and modules we can use the require statement, required to allow us to make available the submodules inside our codes, there are two way to require any file first way by giving the full path of the file like require './dire/lib/xyz.

What is difference between include and extend in Ruby?

In simple words, the difference between include and extend is that 'include' is for adding methods only to an instance of a class and 'extend' is for adding methods to the class but not to its instance.


3 Answers

require searches for the library in all the defined search paths and also appends .rb or .so to the file name you enter. It also makes sure that a library is only included once. So if your application requires library A and B and library B requries library A too A would be loaded only once.

With load you need to add the full name of the library and it gets loaded every time you call load - even if it already is in memory.

like image 90
Nikolaus Gradwohl Avatar answered Oct 06 '22 01:10

Nikolaus Gradwohl


Another difference between Kernel#require and Kernel#load is that Kernel#load takes an optional second argument that allows you to wrap the loaded code into an anonymous empty module.

Unfortunately, it's not very useful. First, it's easy for the loaded code to break out of the module, by just accessing the global namespace, i.e. they still can monkeypatch something like class ::String; def foo; end end. And second, load doesn't return the module it wraps the code into, so you basically have to fish it out of ObjectSpace::each_object(Module) by hand.

like image 33
Jörg W Mittag Avatar answered Oct 06 '22 03:10

Jörg W Mittag


I was running a Rails application and in Gemfile, I had a specific custom gem I created with the option "require: false". Now when I loaded up rails server or rails console, I was able to require the gem in the initializer and the gem was loaded. However, when I ran a spec feature test with rspec and capybara, I got a load error. And I was completely bewildered why the Gem was not found in $LOAD_PATH when running a test.

So I reviewed all the different ways that load, require, rubygems and bundler interact. And these are a summary of my findings that helped me discover the solution to my particular problem:

load

1) You can pass it an absolute path to a ruby file and it will execute the code in that file.

load('/Users/myuser/foo.rb')

2) You can pass a relative path to load. If you are in same directory as file, it will find it:

> load('./foo.rb')
foo.rb loaded!
=> true

But if you try to load a file from different directory with load(), it will not find it with a relative path based on current working directory (e.g. ./):

> load('./foo.rb')
LoadError: cannot load such file -- foo.rb

3) As shown above, load always returns true (if the file could not be loaded it raises a LoadError).

4) Global variables, classes, constants and methods are all imported, but not local variables.

5) Calling load twice on the same file will execute the code in that file twice. If the specified file defines a constant, it will define that constant twice, which produces a warning.

6) $LOAD_PATH is an array of absolute paths. If you pass load just a file name, it will loop through $LOAD_PATH and search for the file in each directory.

> $LOAD_PATH.push("/Users/myuser")
> load('foo.rb')
foo.rb loaded!
 => true

require

1) Calling require on the same file twice will only execute it once. It’s also smart enough not to load the same file twice if you refer to it once with a relative path and once with an absolute path.

2) require returns true if the file was executed and false if it wasn’t.

3) require keeps track of which files have been loaded already in the global variable $LOADED_FEATURES.

4) You don’t need to include the file extension:

require 'foo'

5) require will look for foo.rb, but also dynamic library files, like foo.so, foo.o, or foo.dll. This is how you can call C code from ruby.

6) require does not check the current directory, since the current directory is by default not in $LOAD_PATH.

7) require_relative takes a path relative to the current file, not the working directory of the process.

Rubygems

1) Rubygems is a package manager designed to easily manage the installation of Ruby libraries called gems.

2) It packages its content as a zip file containing a bunch of ruby files and/or dynamic library files that can be imported by your code, along with some metadata.

3) Rubygems replaces the default require method with its own version. That version will look through your installed gems in addition to the directories in $LOAD_PATH. If Rubygems finds the file in your gems, it will add that gem to your $LOAD_PATH.

4) The gem install command figures out all of the dependencies of a gem and installs them. In fact, it installs all of a gem’s dependencies before it installs the gem itself.

Bundler

1) Bundler lets you specify all the gems your project needs, and optionally what versions of those gems. Then the bundle command installs all those gems and their dependencies.

2) You specify which gems you need in a file called Gemfile.

3) The bundle command also installs all the gems listed in Gemfile.lock at the specific versions listed.

4) Putting bundle exec before a command, e.g. bundle exec rspec, ensures that require will load the version of a gem specified in your Gemfile.lock.

Rails and Bundler

1) In config/boot.rb, require 'bundler/setup' is run. Bundler makes sure that Ruby can find all of the gems in the Gemfile (and all of their dependencies). require 'bundler/setup' will automatically discover your Gemfile, and make all of the gems in your Gemfile available to Ruby (in technical terms, it puts the gems “on the load path”). You can think of it as an adding some extra powers to require 'rubygems'.

ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])

2) Now that your code is available to Ruby, you can require the gems that you need. For instance, you can require 'sinatra'. If you have a lot of dependencies, you might want to say “require all of the gems in my Gemfile”. To do this, put the following code immediately following require 'bundler/setup':

Bundler.require(:default)

3) By default, calling Bundler.require will require each gem in your Gemfile. If the line in the Gemfile says gem 'foo', :require => false then it will make sure foo is installed, but it won’t call require. You’ll have to call require('foo') if you want to use the gem.

So given this breadth of knowledge, I returned to the issue of my test and realized I had to explicitly require the gem in rails_helper.rb, since Bundler.setup added it to $LOAD_PATH but require: false precluded Bundler.require from requiring it explicitly. And then the issue was resolved.

like image 32
Daniel Viglione Avatar answered Oct 06 '22 01:10

Daniel Viglione