What does __FILE__ mean in Ruby? - ruby

I see this all the time in Ruby:
require File.dirname(__FILE__) + "/../../config/environment"
What does __FILE__ mean?

It is a reference to the current file name. In the file foo.rb, __FILE__ would be interpreted as "foo.rb".
Edit: Ruby 1.9.2 and 1.9.3 appear to behave a little differently from what Luke Bayes said in his comment. With these files:
# test.rb
puts __FILE__
require './dir2/test.rb'
# dir2/test.rb
puts __FILE__
Running ruby test.rb will output
test.rb
/full/path/to/dir2/test.rb

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.chdir anywhere else in your application, this path will expand incorrectly.
puts __FILE__
Dir.chdir '../../'
puts __FILE__
One workaround to this problem is to store the expanded value of __FILE__ outside of any application code. As long as your require statements are at the top of your definitions (or at least before any calls to Dir.chdir), this value will continue to be useful after changing directories.
$MY_FILE_PATH = File.expand_path(File.dirname(__FILE__))
# open class and do some stuff that changes directory
puts $MY_FILE_PATH

__FILE__ is the filename with extension of the file containing the code being executed.
In foo.rb, __FILE__ would be "foo.rb".
If foo.rb were in the dir /home/josh then File.dirname(__FILE__) would return /home/josh.

In Ruby, the Windows version anyways, I just checked and __FILE__ does not contain the full path to the file. Instead it contains the path to the file relative to where it's being executed from.
In PHP __FILE__ is the full path (which in my opinion is preferable). This is why, in order to make your paths portable in Ruby, you really need to use this:
File.expand_path(File.dirname(__FILE__) + "relative/path/to/file")
I should note that in Ruby 1.9.1 __FILE__ contains the full path to the file, the above description was for when I used Ruby 1.8.7.
In order to be compatible with both Ruby 1.8.7 and 1.9.1 (not sure about 1.9) you should require files by using the construct I showed above.

Related

Ruby: How to get the correct full path of a source file after a chdir?

See the following example:
puts __FILE__ #test.rb
puts File.expand_path(__FILE__) #C:/TEMP/test.rb
Dir.chdir('..')
puts __FILE__ #test.rb
puts File.expand_path(__FILE__) #C:/test.rb
After a (global) chdir the expand_path returns a wrong result.
How can I get the correct result?
I tried to use the 2nd parameter of File.expand_path:
puts File.expand_path(__FILE__, 'temp') #C:/TEMP/test.rb
puts File.expand_path(__FILE__, 'c:/temp') #C:/TEMP/test.rb
But to use it, I must know the path of __FILE__.
The command require_relative seems to ignore all chdir-actions. So I have the hope, there is a way to get the 'real' directory of a file.
Remarks:
I know the block-version of Dir.chdir - for my specific task i can#t use it.
My actual solution: I store the fullpath before I change the directory (I could also store Dir.pwd before I change the directory).
__FILE__ builtin is an instance of String class:
puts __FILE__.class
# ⇒ String
That means you should not expect any voodoo magic from it. It stores the relative path, this file was loaded at.
ruby C:\TEMP\test.rb # ⇒ __FILE__ == 'C:\TEMP\test.rb'
cd C:\TEMP && ruby test.rb # ⇒ __FILE__ == 'test.rb'
In ruby 2.0 was new builtin __dir__ introduced. It looks like what you are looking for, in case 2.0-only solution is OK with you.

Require in an IRB shell

I'm working in an IRB shell on a dos CMD
I load a module from a mystuff file
require '.\mystuff'
I change the module in the mystuff file and I type again
require '.\mystuff'
How come the IRB does not pick up the changes in the file when I try to call functions or variables from the newest version of my mystuff module?
require will not load the same file twice. If you want to load the file again, you need to use load. See What is the difference between include and require in Ruby? for more information.
Your Syntax is Wrong
Ruby doesn't use backslashes. You need to use forward slashes, or use File#join.
Your $LOAD_PATH is Wrong
Your $LOAD_PATH (a.k.a $:) is wrong. You need to include the present working directory with:
$: << '.'
in irb, or use Kernel#require_relative in executable or sourced files.

Confusing behavior of File.dirname

