File.Expand_Path("../../Gemfile", _File_) How Does This Work? Where Is the File

File.expand_path( ../../Gemfile , __FILE__) How does this work? Where is the file?

File.expand_path('../../Gemfile', __FILE__)

is a somewhat ugly Ruby idiom for getting the absolute path to a file when you know the path relative to the current file. Another way of writing it is this:

File.expand_path('../Gemfile', File.dirname(__FILE__))

both are ugly, but the first variant is shorter. The first variant is, however, also very non-intuitive until you get the hang of it. Why the extra ..? (but the second variant may give a clue as to why it is needed).

This is how it works: File.expand_path returns the absolute path of the first argument, relative to the second argument (which defaults to the current working directory). __FILE__ is the path to the file the code is in. Since the second argument in this case is a path to a file, and File.expand_path assumes a directory, we have to stick an extra .. in the path to get the path right. This is how it works:

File.expand_path is basically implemented like this (in the following code path will have the value of ../../Gemfile and relative_to will have the value of /path/to/file.rb):

def File.expand_path(path, relative_to=Dir.getwd)
# first the two arguments are concatenated, with the second argument first
absolute_path = File.join(relative_to, path)
while absolute_path.include?('..')
# remove the first occurrence of /<something>/..
absolute_path = absolute_path.sub(%r{/[^/]+/\.\.}, '')
end
absolute_path
end

(there's a little bit more to it, it expands ~ to the home directory and so on -- there are probably also some other issues with the code above)

Stepping through a call to the code above absolute_path will first get the value /path/to/file.rb/../../Gemfile, then for each round in the loop the first .. will be removed, along with the path component before it. First /file.rb/.. is removed, then on the next round /to/.. is removed, and we get /path/Gemfile.

To make a long story short, File.expand_path('../../Gemfile', __FILE__) is a trick to get the absolute path of a file when you know the path relative to the current file. The extra .. in the relative path is to eliminate the name of the file in __FILE__.

In Ruby 2.0 there is a Kernel function called __dir__ that is implemented as File.dirname(File.realpath(__FILE__)).

How does File.expand_path work?

Theory

I think you missed a .. while reading the answer you link to.

No File.dirname is ever done implicitely by expand_path.

File.expand_path('../../Gemfile', __FILE__)
# ^^ Note the difference between here and
# vv there
File.expand_path('../Gemfile', File.dirname(__FILE__))

What confused me at first was that the second parameter is always considered to be a directory by File.expand_path, even if it doesn't exist, even if it looks like a file or even if it is an existing file.

File.expand_path goes to the first parameter from the directory specified by the second parameter (Dir.pwd if not present).

Examples

[3]

File.expand_path('..', "cats")

It is executed in the current directory, which is "/Users/max/Dropbox/work/src/github.com/mbigras/foobie".

Is cats an existing file, an existing directory or a non-existent directory?

It doesn't matter to File.expand_path : "cats" is considered to be an existing directory, and File.expand_path starts inside it.

This command is equivalent to launching :

File.expand_path('..')

inside the "/Users/max/Dropbox/work/src/github.com/mbigras/foobie/cats" directory.

So expand_path goes back one directory, and lands back to :

"/Users/max/Dropbox/work/src/github.com/mbigras/foobie"

[4]

Same thing. It is equivalent to File.expand_path('..') from the (probably) non-existing :

"/Users/max/Dropbox/work/src/github.com/mbigras/foobie/(pry)"

So it is :

"/Users/max/Dropbox/work/src/github.com/mbigras/foobie"

[5]

Going from [4], it just goes to the subfolder lib.

[8]

Starting from "/Users/max/Dropbox/work/src/github.com/mbigras/foobie/(pry)"
, it just goes to the subfolder lib.

Once again, File.expand_path never checks if the corresponding folders and subfolders exist.

What does __FILE__ mean in Ruby?

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

What Does require File.expand_path('../../config/environment', __FILE__) do Exactly?

__FILE__ is the relative path to the file from current directory. File.expand_path will get you absolute path of file, so above in your question require the environment.rb file.
$: contains the array of required path, so $:.push append the your given path into list of required path, so that you can require that file in your app. Rails push various file while booting process.

File paths for parsing in Ruby using Rake

__dir_ method returns directory of the current file you're in, so this should work for you:

File.read(__dir__ + "/../metadata.json")

why File.expand_path(__FILE__)?

__dir__ or (__FILE__) is not necessarily the same as ".". The former is the location of the file. The latter is the location from where the main command was called (or wherever it was changed to by commands like Dir.chdir).

How to read files (.yml) from a Gem

Solution 1

You can store the root path in a constant from your main gem file and retrieve it in other locations of your code. You must ensure that the gem got initialized before the code in your app runs otherwise you'll have an errors because the constant won't be defined.

# lib/my_gem.rb
GEM_ROOT = File.expand_path("../..", __FILE__)

# app/.../some_class.rb
IO.read("#{GEM_ROOT}/config/test.yml")

Solution 2

The most advisable, you can get the gem path programmatically from Bundler, then use that root path to retrieve the full path of your yml file.

Have a look at this answer that you can easily adapt to your case



Related Topics



Leave a reply



Submit