What does `if __FILE__ == $0` mean in Ruby
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)
精彩评论