$:.unshift File.expand_path(path, __FILE__)
I saw this line of code somewhere and i felt kind of confuse about it and intimidate. That's why, i'll try to explain what i've found so far (if there is any errors, feel free to point them out).
$:
?
What is this This alien thing $:
is a shortcut referencing the $LOAD_PATH
. What is the $LOAD_PATH
?
The $LOAD_PATH
is a global variable as you can tell from $
at the beginning. A global variable is a variable which
is accessible from everywhere in a given context. For example take a look at the function below :
$global = 1
def sum(a, b)
$global += a + b #Same as $global = $global + a + b
end
p increment(2,3) # 6
Here, the context is the file you're in. The variable $global
is callable from anywhere in the code because of the $
.
Reciprocally, a global variable like $LOAD_PATH
is accessible from anywhere in your command line environnement and
that can be helpful to shorten some actions that can be laborious is you're working on a big project.This why we're using the $LOAD_PATH
here.
The $LOAD_PATH
variable contains an array of path which mostly point to lib/
sub-directories :
>> $LOAD_PATH
=> ["/home/Mansa/.rbenv/rbenv.d/exec/gem-rehash",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/did_you_mean-1.3.0/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/coderay-1.1.2/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/method_source-0.9.2/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/pry-0.12.2/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/yard-0.9.19/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/pry-doc-1.0.0/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/pry-rails-0.3.9/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/site_ruby/2.6.0",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/site_ruby/2.6.0/x86_64-linux",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/site_ruby",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/vendor_ruby/2.6.0",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/vendor_ruby/2.6.0/x86_64-linux",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/vendor_ruby",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/2.6.0",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-linux"]
>> $:
=> ["/home/Mansa/.rbenv/rbenv.d/exec/gem-rehash",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/did_you_mean-1.3.0/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/coderay-1.1.2/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/method_source-0.9.2/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/pry-0.12.2/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/yard-0.9.19/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/pry-doc-1.0.0/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/pry-rails-0.3.9/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/site_ruby/2.6.0",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/site_ruby/2.6.0/x86_64-linux",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/site_ruby",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/vendor_ruby/2.6.0",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/vendor_ruby/2.6.0/x86_64-linux",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/vendor_ruby",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/2.6.0",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-linux"]
>> $: == $LOAD_PATH
=> true
We can see that the $:
notation is obviously a shortened version of $LOAD_PATH
$:.unshift
?
What is Now we see that things are starting to fall into place but still, there is quite a bit cover to get the full picture.
We saw earlier that the $LOAD_PATH
was an array containing several path. It means that $:.unshift
is calling
to a Array#unshift
(which is the Ruby notation refering to an instance method from a Ruby classes) method on the $:
array :
# $:.unshift ... >> $LOAD_PATH.unshift >> Array#unshift
The Array#unshift
method is adding a elements pass in argument to the beginning of an array :
>> [1,2,3].unshift(0)
=> [0,1,2,3]
Read the Official Ruby Doc for more info.
File.expand_path(path, __FILE__)
?
What is The File#expand_path
method is used to convert a relative path to an absolute path. Relative path are relative, which
means that there defined in the context they we're in.
$ pwd #show the current directory
~/code/Rails
$ ls #show all the public access file in a directory
my_app my_app2
$ cd myapp/ #change the directory
With the cd
command we've used the relative path to the myapp/
directory instead of absolute path which is
~/code/Rails/my_app
What the File#expand_path
method allow us to reconstruct the path from the root directory. The first argument specify
the relative path to a file or directory. The second argument set the starting point from where we want to start reconstructing
the path.
>> __FILE__
=> my_app/Gemfile
>> File.expand_path("../my_app2/Gemfile", __FILE__)
=> ~/code/Rails/my_app2/Gemfile
Here the second argument is set to __FILE__
which is a variable returning the current file or directory we're in. You can
replace __FILE__
by any file or directory you want.
Not so complicated huh ? If you want a sharp explaination about how the File#expand_path
method work, i suggest you take
a look at the first awswer of this Stackoverflow post
$:.unshift File.expand_path(path, __FILE__)
?
What is Now with all pieces together we can start reconstructing the puzzle.
As we know now, $:.unshift
represents an array method call. We can deduce from that File.expand_path(path, __FILE__)
is the argument we're passin in(Note: In Ruby, parenthesis are optional if there is only one argument).
It means that through the $:.unshift
method call we've plan to add File.expand_path(path, __FILE__)
to the
$:
array.
By doing so, we're adding the path generate by File.expand_path(path, __FILE__)
in the $LOAD_PATH
array which allows
our command line environnment to have access to the specified path from anywhere. And why it is that helpful ? Because it allow
us to call require "directory"
instead of require "../../../path/to/directory
to require a specified directory in
our Ruby project.
Viewing like this it may not be seem that helpful, but in real life substantial projects, this can time/energy saver. Because
things like this require "../../../../../directory
aren't particulary fun to do in my opinion :). Moreover, when you have a tons of files/directories to require,, it can be tremendously laborious.
Conclusion
That's all :)
Let's review what we've seen so far :
a - We saw that the $:
notation was a shorcut for $LOAD_PATH
and that $LOAD_PATH
is global variable containing
an array of path.
b - We saw that $:.unshift
was an Array
method which serve to add elements to the beginning of an array.
c - We saw that File.expand_path(path, __FILE__)
serve to reconstruct an absolute path from a relative path.
d - We saw that $:.unshift File.expand_path(path, __FILE__)
serve to add an absolute path generate by with
File.expand_path(path, __FILE__)
to the beginning of the $:
array, which allow us to require file and directories
without specifing the absolute path for it.
I hope that you get a clearer understanding now or a least that you're not as confused as the first time you saw this code :)
Peace ☥