I have written a couple of small Ruby scripts for system administration using Ruby 1.9.3. In one script I use:
File.dirname(__FILE__)
to get the directory of the script file. This returns a relative path, however when I call the script from a second script File.dirname returns an absolute path.
Ruby Doc lists an absolute return path in its example whereas I found a discussion on Ruby Forum where a user says dirname should only return a relative path.
I am using the suggested solution from Ruby Forums to use File.expand_path to always get the absolute path like this:
File.expand_path(File.dirname(__FILE__))
but is there a way to make the behaviour of dirname consistent?
UPDATE:
To expand on Janathan Cairs answer, I made two scripts:
s1.rb:
puts "External script __FILE__: #{File.dirname(__FILE__)}"
s0.rb:
puts "Local script __FILE__: #{File.dirname(__FILE__)}"
require './s1.rb'
Running ./s0.rb gives the following output:
Local script __FILE__: .
External script __FILE__: /home/kenneth/Pictures/wp/rip_vault
File.dirname should return an absolute path if given an absolute path, and a relative path if given a relative path:
File.dirname('/home/jon/test.rb') # => '/home/jon'
File.dirname('test.rb') # => '.'
__FILE__ returns the name of the current script, which is therefore a relative path from the current directory. That means you should always use expand_path if you want to get the absolute path with File.dirname(__FILE__).
NB Ruby 2.0.0 introduces the __dir__ constant
If you already upgraded to Ruby 2.0, you can use the new constant
__dir__
otherwise you can use
File.expand_path('..', __FILE__)
which is shorter than
File.expand_path(File.dirname(__FILE__))
File.expand_path documentation

What does $:<< "." do to Ruby's require path?

I don't understand the meaning of $:<< "." in Ruby.
I upgraded Ruby to 1.9.1, but a program was not working. My classmate told me that I am supposed to add $:<< "."
What does $:<< "." do?
$: is the variable that holds an array of paths that make up your Ruby's load path
<< appends an item to the end of the array
. refers to the current directory
1 2 3
| | |
V V V
$: << "."
So you are adding the current directory to Ruby's load path
References:
Can be found in the Execution Environment Variables section of of this page from The Pragmatic Programmers Guide
An array of strings, where each string specifies a directory to be searched for Ruby scripts and binary extensions used by the load and require methods. The initial value is the value of the arguments passed via the -I command-line option, followed by an installation-defined standard library location, followed by the current directory (“.”)[Obviously this link is for an older version of Ruby as this is still in there]. This variable may be set from within a program to alter the default search path; typically, programs use $: << dir to append dir to the path.
Can be found in the docs for array at ruby-doc.org.
Append—Pushes the given object on to the end of this array. This expression returns the array itself, so several appends may be chained together.
Since version 1.9, Ruby doesn't look for required files in the current working directory AKA .. The $LOAD_PATH or $: global variable is an array of paths where Ruby looks for files you require.
By adding $:<< "." to your files, you are actually telling Ruby to include your current directory in the search paths. That overrides new Ruby behavior.
In your example you add working directory (".") to ruby load path ($:).
Working directory (".") was removed from load path (global variable $: or $-I or $LOAD_PATH) in Ruby 1.9 because it was considered a security risk:
Your working directory may be any folder, and your script will require files from this folder if these files have appropriate names. For example you have 2 files in Project1 folder main.rb and init.rb:
==Project1/main1.rb:
$: << "."
require 'init'
==Project1/init.rb:
puts 'init 1'
And you have alike project:
==Project2/main2.rb:
$: << "."
require 'init'
==Project2/init.rb:
puts 'init 2'
If you run Project1 from Project2 folder, then main1.rb will require Project2/init.rb, not Project1/init.rb:
~/Projects/Project2$ ruby ../Project1/main1.rb
init 2 # may be unexpected an dangerous
~/Projects/Project2$ ruby main2.rb
init 2
You can change your working directory in your code, e.g. using Dir.chdir:
ruby-1.9.2-p290 :002 > puts File.expand_path('.')
=> /home/alex/Projects
ruby-1.9.2-p290 :003 > Dir.chdir('..')
ruby-1.9.2-p290 :004 > puts File.expand_path('.')
=> /home/alex
I recommend you to use the following techniques instead of $: << '.':
require_relative (Ruby 1.9 only)
Add folder of the file to the working directory (common approach because it is compatible with Ruby 1.8): $: << File.expand_path('..', __FILE__) etc.. __FILE__ is a reference to the current file name. File.expand_path converts a pathname to an absolute pathname.

Strange ruby behaviour with __FILE__ constant?

Hi I have been testing some very basic things in ruby and discover the following.
If i put in a file called xxxx.rb in this path "C:\Documents and Settings\Desktop\xxxx.rb"
puts __FILE__
and invoke this ruby file in a command line WITHOUT preceding ruby the output is the following
C:/Documents and Settings/Desktop/xxxx.rb
but if i invoke the xxxx.rb file with ruby (ruby xxxx.rb) in the command like the output is the following:
xxxx.rb
Why is that difference?? Thanks
PD: I'M ON WINDOWS XP SP3
RUBY VERSION: 1.8.6
What you want is to expand the path properly:
# Affected by the current working directory, etc.
puts __FILE__
# Always an absolute path
puts File.expand_path(__FILE__, Dir.getwd)
This takes your current working directory into account.
I'm guessing that when you just double click on the file, the absolute path gets passed. You should achieve the same effect by calling it like:
ruby C:/Documents and Settings/Desktop/xxxx.rb

Resources