Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does `if __FILE__ == $0` mean in Ruby

Tags:

ruby

People also ask

What does __ file __ mean in Ruby?

The value of __FILE__ is a relative path that is created and stored (but never updated) when your file is loaded. This means that if you have any calls to Dir.

What happens when you require a file 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 EOF in Ruby?

Raised by some IO operations when reaching the end of file. Many IO methods exist in two forms, one that returns nil when the end of file is reached, the other raises EOFError . EOFError is a subclass of IOError .


# Only run the following code when this file is the main file being run
# instead of having been required or loaded by another file
if __FILE__==$0
  # Find the parent directory of this file and add it to the front
  # of the list of locations to look in when using require
  $:.unshift File.expand_path("../../", __FILE__)  
end

Note that this particular practice (adding to the LOAD_PATH directory) is not usually necessary with the advent of require_relative, and expand_path is a simpler way of finding the parent directory.


It's a couple of Ruby Mini-Design-Patterns

It means:

  • IF the file is being executed directly, i.e., as a script,
  • THEN find the directory the script is in and prepend it to beginning of the load/require search path

The conditional part can be useful for many things. A Ruby file could be written to provide functionality for a large program but also be available (with the extra code) as a script. Alternatively, the script-form could run the module's tests, while the component form implements some class for a bigger program and calls the tests only if referenced by name.

The path prepend has some general uses, besides the obvious one of finding private includes. If you have several different versions or releases of something, this way any companion "executables" (scripts) will get called preferentially. /usr/local/release232/bin/whatever will run everything from the same bin directory, even if release220 is earlier on the default path.


A great explanation on what/why from ruby-lang.org:

__FILE__ is the magic variable that contains the name of the current file. $0 is the name of the file used to start the program. This check says “If this is the main file being used…” This allows a file to be used as a library, and not to execute code in that context, but if the file is being used as an executable, then execute that code.

See: https://www.ruby-lang.org/en/documentation/quickstart/4/


Ruby, like any language, has some reserved keywords including if, return, class; one of them happens to be __FILE__. Ruby uses __FILE__ to hold the current source file name.

A prepended $ on a variable's name indicates a global variable. In this case, $0 contains the name of the script being executed. For example, if you run ruby hello_world.rb, the value of $0 would be hello_world.rb

if __FILE__ == $0
  ...
end

Now code inside the if statement will only be executed when the file that contains the source code is the same file you are executing. For better explanation let's create 2 files.

First hello_world.rb:

# hello_world

puts "Hello world"

and second hello_pluto.rb:

# hello_pluto

require_relative "hello_world"
puts "Hello Pluto"

Here if you run ruby hello_world.rb, it will simply output:

Hello world

Now if you run ruby hello_pluto.rb, it will output:

Hello world
Hello Pluto

It actually runs the file hello_world as well. Now stick the code from hello_world inside the if statement and run hello_pluto again:

# hello_world

if __FILE__ == $0
  puts "Hello world"
end

As expected, the only thing you see being printed is Hello Pluto. So, that if statement guarantees that any code that lies within the statement will only run if the source file is the same as the script you are running.

Ref: http://periclestheo.com/2014/02/what-is-up-with-FILE-and-$0.html