开发者

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

开发者 https://www.devze.com 2023-02-03 23:23 出处:网络
if __FILE__ == $0 $:.unshift File.j开发者_高级运维oin(File.dirname(__FILE__),\'..\') I found this code in Ruby, what\'s the meaning?# Only run the following code when this file is the main file bein
if __FILE__ == $0
  $:.unshift File.j开发者_高级运维oin(File.dirname(__FILE__),'..')

I found this code in Ruby, what's the meaning?


# 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


I recommend you use $PROGRAM_NAME alias over $0 since it’s a little clearer what you mean when you use it—they mean the same thing.

Now, what does $PROGRAM_NAME/$0 mean? From the Ruby docs:

$0
Contains the name of the script being executed. May be assignable.

Let’s demonstrate how this works with code.

1. Create hello.rb

module Hello
  def self.world
    puts "Hello, world!"
    puts "$0       = #{$0}"
    puts "__FILE__ = #{__FILE__}"
  end
end

if $PROGRAM_NAME == __FILE__
  puts Hello.world
end

Look what happens if you run this file by itself:

$ ruby hello.rb
Hello, world!
$0       = hello.rb
__FILE__ = hello.rb

2. Create a Rakefile

require 'rake'
require_relative 'hello'

task :hello do
  Hello.world
end

Now execute this same code from within the context of a Rake task:

$ rake hello
Hello, world!
$0       = /Users/sean/.rbenv/versions/2.3.0/bin/rake
__FILE__ = /Users/sean/Projects/hello/hello.rb

Wrapping code at the end of a Ruby file in a if $PROGRAM_NAME == __FILE__ conditional is an idiom many developers use to say “only execute this code if you’re running this file individually”.

What kind of code would you wrap in this conditional? I often use it to demonstrate how to use a module. This also makes it very convenient to execute this file in isolation to make sure it works outside the context of the larger program you may be writing.

If you didn’t wrap your example code in this conditional, then it would get executed whenever the file is required/loaded in the lifecycle of your larger program, which is almost certainly not what you want.


this means that if file was run directly, not required or loaded then add scripts parent directory to $LOAD_PATH (path where ruby search for files that are require()d)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号